InheritedWidget
as a provider to pass state between widgets and pagesLoginBloc
class to the Login pageAuthenticationBloc
class to manage user credentials for app‐wide state managementHomeBloc
class to the home page to list, add, and delete journal entriesJournalEditBloc
to the journal edit page to add or modify an existing entryStreamBuilder
widgetListView.separated
constructor to build a list of journal entries with a divider line by using the Divider
()
widgetDismissible
widget to swipe and delete an entryDismissible
widget confirmDismiss
property to prompt a delete confirmation dialogDropdownButton()
widget to present a list of moods with the title, color, and icon rotationMoodIcons
class to retrieve the mood title, color, rotation, and iconMatrix4 rotateZ()
method to rotate icons according to the mood in conjunction with the MoodIcons
classFormatDates
class to format datesIn this chapter, you'll continue to edit and complete the mood journaling app you've worked on in Chapters 14 and 15. For your convenience, you can use the ch15_final_journal
project as your starting point and make sure you add your GoogleService‐Info.plist
file to the Xcode project and the google‐services.json
file to the Android project that you downloaded in Chapter 14 from your Firebase console.
You'll learn how to apply the BLoC, service, provider, model, and utility classes to the UI widget pages. The benefit of using the BLoC pattern allows for separation of the UI widgets from the business logic. You'll learn how to use dependency injection to inject service classes into the BLoC classes. By using dependency injection, the BLoCs remain platform‐agnostic.
You'll also learn how to apply app‐wide state management by implementing the AuthenticationBlocProvider
class to the main page. You'll learn how to pass state between pages and the widget tree by implementing the HomeBlocProvider
and JournalEditBlocProvider
classes. You'll learn how to create a Login page that implements the LoginBloc
class to validate emails, passwords, and user credentials. You'll modify the home page and learn how to implement the HomeBloc
class to handle the journal entries list and add and delete individual entries. You'll learn how to create the journal edit page that implements the JournalEditBloc
class to add, modify, and save existing entries.
The Login page contains a TextField
for entering the email address and a TextField
for entering the password by obscuring the characters for privacy. You'll also add a button to log in the user and a button to create a new user account. You'll learn how to implement the LoginBloc
class by using the StreamBuilder
widget. You'll learn how to use dependency injection to inject the AuthenticationService()
class to the LoginBloc
class constructor, resulting in the LoginBloc
being platform‐agnostic. See Figure 16.1 for an idea of how the final Login page will look.
The main page is the control center responsible for monitoring app‐wide state management. You'll learn how to implement the AuthenticationBlocProvider
class as the main provider to the AuthenticationBloc
class. You'll learn how to implement the HomeBlocProvider
class as the provider to the HomeBloc
class with the child
property as the Home
class and also to hold the state for the user uid
. You'll learn how to apply the StreamBuilder
widget to monitor the user's authentication status. When the user logs in, the widget directs the user to the home page, and when the user logs out, it directs the user to the Login page. See Figure 16.2 for the main page BLoC flow.
The home page is responsible for showing a list of journal entries filtered by the logged‐in user uid
and the ability to add, modify, and delete individual entries. In this section, you'll learn how to implement the AuthenticationBlocProvider
as the provider for the AuthenticationBloc
class. You'll learn how to implement the HomeBlocProvider
class as the provider for the HomeBloc
class. You'll learn how to apply the StreamBuilder
widget to build the journal entries list by calling the ListView.separated
constructor. The Dismissible
widget is used to swipe on an item to delete the entry. You'll learn how to use the Dismissible
widget confirmDismiss
property to prompt the user with a delete confirmation dialog. You'll learn how to call the MoodIcons
class to color and rotate icons according to the selected mood. You'll learn how to call the FormatDates
class to format dates.
Note that I purposely didn't inject the MoodIcons
and FormatDates
classes into the HomeBloc
and EditJournalBLoc
classes to show that you can decide not to include certain utility classes in the BLoC. If you were to include them in these BLoCs, you would duplicate the MoodIcons
and FormatDates
methods into two different BLoCs. In Chapter 15's “Implementing the BLoC Pattern” section, you learned in the UI design guidelines to create a BLoC for each complex enough component. Another option is to create a MoodAndDatesBloc
class to handle the MoodIcons
and FormatDates
classes (as abstract classes) and use the MoodAndDatesBloc
class in both the home and edit entry pages. See Figure 16.3 for an idea of how the final home page will look.
The edit journal page is responsible for adding and editing a journal entry. In this section, you'll learn how to create the journal edit page that implements the JournalEditBlocProvider
as the provider for the JournalEditBloc
class. You'll learn to use the StreamBuilder
widget with the date, mood, note, and Cancel and Save buttons. You'll implement the showTimePicker()
function to present the user with a calendar to choose a date. You'll learn how to use the DropdownButton()
widget to present the user with a list of selectable moods with the icon, color, description, and mood icon rotation. You'll use the Matrix4 rotateZ()
method to implement the mood icon rotation. You'll use the TextEditingController()
constructor with the note TextField()
widget. You'll learn how to call the MoodIcons
class to color and rotate icons in the DropdownButton DropdownMenuItem
selection list. You'll learn how to call the FormatDates
class to format the selected date. See Figure 16.4 for the look of the final edit journal page.
In this chapter, you completed the journal app that you started in Chapter 14. You applied the BLoC pattern to separate the UI widgets from the business logic. You implemented BLoC classes, BLoC providers, service classes, utility classes, model classes, and app‐wide and local‐state management. You passed app‐wide state management between pages and local‐state management in the widget tree by using providers (InheritedWidget
) and BLoCs. You used dependency injection to inject service classes into the BLoC classes. You learned that the benefit of using dependency injection keeps the BLoC classes platform‐agnostic, giving the ability to share BLoC classes between different platforms like Flutter, AngularDart, or others.
You applied app‐wide state management by implementing the AuthenticationBlocProvider
and AuthenticationBloc
classes to the app's main page. You used the StreamBuilder
widget to monitor the _authenticationBloc.user stream
for user credential changes. When the user credential changes, the StreamBuilder builder
rebuilds and appropriately navigates the user to the login or home page.
You applied the LoginBloc
class to validate the user's credentials and email and password requirements. You overrided the initState()
method to initialize the _loginBloc
variable with the LoginBloc
class by injecting the AuthenticationService()
class without using a provider. Note that the reason you initialized the _loginBloc
variable from the initState()
and not the didChangeDependencies()
is because the LoginBloc
does not need a provider (InheritedWidget
).
You used the StreamBuilder
widget with the TextField
widget to validate email and password values. The TextField
widget's onChanged
property calls the _loginBloc.emailChanged.add sink
and the _loginBloc.passwordChanged.add sink
to send the values to the LoginBloc Validators
class. You used the StreamBuilder
widget to listen to the _loginBloc.loginOrCreateButton stream
to toggle Login or Create Account as the default button.
You applied the HomeBloc
class to build a list of journal entries filtered by the user uid
with the ability to add, modify, and delete entries. You accessed the AuthenticationBlocProvider
and HomeBlocProvider
classes by using the provider's of()
method from the didChangeDependencies
method. You used the StreamBuilder
widget by calling the ListView.separated
constructor to build the journal entries list. You used the Dismissible
widget's confirmDismiss
property to prompt the user with the delete confirmation dialog. You called the MoodIcons
utility class to format mood icons and the FormatDates
class to format dates.
You accessed the JournalEditBlocProvider
class by using the provider's of()
method from the didChangeDependencies
method. You applied the JournalEditBloc
class to add, edit, and save journal entries. You used the StreamBuilder
widget to handle the date, mood, note, and Cancel and Save buttons. You implemented the showTimePicker()
function to show a calendar and to use the DropdownButton()
widget to present the user with a list of selectable moods. You used the Matrix4 rotateZ()
method to rotate the mood icon according to mood. You used the MoodIcons
class with the DropdownButton DropdownMenuItem
to present the mood selection list. You used the FormatDates
class to format the selected date.
TOPIC | KEY CONCEPTS |
LoginBloc class |
You learned how to implement the LoginBloc class without a provider to handle the authentication credentials and to validate email and password requirements. |
AuthenticationBloc class |
You learned how to implement the AuthenticationBloc class with the AuthenticationBlocProvider class to handle app‐wide state management in the main page. |
HomeBloc class |
You learned how to implement the HomeBloc class with the HomeBlocProvider class to populate the ListView with journal entries by using the separated() constructor. You learned to use the HomeBloc class to add, modify, or delete existing journal entries. |
JournalEditBloc class |
You learned how to implement the JournalEditBloc class without a provider to add or edit and save journal entries. |
InheritedWidget class |
The AuthenticationBlocProvider , HomeBlocProvider , and JournalEditBlocProvider classes extend from the InheritedWidget class, and you learned how to access them from the didChangeDependencies() method and not the initState() method. |
AuthenticationBlocProvider class |
You learned how to implement the AuthenticationBlocProvider as the provider for the AuthenticationBloc class for app‐wide authentication state management. |
HomeBlocProvider class |
You learned how to implement the HomeBlocProvider class as the provider for the HomeBloc class. |
Dependency injection | You learned how to use dependency injection by injecting service classes to the BLoC classes. You learned that by injecting services, the BLoC classes remain platform‐agnostic. |
StreamBuilder widget |
You learned how to implement the StreamBuilder widget to monitor a stream , and when a change occurs, the builder rebuilds the widget with the latest data. |
ListView.separated constructor and Divider() widget |
You learned how to implement the ListView.separated constructor to build a list of journal entries separated by a Divider() widget. |
Dismissible widget and confirmDismiss property |
You learned how to implement the Dismissible widget to swipe and delete a journal entry. You learned how to implement the Dismissible widget's confirmDismiss property to prompt a dialog to confirm deleting a journal entry. |
DropdownButton() widget |
You learned how to implement the DropdownButton() widget to present a list of moods with the title, color, and icon rotation. |
MoodIcons class |
You learned how to implement the MoodIcons class to retrieve the mood's properties like the title , color , rotation , and icon . |
showTimePicker() function |
You learned how to implement the showTimePicker() function to present a calendar to choose a date. |
Matrix4 rotateZ() method |
You learned how to implement the Matrix4 rotateZ() method to rotate an icon according to the selected mood. |
FormatDates class |
You learned how to implement the FormatDates class to format dates. |