CODEX
Flutter Navigator 2.0 for Authentication and Bootstrapping — Part 4: Bootstrapping

- Part 1: Introduction
- Part 2: User Interaction
- Part 3: Authentication
- Part 4: Bootstrapping
- Part 5: Web
In the third part of this series, we explored the Navigator 2.0 API with the authentication use case. In this article, we handle the bootstrapping process and build the navigation stack accordingly.

Let’s start with clarifying what I mean by bootstrapping. According to techterms.com website:
… bootstrapping is the startup process that takes place when you start up a computer… While bootstrapping is often associated with the system boot sequence, it can be used by individual applications as well. For example, a program may automatically run a series of commands when opened. These commands may process user settings, check for updates, and load dynamic libraries ... They are considered bootstrap processes because they run automatically as the program is starting up.
In many applications, when the app is launched, the authentication state is checked first. If the user is logged in, the app prepares itself by fetching user data from the local and remote data sources. Usually, a splash screen is shown to a user until the app is ready. In this article, we focus on the navigation of screens starting from the launch of the app until the point that the app is showing the home screen with user-specific data.

ColorsRepository
In the previous samples, the list of colors is accessed from Flutter's Colors
class immediately. In this sample, we access the colors from the ColorsRepository
class asynchronously during the bootstrapping process. The fetchColors()
method returns the same color list from the Colors
class with a delay of 3 seconds.
Normally, the repository pattern is used for abstracting the data access. Thus, we shouldn’t implement the data access logic here. However, in our case, we implemented the data access logic in the repository classes for easy explanation with less code and staying more focused on the actual topic.
The App
When the app is launched, the Router
widget is instantiated and located at the top of the app widget tree as in the previous samples. In this sample, we inject the ColorsRepository
together with the AuthRepository
to the app through ColorsViewModel
and AutViewModel
classes using the Provider State Management pattern.
The RouterDelegate
The list of colors state is saved in the _colors
property of the RouterDelegate
class together with the _loggedIn
, _selectedColorCode
and the _selectedShape
states.
Let’s see what happens when the RouterDelegate
class is initialized:
- The
RouterDelegate
asks to theAuthRepository
the authentication state, and waits until it receives the result. - Meanwhile, the
Router
widget calls thebuild
method of theRouterDelegate
andSplashScreen
for fetching the checking login state is shown to the user as explained in the previous article. - When the authentication state is received, the
RouterDelegate
notifies theRouter
widget inside the setter method of the_loggedIn
. - The
Router
widget asks theRouterDelegate
to build the navigation stack accordingly.
If the user is already logged in
- Navigator widget with
_splashStack
is returned from thebuild
method of theRouterDelegate
andSplashScreen
for fetching the colors is shown to the user.
- The
RouterDelegate
requests the colors from theColorsRepository
class. It callsColorsRepository.fetchColors()
method, and waits until it receives the colors. - When the color list is fetched, the
RouterDelegate
sets thecolors
state and notifies theRouter
widget inside its setter method. - The
Router
widget asks theRouterDelegate
to build the_loggedInStack
navigation stack.

If the user is not logged in
- Navigator widget with
_loggedOutStack
is returned from thebuild
method andLoginScreen
is shown to the user. - When
onLogin
callback is invoked inside theLoginScreen
,loggedIn
state is set to true and theRouter
widget is notified. - Navigator widget with
_splashStack
is returned from thebuild
method of theRouterDelegate
andSplashScreen
for fetching the colors is shown to the user. ColorsRepository.fetchColors()
method is invoked.- When the color list is fetched, the
RouterDelegate
sets thecolors
state and notifies theRouter
widget inside its setter method. - The
Router
widget asks theRouterDelegate
to build_loggedInStack
the navigation stack.

