Implementation

We are going to use the cloud_firestore package as Dart library for the implementation today.

Dependencies

Let’s add the required package to our project by including it into the dependencies section in pubspec.yaml first.

Now, run flutter packages get to get the new package and to be able to use it as a Dart library.

Recipe class

In order to be able to work with data from Firestore and Recipe objects we are going to implement a constructor fromMap in the class Recipe . The method fromMap is going to deserialize data that we are going to receive from Firestore and initialize a new Recipe object.

Let’s add the constructor fromMap to the class Recipe in recipe.dart.

lib/model/recipe.dart

In the previous article we have learned how to store app’s state and pass the state down the widget tree using InheritedWidget . So far we have stored data of the state in a State object. By now, the State class contains properties isLoading and user .

State

In order to store users’ favorites add a new property favorites of data type List<String> to the State class.

lib/model/state.dart

Since data of our recipes is stored in Firestore we do not need the getRecipes method in lib/utils/store.dart anymore.

Update Firestore Database

Delete the code in store.dart and put the implementation of the method updateFavorites that follows into the file store.dart.

Why do we need the method updateFavorites ?

Here is what the new method is going to do:

Create a collection “users” and a document named by the current user’s ID that contains an array “favorites”. The array “favorites” is going to be a list of string values representing recipe IDs.

Add the passed recipe ID to “favorites” of current user if the collection and document already exist and the collection “favorites” doesn’t contain given recipe ID.

Delete the recipe ID in the another case (the collection “favorites” already contains the passed recipe ID).

The method updateFavorites is going to contain the entire logic of adding or deleting entries of users’ favorites.

Here is the implementation:

lib/utils/store.dart

As next, we are going to add a new method called getFavorites to the class _StateWidgetState .

Initialize State

We are going to use getFavorites to get user’s favorites on the initialization of the app’s state. As soon as the current user is signed-in with Google we are going to load his or her favorites.

In the code that follows you can see the implementation of the new method getFavorites and how we use it within the method signInWithGoogle .

lib/state_widget.dart

Let’s move to the implementation of the list view in the widget of the home screen. There are a couple of changes we need to implement.

Home Screen

Since the method _handleFavoritesListChanged in _HomeScreenState does not update data in Firestore yet, we need to change it, too. We are going to implement the following scenario in _handleFavoritesListChanged :

Update the list of user’s favorites in Firestore by using the method updateFavorites

If the method updateFavorites has been successfully executed, update the state of the app

Take a look at the implementation.

lib/ui/screens/home.dart

In the last step we are going to change the method _buildTabsContent in home.dart so we are able to get recipes’ data from our cloud database.

We are going to change parameters of the private method _buildRecipes first. Change parameters of this method to optional parameters RecipeType recipeType and List<String> ids . Notice the syntax that we are using for optional named parameter in the code that follows. An optional named parameters are wrapped by curly brackets.

At the beginning of the method _buildRecipes we define a reference to the source of recipes’ data. In our case it is an CollectionReference to the previously created collection “recipes”. After that we declare a new Stream<QuerySnapshot> object called stream . Depending on whether an argument for the parameter recipeType has been passed we define stream so we get recipes of passed type or we get all recipes from the stream later on.

If we take a look at the implementation below we can see that the ListView.builder that we have been using before has been replaced by StreamBuilder . The StreamBuilder listens to the stream and returns a ListView containing RecipeCard widgets.

What about the parameter ids ? We are going to use ids to get RecipeCard widgets only for recipes contained in the list of favorites which are being stored in the favorites array in the State class.

Before a RecipeCard is being returned by the StreamBuilder we check if ids is set. If so, we check if the recipe’s ID is contained in the list passed to parameter ids .

Here is the code:

lib/ui/screens/home.dart

Now, delete unused variables in _HomeScreenState .

Well done! We have finished the implementation.

Let me summarize what we have learned today.