cover-img

Creating a News App in Flutter using ChatGPT

In this blog, I am going to show you how I created a new app in Flutter with the help of ChatGPT in under 2 hours

24 May, 2023

9

9

0

Introduction

Hey everyone, I am Hasnain Makada and I am currently a Founding Creator, a CCO as well as a Rotational Tech Writer at Showwcase. I also maintain an open-source project named "Open Source with Hasnain" where I provide resources for beginners to seasoned developers. I am also currently an MLSA - Beta where I explore and learn new things from Microsoft and educate my community as well.

Today, In this blog, I am going to show you how I created a news app in Flutter in under 2 hours with the help of chatGPT

I am going to show you how I implemented the Ui, how I implemented the logic and how I managed the state using riverpod 2.0.

So without wasting any furthermore time, Let's get started πŸ”₯

Gathering the requirements

When developing any application first, we first gather the requirements, Like which dependencies we're going to use, which state management libraries we're going to use etc...

So the initial gathering criteria was easy for me, these are the dependencies we're going to use inside our app.

  • flutter_dotenv - To load environment variables, such as API key.
  • flutter_riverpod - For managing state across the app.
  • http - Handling API calls from the news API which we are going to use.
  • url_launcher - For launching URLs in an external browser

Now that our dependencies are gathered, create a new Flutter app by running the below command and all of these dependencies inside the pubspec.yamlfile.

flutter create innews

I am currently using the latest Flutter version inside which there are a lot of Ui changes are there which you can check out here πŸ‘‡

https://docs.flutter.dev/release/whats-new

Designing the UI

The design is pretty much simple, in the home screen a box will and it will include the image, title and description of the news inside it, once the user clicks on it, it will redirect the user to the main article screen. If the user wants to read the full news, it will also provide a link to the full article.

Here is the rough sketch of the Ui,

image.png

Initially, when I designed the UI, I was confused that how should I start it. So I had gone to chatGPT and I prompted it the design I wanted

image.png

ChatGPT helped me generate the newsItem layout which I wanted, Although I modified the layout a little bit, it was great and after modifying this was the end result.

Here is the code πŸ‘‡ and its output.

 return Card(
      elevation: 2,
      margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 30),
      child: InkWell(
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => ArticleDetailScreen(article: article),
            ),
          );
        },
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              height: 200,
              width: double.infinity,
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: NetworkImage(article.imageUrl),
                  fit: BoxFit.cover,
                ),
              ),
            ),
            const SizedBox(height: 8),
            Text(
              article.title,
              style: const TextStyle(fontSize: 16),
            ),
            const SizedBox(height: 8),
            Text(
              article.description,
              style: const TextStyle(
                fontSize: 14,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 8),
            Text(
              article.sourceName,
              style: const TextStyle(fontSize: 12, color: Colors.grey),
            ),
          ],
        ),
      ),
    );

image.png

Now that our NewsItem widget was successfully designed, It was time to design the Article detail screen, if a user clicks on any area of the NewsItem widget, it should redirect him/her to the article screen.

So I again prompted ChatGPT for designing the Article detail screen,

image.png

ChatGPT generated for me the article, but It needed some modifications so I modified it a little and the end result was good.

Here's the code πŸ‘‡

class ArticleDetailScreen extends StatelessWidget {
  final NewsArticle article;

  ArticleDetailScreen({required this.article});