Different from the previous sample app, the _splashStack
is built also considering the _colors
state. If the _colors
has not yet been fetched and the user is logged in, the app should show the SplashScreen
because it is waiting for the colors from the ColorsRepository
. The _loggedInStack
and the _loggedOutStack
is exactly the same as the second sample.
In this sample app, we associate the list of colors with the user. Therefore, when the user logs out, we clear the states by setting _colors
, _selectedColorCode
and the _selectedShape
states to null
. We also should call the ColorsRepository.clearColors()
method to clear the data associated with the user.
ColorsViewModel
The ColorsViewModel
and AuthViewModel
classes extend ChangeNotifier
mixin and they are injected into the app tree widget using the Provider state management library. The ViewModel
classes are used to represent the states of the data fetching process. It is debatable for many developers whether state management with Provider pattern is exactly MVVM (Model-View-ViewModel). I am not going to explain my opinions on this to give the focus more on the the navigation topic.
loggingIn
, loggingOut
, fetchingColors
, and clearingColors
states inside the view models are accessed by the child widgets to figure out if an operation is started, in progress, and done.
Logout Fab
When the LogoutFab
widget is pressed:
AuthViewModel.logout
is called. This method sets thelogingOut
state inside theAuthViewModel
totrue
, and callsnotifyListeners
which will cause a rebuild of theLogoutFab
.LogoutFab
widget shows a floating action button (fab) with aCircularProgresIndicator
- When the
logout
process is done,logingOut
state inside theAuthViewModel
is set tofalse
and theLogoutFab
widget is notified. - This time, the rebuilding of the
LogoutFab
widget will not be noticeable because the subsequentcolorsViewModel.clearColors()
call will set theclearingColors
state totrue
which causes another rebuilding. LogoutFab
will be rebuilt, and a FAB with aCircularProgresIndicator
is shown again.- When the
clearColors()
process is done,clearingColors
state inside theAuthViewModel
is set tofalse
and theLogoutFab
widget is notified. - Again, the rebuilding will not be noticeable because the subsequent
onLogout
call will cause a rebuilding of the navigation history inside theRouterDelegate
and as a result,LoginScreen
will be shown.
HomeScreen, ColorScreen, ShapeScreen
We want the HomeScreen
, ColorScreen
, and ShapeScreen
to have the same logic so that whenever the LogoutFab
is pressed, the user will be notified with a text telling that logout
is in progress and clearing the color list.
The state management inside these widgets is straightforward. If either AUthViewModel.logingOut
or ColorsViewModel.clearingColors
are true, we show the InProgressMessage
which is a custom widget that shows the operation name and the screen name to the user.

Disclaimer
Note that in this sample app, all the properties used to determine the current app state are stored separately in the RouterDelegate
class for demonstration purposes and easier explanation. This is not recommended as the number of these properties is subject to increase over time during application development, and it will be overkill to store them all. We need to apply best practices with a clean architecture. For example, we don’t need to store the colors
list inside RouterDelegate
. In fact, we shouldn’t inject the repository classes to the RouterDelegate
because RouterDelegate
class doesn’t need to know which repositories are needed to find out the app state. Instead, we could inject the use case classes that interact with the repositories using dependency injection libraries. Although clean architecture is out of this series of article’s scope, I would strongly recommend further reading if the reader is not familiar with the topic.
Conclusion
In this article, we learned how to build a navigation stack in response to the app state changes caused by bootstrapping. You can find the source code on the Github page. The project includes multiple main.dart
files. The easiest way of running this sample app is right-clicking on the main_002_03.dart
file and selecting the Run 'main_002_03.dart'
.
Until now, we used the Navigator 2.0 API for mobile applications. All these samples will also work for Web applications but the user experience will be poor since the Web browser’s address bar won’t be updated with the navigation stack updates. In the next article, we will learn how to parse and restore Web URL links and navigate accordingly.
Special thanks to Jon Imanol Durán who reviewed all the articles in this series and gave me useful feedback. If you liked this article, please press the clap button, and star the Github repository.