60 Days of Flutter :Building a Messenger : Day 33–35 : Paginating data from Firestore using Firebase Queries
In the last post, we built the ChatBloc. At the end of the post I listed out few issues with the ChatBloc that we built.
We’re loading all the messages at once, We’ll also need to implement pagination for the messages.
On swiping between the pages, the state of the page does not persist, they’re getting rebuilt everytime. Also the messages get jumbled up between the pages. This also needs to be fixed.
The TextField overflows the AppBar.
On clicking the contact, it takes a little bit time before the data is returned, we’ll need to implement a Local Storage to cache this data locally as well.
The last item in the list will make for a separate post which I’ll be doing in the coming days. We’ll be taking up all the other issues in the list, today.
Oh, and before we start, for no reason at all here are some sneaks into DevFest19, Bangalore which I happened to attend today!
Alright, Let’s get started!
Implementing Pagination on Chat Screen
Our pagination scheme is going to be a bit different than usual because we also need to keep track of new incoming messages. Let’s first try to understand it with a diagram.
To start with, our chat screen now has two different events.
- FetchMessagesEvent : Triggered when the chat is first opened. It retrieves the latest 20 messages and returns a
Stream<List<Message>>
. This stream will emit any new messages received. - FetchPreviousMessagesEvent : Triggered when user reaches the top of the page. It returns a
List<Message>
of 20 messages previous 20 messages. (and the next 20 after that, on next scroll to top).
The Implementation
We have the usual Event-Bloc-State trio to start with. Let’s take a look at them first to see which one is doing what. The two Events
we talked about above,
The associated Bloc
.
And the resultant States
are.
Firebase Query
Cloud Firestore provides powerful query functionality for specifying which documents you want to retrieve from a collection or collection group. This basically allows you to apply certain constraints, ordering or filters while retrieving the data. Let’s take a look at how we’re doing it.
We had the getMessages()
previously as well, it does the same thing as before i.e. gives a stream of the latest 20 messages.
The new thing here is the getPreviousMessages()
method. It takes the documentID
of the top most message in the chat screen, and returns the next 20 messages after it. So every time user reaches the top, the next 20 messages are loaded. To achieve this, it uses the different query operations available with Firebase to achieve this.
We also want to make sure that everytime the user reaches the top of the ChatList , FetchPreviousMessageEvent
is trigged. This is how our ChatListWidget
looks after these modifications.
PageView Persistance
Next up, we wanted the PageView
data to persist between Page switches and also fix the BottomOverFlow
error which showed everytime the keyboard came up.
We’ll be using AutomaticKeepAliveClientMixin
to keep our PageView
pages alive. Modify your ConversationPage
to add this mixin.
The BottomOverFlow
error was because we used the Expand
Widget and it was getting pushed everytime the keyboard showed up, in turn shrinking the AppBar
. Replaced it with a Stack
and everything works as we want it to.
Let’s see it in action.
Neat!
In the next article we’ll take a look at caching data using a Local Storage technique.
Hit me up in the comments below or Twitter or Linkedin or Instagram if you have any queries or suggestions or just for a casual tech talk maybe? See you guys in the next one!
Code Changes
#23 Pagination and other ConversationPage Fixes
How Can You Contribute?
- Open issues with suggestion of better approaches or ideas for the app.
- Connect with me on Twitter or Linkedin or Instagram.
- Star the Github repository.
- Share the series on Twitter.
- Follow me on Github.
Posts In This Series
- 60 Days Of Flutter : Building a Messenger from Scratch
- 60 Days of Flutter : Day 1 : Creating the App
- 60 Days of Flutter : Day 2 : Setting Up A CI With Flutter
- 60 Days of Flutter : Day 3–4 : Building a Chat Screen in Flutter
- 60 Days of Flutter : Day 4–5 : Widget Testing With Flutter
- 60 Days of Flutter : Day 6–7 : Implementing a Slideable Widget Using Bottomsheet in Flutter
- 60 Days of Flutter : Day 8 : Changing The Launcher Icon and Implementing GestureDetector
- 60 Days of Flutter : Day 9–10–11 : Creating Awesome Register Screen in Flutter
- 60 Days of Flutter : Day 12–14 : Understanding BLoC Pattern in Flutter
- 60 Days of Flutter : Day 15–17 : Implementing Registration Screen using ‘flutter_bloc’
- 60 Days of Flutter : Day 18–19 : Unit Testing in Flutter using ‘ mockito’
- 60 Days of Flutter : Day 20–21 : Unit Testing a Bloc in Flutter
- 60 Days of Flutter : Day 22–23 : Building a Modern Contacts Page in Flutter
- 60 Days of Flutter : Day 24–26 : Building a Animated Progress Fab and the Contacts Bloc in Flutter
- 60 Days of Flutter : Day 27–29 : Sending and Retrieving Messages from Firebase using BLOC
- 60 Days of Flutter : Day 30–32 : Firebase Chat UI using Stream and Bloc
- 60 Days of Flutter : Day 33–35 : Paginating data from Firestore using Firebase Queries
- 60 Days of Flutter : Day 36–38 : Seamlessly Upload Files to Firebase Storage
- 60 Days of Flutter : Day 39–41 : One UI Inspired Attachments Showcase Page
- 60 Days of Flutter : Day 42–45 : Creating the Home Page & Quick Peek BottomSheet for Messages
- 60 Days of Flutter : Day 45–47 : Adding Dark Mode to a Flutter App
- 60 Days of Flutter : Day 48–50 : Creating the Settings Page using Bloc
- 60 Days of Flutter : Day 51–54 : Unit Testing Firebase Providers with Mockito
- 60 Days of Flutter : Day 55–56 : Deploying Firestore Security Rules using Firebase CLI
- 60 Days of Flutter : Day 60 : Wrapping It Up
Show Your Support
Press the clap button below if you liked reading this post. The more you clap the more it motivates me to write better!