  Future<void> _launchURL(String url) async {
    if (!await launchUrl(
      Uri.parse(url),
      mode: LaunchMode.externalApplication,
    )) {
      throw Exception('Could not launch $url');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Article Details'),
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Image.network(article.imageUrl),
              Text(
                article.title,
                style: const TextStyle(
                  fontSize: 24,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 16),
              ExpandableText(
                article.content
                    .toString()
                    .replaceAll(RegExp(r'\[\+\d+ chars\]$'), ''),
                style: const TextStyle(fontSize: 16),
                expandText: 'Show more',
                collapseText: 'Show less',
                maxLines: 3,
                expanded: false,
              ),
              const SizedBox(height: 16),
              GestureDetector(
                onTap: () {
                  _launchURL(article.url);
                },
                child: const Text(
                  'Read More',
                  style: TextStyle(
                    color: Colors.blue,
                    decoration: TextDecoration.underline,
                  ),
                ),
              ),
              const SizedBox(height: 16),
              Text(
                'Source: ${article.sourceName}',
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 16),
              Text(
                'Published At: ${article.publishedAt}',
                style: const TextStyle(fontSize: 14),
              ),
              const SizedBox(height: 16),
              Text(
                'Author: ${article.author}',
                style: const TextStyle(fontSize: 14),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

And here is the output πŸ‘‡

image.png

So far now our app ui is almost completed, Now it's time to work on the logic.

Creating the logic

For creating the logic of the app, I used the NewsAPI site to get the API, It's really simple to get started with it.

Fetching the News API

Now I wanted to use Riverpod for managing the state across the app because I always try to manage the state of my app dynamically and don't want to go with the traditional setState the method as it becomes difficult over a period of time.

As our riverpod dependency is already installed, create a new directory inside your /lib folder as our models and logic will reside over there.

After creating the directory, create a new file named NewsApi.dart

And inside the file, paste this code πŸ‘‡

import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;

class NewsApiClient {
  final http.Client client;
  NewsApiClient(this.client);

  Future<String> fetchNews() async {
    final response = await client.get(
      Uri.parse(
          'https://newsapi.org/v2/everything?q=apple&from=2023-05-19&to=2023-05-19&sortBy=popularity&apiKey=${dotenv.env['newapikey']}'),
    );

    if (response.statusCode == 200) {
      return response.body;
    } else {
      throw Exception('Failed to fetch the news');
    }
  }
}

final newsApiClientProvider = Provider<NewsApiClient>((ref) {
  return NewsApiClient(http.Client());
});

final newsProvider = FutureProvider<String>(
  (ref) async {
    final newsApiClient = ref.read(newsApiClientProvider);
    return await newsApiClient.fetchNews();
  },
);

We first created a NewsApiClient class which will take the help of thehttp.Client instance and will get the data from our API.

After that, we created a Future<String> fetchNews method which will asynchronously wait for our API to get fetched successfully, and if our API was successfully got, then it will return the body of the API else it will throw an error.

Then we created a newsApiClientProviderwhich will use the Provider object to expose the state of httpto the NewsApiClient class

In the end, we created a newsProvider which will read the data from the NewsApiClient and it will return the response in String format. Because as we now have access to the client provider then we can access the methods of the NewsApiClient class.

Creating the Article Model

When I first checked the response of my API, It was like this πŸ‘‡

{
"status": "ok",
"totalResults": 1972,
"articles": [
{
"source": {
"id": "engadget",
"name": "Engadget"
},
"author": "Mat Smith",
"title": "The Morning After: Meta could launch a Twitter competitor next month",
"description": "Meta has long been rumored to be building a platform to rival Twitter. After months of speculation, there are finally some details on how it might turn out, according to digital media marketing expert Lia Haberman, who has heard about the app through content …",
"url": "https://www.engadget.com/the-morning-after-meta-could-launch-a-twitter-competitor-next-month-111543954.html",
"urlToImage": "https://s.yimg.com/uu/api/res/1.2/nbbyqy5Ca.eCKGzLfcl5CA--~B/Zmk9ZmlsbDtoPTYzMDtweW9mZj0wO3c9MTIwMDthcHBpZD15dGFjaHlvbg--/https://media-mbst-pub-ue1.s3.amazonaws.com/creatr-uploaded-images/2022-11/6e32a9f0-608e-11ed-85af-6f6f0330bc92.cf.jpg",
"publishedAt": "2023-05-22T11:15:43Z",
"content": "Meta has long been rumored to be building a platform to rival Twitter. After months of speculation, there are finally some details on how it might turn out, according to digital media marketing exper… [+3401 chars]"
},

So I provided my API to chatGPT and asked him to create the model for me and after a few minutes and modifying the code which it provided me, I designed the model.

import 'dart:convert';

class NewsArticle {
  final String sourceName;
  final String author;
  final String title;
  final String description;
  final String url;
  final String imageUrl;
  final String publishedAt;
  final String content;

  NewsArticle({
    required this.sourceName,
    required this.author,
    required this.title,
    required this.description,
    required this.url,
    required this.imageUrl,
    required this.publishedAt,
    required this.content,
  });

  factory NewsArticle.fromJson(Map<String, dynamic> json) {
    return NewsArticle(
      sourceName: json['source']['name'] as String? ?? '',
      author: json['author'] as String? ?? '',
      title: json['title'] as String? ?? '',
      description: json['description'] as String? ?? '',
      url: json['url'] as String? ?? '',
      imageUrl: json['urlToImage'] as String? ?? '',
      publishedAt: json['publishedAt'] as String? ?? '',
      content: json['content'] as String? ?? '',
    );
  }
}

List<NewsArticle> parseNewsData(String newsData) {
  final jsonData = json.decode(newsData);
  final List<NewsArticle> newsArticles = [];

  if (jsonData['articles'] != null) {
    for (final article in jsonData['articles']) {
      final newsArticle = NewsArticle.fromJson(article);
      newsArticles.add(newsArticle);
    }
  }

  return newsArticles;
}

Integrating the logic with the final UI

Now when I asked chatGPT how can I manage the state and the UI dynamically, it answered me that I should use the Consumer widget inside my home screen UI and it will help me update the Ui without reloading the whole screen again and again.

It also provided me with a snippet to get an idea of how to implement it.

Consumer(builder: (context, watch, child) {
final newsAsyncValue = watch(newsProvider);
return newsAsyncValue.when(
loading: () => CircularProgressIndicator(),
error: (error, stackTrace) => Text('Error: $error'),
data: (newsList) => ListView.builder(
itemCount: newsList.length,
itemBuilder: (context, index) {
final news = newsList[index];
// Build your widget using the news data
return ListTile(
title: Text(news.title),
subtitle: Text(news.description),
// ...
);
},
),
);
},
),

After modifying the code, The final output I got was this πŸ‘‡

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:news_app/NewsApi/NewsApi.dart';
import 'package:news_app/NewsApi/NewsArticle.dart';

import 'newsItem.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text(
          'InNews',
          style: TextStyle(
            color: Colors.purple,
            fontStyle: FontStyle.italic,
            fontSize: 25,
          ),
        ),
      ),
      body: Consumer(
        builder: (context, ref, child) {
          final newsAsyncValue = ref.watch(newsProvider);

          return newsAsyncValue.when(
            data: (data) {
              final newsArticles = parseNewsData(data);

              return ListView.builder(
                itemCount: newsArticles.length,
                itemBuilder: (context, index) {
                  return NewsItemWidget(article: newsArticles[index]);
                },
              );
            },
            error: (error, stackTrace) {
              return Center(
                child: Text("Error $error"),
              );
            },
            loading: () {
              return const Center(
                child: CircularProgressIndicator(),
              );
            },
          );
        },
      ),
    );
  }
}
  1. The newsAsyncValue represents the current value of newsProvider. It can be in three states: loading, error, or data.
  2. When the newsAsyncValue is in the data state, the code retrieves the news articles data using parseNewsData function, which converts the data into a list of NewsArticle objects.
  3. A ListView.builder widget is used to display the list of news articles. It takes the number of articles as the itemCount and generates each item by calling the NewsItemWidget constructor, passing the corresponding NewsArticle object.
  4. When the newsAsyncValue is in the error state, an error message is displayed at the centre of the screen.
  5. When the newsAsyncValue is in the loading state, a CircularProgressIndicator is displayed at the centre of the screen, indicating that the data is being loaded.

Overall, this code sets up the HomeScreen widget to display a list of news articles. It uses the Consumer widget to listen to changes in the state of the newsProvider and updates the UI accordingly based on the current state.

The Final Output

Here's the final output of the app πŸ‘‡

InNewsDemo.mp4

You can also check out the project here πŸ‘‡

https://github.com/hasnainmakada-99/InNews

Conclusion

In this blog, We explored how we can build our flutter apps efficiently with the help of Ai tools such as ChatGPT, We explored a lot of things and as a developer, it also improves our productivity, So if you have any doubts related to DevOps or Flutter, feel free to reach out on my Twitter and Showwcase handle

Till then, Happy Coding πŸ˜€


mobile

news

flutter

developer

chatgtpt

newsapp

aplication

9

9

0

mobile

news

flutter

developer

chatgtpt

newsapp

aplication

Hasnain Makada
Elite @Showwcase | Prev: CCO @ShowwcaseHQ | Building out OSWH πŸ‘¨β€πŸ’» | MLSA - Ξ² | DevOps and Flutter πŸ’™ | Blogger at Hashnode and Showwcase πŸ“‘

More Articles

Showwcase is a professional tech network with over 0 users from over 150 countries. We assist tech professionals in showcasing their unique skills through dedicated profiles and connect them with top global companies for career opportunities.

Β© Copyright 2025. Showcase Creators Inc. All rights reserved.