Mobile App Development with Flutter (Part 2)

Mobile App Development with Flutter (Part 2)

By Ümit Kara • September 25, 2022 • 7 mins read

Second Step: Plan and Practice

After learning how to play the game, in this case learning the Dart programming language and Flutter SDK, we need to decide what we will do with them. As I mentioned in the previous post, I want to create a Twitter clone with core Twitter functionality. Now let's think about it and decide how we are going to build it.

The Plan

In the previous post, I mentioned a few words about Firebase. Firebase is equipped to provide everything that we are most likely to need in this project. With that in mind, let's start planning.

Authentication

As a first step, we need to provide authentication, sign-in, and sign-up screens for our users. We provide this feature through Firebase Authentication. For the sign-in page, we need fields for users to enter their credentials, e-mail address, and password. Also a button to sign-in and a button to redirect users to the sign-up page if they don't have an account.

Sign-in page

The sign-up page is expected to be more complicated than the sign-in. At sign-up I don't want to just register the user, but I also want to get information about the user, like the user's bio. For that we are preparing to build a 2-step sign up page. The first step is for credentials and 2 step is for profile information. For this reason, we are going to use the Stepper widget here. The stepper widget allows me to progress step by step. When the user is finished, we will register the user via Firebase Authentication and redirect to our main page, which is the timeline.

Sign-up Step 1

When we look at which information we ask from users, those are also the core information that Twitter wants from users. A brief biography (maximum 240 characters), a website link, location and full name. We will store these information in the Firebase Firestore database, in the users document. For every user that signed-up, Firebase Authentication provides that user a unique id. We will use this id as document name, and store data. In this way, we could create relationships easily.

Sign-up Step 2

Timeline

The timeline page is meant to be our homepage and host a lot of content that we build. We will fetch and show tweets from the user's followings. For this we will use the Listview widget. Its name suggests that the listview widget lists all the tweets that we fetch from Firestore. It has a builder method, that loads only the visible list items for performance.

Timeline

For realtime data fetching, will use StreamBuilder widget. This widget listens to incoming streams, in this context the provided websocket from Firestore, then rebuilds the children widgets.

We will retrieve a limited number of tweets when fetching tweets from Firestore with StreamBuilder widget to increase app performance and reduce redundant network traffic. I will load 20 tweets at a time, and load new tweets when the user scrolls to the bottom. Additionally, we will add RefreshIndicator widget to refresh the timeline by pulling down.

For displaying a tweet in the Listview, we also need to build our custom tweet widget. This widget shows the body of the tweet, the user who posted it and stats; like, retweet and quote count.

Other than these, we will build two App Drawers, one for navigation and one for showing search field and trending hashtags.

Finally, we will add a floating action button that redirects users to a tweet composition page.

For the database part of timeline, we will store all tweets in the tweets document in the Firestore. Each tweet document has several fields which are: body, createdAt, likes, originalTweet, replies, retweets, type, user and userId.

The body field will hold the tweet text that the user entered. The created at field stores the time the tweet was posted. Users who liked the tweet are also stored in the "likes" field. Original tweet field is here for replies and retweets. When a user retweets a tweet we will define the tweet type to retweet and display the original tweet in the body of the retweet. We're planning to use the user ID for filtering the tweets by followings. The user field is here to fetch the user's details. Right now, I will not accept any media from users, but Firebase Storage will allow us to do so.

Profile

Another significant screen that we will build is the profile page. The timeline and this page share the same app bar design. In addition to that, we will show the user's cover art and profile picture at the top. For now, we will use some placeholders for both. Also the banner will display the user's biography, tweet, following and follower counts. In addition, we want to display a follow/unfollow button for each user profile other than the user's own profile.

Profile

Moreover we will use the BottomNavigationBar widget to show the user's tweets and replies on different pages. Just as we provide a RefreshIndicator widget to refresh the timeline, we will also provide a RefreshIndicator widget to refresh the profile page. With this feature, we can update tweet stats and new tweets.

Explore

The Explore page will show the top 10 trending topics and their statistics. The Listview widget is also used for this purpose. When we look at how we will get hashtags from tweet, we will add mentions and hashtags fields to each tweet document. Then we will define a scheduled task in Firebase to look up tweets that were posted last hour. This task will generate list of top 10 hashtags that were use.

The trending topics will be listed like tweets in the timeline when the user chooses to view them. We will fetch 20 tweets at a time and display them in ascending order of their creation time.

Messages

The messages screen will host a basic real-time messaging application. We will host chats in the chats document in the Firestore and fetch chat and it's messages from there. For ease of implementation we won't let the user delete messages. Again for ease of implementation we only accept text messages.

Other Screens

We also have notifications and search results, in addition to all of these. With Firestore we could store all notifications, but I prefer to store the last 10 for ease of implementation. Firestore does not support full-text searching, so we have to rely on a third-party solution for our searches. In the official documentation, a few products are suggested for search. In light of this, I chose to stick with Algolia because it has Dart library and Firebase extension and it's free.

Practice

With a broad plan in our hands, and an idea of how we will accomplish our goal, we need to solve an issue; how are we planning to communicate between our screens, in other words how are we planning to manage state? When it comes to state management, Flutter and Dart have lots of packages. The most known and used package is called Provider. In the first part, I mentioned a third type of widget called an inherited widget. Provider package wraps inherited widgets and provide us a useful API. So you might wonder, what is an inherited widget? An inherited widget does not have a display. Whenever you place an inherited widget into the widget tree, every child widget and every child of that child can reach directly to it. This is because there is no need for an intermediary widget. The provider package uses this feature to manipulate data. Any child can access this data and modify it easily. If you use a provider, you need to use the ChangeNotifier mixin to have the notifyListeners function. This function does the same job that setState function does. It notifies Flutter that some data in the application state has changed, so it needs to rebuild the widgets.

While there are other options like Redux, BloC, and GetIt, I decided to stick with the RiverPod package because I find it easier to use. Also it uses similar API like provider package but it has far more features than that. Other than a basic provider, it has StateProvider for changing states, FutureProvider for asynchronous data and StreamProvider for realtime data.

So how are we aiming to use state management in our application? In order to avoid re-fetching tweets, we have to store them in the cache when we retrieve them. Retrieving the data repeatedly wastes our time and delays the user. Apart from tweets, we need to store the user's information. This is because most of the time we need the user's data, for example when fetching tweets we need the user's followings. We don't want to fetch this information repeatedly. It will save the user a great deal of bandwidth and time in real-world applications.

Environment

I discuss a lot about Dart and Flutter, but do not mention anything about development environments. As a last thing, let's talk about it. For application development with Flutter, you need to have the SDK. The SDK can be downloaded from the official website. It supports most major operating systems. It also includes the Dart SDK, so you don't need to install both. After SDK installation, go to the command line or console and type flutter doctor. This command shows what dependencies are missing and what you should do. Other than that you must have Android SDKs, so I strongly suggest you to install Android Studio for that. Because you can select which SDKs to download and it has a built-in emulator with it. For programming you don't have to stick with Android Studio though, you can work with Visual Studio Code. All you need to install is the Flutter extension and you are ready to start.