Hey There! In last post we took a look at how Bloc pattern works. Today we’ll implement it on the Registration Page of our app. We’ll be using flutter_bloc which makes implementing Bloc pattern easier.

If you have no idea what Bloc is, I strongly recommend you read the previous post in this series before moving ahead. Let’s get started.

Visualization

Before we start let’s visualize the events and the states we’re going to encounter during the whole process. Start by taking a look at both the pages on our registration screen.

Events

The Events can be seen as the user’s journey throughout this page. Let’s list them down in sequence.

States

Every time a Event is dispatched, the Bloc takes it and converts it into a State . In simple words, for every Event executed by the user, the UI responds by a predictable State . Check the state diagram below to understand the flow.

This should give you a rough idea of what the flow will be. And even if you’re confused you need not worry. It’ll get clearer as we move ahead.

Creating the Bloc Directory Structure

Add these packages under dependencies in your pubspec.yaml.

firebase_auth: ^0.14.0+4 #to auth with firebase

google_sign_in: ^4.0.7 #to auth with google account

flutter_bloc: ^0.21.0 #helps in implementing blocs

equatable: ^0.5.0 #helps in comparing class using their values

cloud_firestore: ^0.12.9+1 #Firebase Database

image_picker: ^0.6.1+4 #image picker used for picking images from gallery

firebase_storage: ^3.0.6 #storage for storing image files

We’ll first start by creating the directory structure of our Bloc . I recommend using this plugin with Android Studio for quickly generating Bloc classes. Similar plugin is also available for VSCode users here.

Create directory blocs/authentication -> right click on it ->new->Bloc Generator -> New Bloc

This should generate the below bloc structure.

AuthenticationBloc : Contains the Bloc logic.

Contains the logic. AuthenticationEvent : Contains the Event classes.

Contains the classes. AuthenticationState : Contains the State classes.

Contains the classes. Bloc.dart : exports all the above classes as a package.

Setting up Firebase

Follow this guide to add Firebase to the project. once you’ve added the google-services.json and followed the steps mentioned in the above guide, go to your project on Firebase console and

Enable Google Authentication

2. Go to Database tab, create a “Cloud Firestore” database and under the rules tab paste the following rules. These are basic CRUD rules to authenticate users before they access our data. Read this documentation for more info on this.

rules_version = '2';

service cloud.firestore {

match /databases/{database}/documents {

match /users/{document=**} {



function isSignedIn() {

return request.auth.uid != null;

} //Allow creating a new user to anyone who is authenticated

allow create: if isSignedIn(); //Allow read if signed in

allow read: if isSignedIn(); // Allow update only if the uid matches (same user)

allow update: if isSignedIn() && request.auth.uid == resource.data.uid; // Allow delete only if the uid matches (same user)

allow delete: if isSignedIn() && request.auth.uid == resource.data.uid;

}

}

}

3. Go to Storage Tab and enable it.

This should setup everything for our project.

Creating the Events

Let’s define all our events first

AppLaunched : Dispatched by main.dart everytime the app start.

Dispatched by everytime the app start. ClickedGoogleLogin : Dispatched when the user clicks ‘Sign In with Google’ Button.

Dispatched when the user clicks ‘Sign In with Google’ Button. LoggedIn : When the authentication is successful, this event is dispatched internally by the Bloc to save the details received from google auth (name, profile picture, email) to Firebase FireStore and then prefil on the second page.

When the authentication is successful, this event is dispatched internally by the to save the details received from google auth (name, profile picture, email) to Firebase FireStore and then prefil on the second page. PickedProfilePicture : This event is dispatched when the user picks an image. It basically passes the image file to the Bloc which triggers a State change and loads the image from new file in the thumbnail.

This event is dispatched when the user picks an image. It basically passes the image file to the which triggers a change and loads the image from new file in the thumbnail. SaveProfile : This event is triggered when the user clicks the done FAB after filling out his age, username and other details.

This event is triggered when the user clicks the done FAB after filling out his age, username and other details. ClickedLogout : This event is not being used right now. We’ll later implement a logout button in the settings page of the app where this will be required.

Creating the States

The names of these states are pretty self explanatory. You’ll understand their usage, when we write the Bloc Logic.

Business Logic aka Bloc

The Bloc contains the event to state conversion logic.

The mapEventToState method takes the Events and yields the States as output. We are using three Repositories for our Bloc. yield is used with async streams in dart. yield adds a value to the output stream of the surrounding async* function. It's like return , but doesn't terminate the function. Refer this documentation for more details.

Creating the Repositories

AuthenticationRepository

Responsible for creating, terminating and retrieving session details.

UserRepository

Responsible for interacting with the FireStore Database, and saving the user data in it.

StorageRepository

Responsible for interacting with the Firebase Storage, uploading image files (for profile pictures in this case) in it.

The Model Class

For now we have a single model class, User . We’ll add a factory to it which can directly convert a Firestore DocumentSnapshot to a User object.

We started by creating the Bloc and then the repositories . Recalling from the previous post, the next layer below these is the Provider layer. Let’s create them.

Let’s Provide !

On one of my previous posts in this series a interesting question was posed by Nick DeMartin suggesting me to architect the app in a way which makes switching from Firebase to say AWS/other services really easy. Let’s see what we can do.

Start by creating abstract base provider classes for all the providers.

then the concrete implementations for all the three providers.

How does it help?

Using abstract implementations of providers will help us swap out the providers and replace them with different ones in future. All the logic related to the interaction with network/db/auth can be kept here. The upper layers will have no knowledge of how the data is being processed in the lower layers. All they’ll care about is about interacting with the repository.

Hooking the BLoC

We have created all the bells and whistles we needed for our app’s business logic to work. Now time to hook it to our UI, RegisterPage .

The first thing we need to do is provide the Bloc in the main Messio App widget itself so that we can trigger the AppStarted Event as soon as the app starts. We’ll user the BlocProvider to wrap our existing Messio App Widget. The builder is where we’ll instantiate the AuthenticationBloc and give it it’s required repository instances.

Now we’ll go ahead and hook the events and states to the RegisterPage . We’ll do it in the same order as shown in the diagram at the start.

First, ‘Sign In with Google’ button should dispatch a ClickedGoogleLogin() Event .

In our initApp() method we would want to receive the resultant state i.e. Authenticated and switch to the next page in PageView .

To show the CircularProgressBar we’ll use a BlocBuilder. It’s similar to a StreamBuilder. Here we give it the bloc to be used and in the builder we receive the state updates.

Similarly we’ll also implement the Event dispatches and BlocBuilder to receive states in other parts of the RegisterPage . In the end the RegisterPage class should look something like this.

And the result should look something like this.

Clean and Nice !

In next post we’ll take a look at how to write test cases for the layers we created today.

Note: You’ll probably face some dex errors while building this code due to issues with firestore and image_picker packages. Compare your android/build.gradle , android/app/build.gradle and android/gradle.properties files to with the one in the project to fix it.

References

Visit this gist.

Code Changes

#13 Registration Bloc

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

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!