How to toggle between dark mode and light mode using the Stacked architecture in Flutter
Tags: flutter, themes, dart, darkmode
Published: 2021-01-18 06:26:56

## Setup
To start things off, make sure you install a fresh Flutter project to follow along.

```
// you can name the project anyway you want, 
// in this case I will just use this name below
flutter create stacked_theme_switcher
```

If you aren’t familiar about the stacked architecture, then I highly recommend you to watch and learn how to setup the stacked architecture from FilledStacks before following through this tutorial since it requires an understanding of the stacked architecture.

I have learned about stacked architecture from there and the content and quality of his tutorials are great so you should check it out.

And if you are familiar about the stacked architecture, then let’s install the dependencies that we need. Head over to your `pubspec.yaml` file in your project directory and put these dependencies.

```
dependencies:
 # state
 stacked: ^1.7.3+2
 # inversion of control
 injectable:
 observable_ish:
 get_it: ^4.0.2
dev_dependencies:
 build_runner:
 injectable_generator:
```

Under dependencies, we need the stacked since it is what we are using for our state management solution. The other 3 below are the ones that handles dependency injection in our Flutter app. For `observable_ish` package handles the reactive values inside services of the stacked architecture. You might say it is an old package but there is a reason why Dane from FilledStacks have chosen this package. But I am now going to talk about that in here.

And lastly, under the `dev_dependencies`, these are what we need so we can avoid boilerplate code in our Flutter app since we would be using injectable annotations as how they are recognized for the builders.

Okay so make sure you run pub get to install the dependencies.
flutter pub get

## Dependency Injection

After setting up for the project, we can then start writing code for our theme switcher. For the main.dart file, clean it up and leave what we only need.

![](https://miro.medium.com/max/465/1*rDzW0F30OmyOb5FAqvEa7Q.png)
<figcaption>main.dart</figcaption>

We create a folder inside /lib directory and name it as “app”, in this directory is where we put our locator, this handles the dependency injection of our Flutter application. And then create a file locator.dart in it.

![](https://miro.medium.com/max/424/1*H-mcGYEJZPOAYu1lhAGsdg.png)
<figcaption>locator.dart</figcaption>

If you have followed then your project directory would look something like this.

![](https://miro.medium.com/max/191/1*zqU1jVmIZTVA4RjAF8buGA.png)
<figcaption>project directory</figcaption>

You may see that VSCode have been indicating errors in the code and that’s fine because the auto-generated boilerplate code are not there yet. Hang on for a little bit as we need to create our theme switcher class or theme service.

In the /lib directory, create a new directory and name it as “services” since inside here we put all of our services that will be responsible of serving some sort of data into our viewmodels. Then create a file called as theme_service.dart and inside the file, write the code and put a lazySingleton annotation from the injectable package, so it will auto register this service and make it accessible globally in our Flutter app.

![](https://miro.medium.com/max/465/1*wlWxtwyjBD2yG3aTzvCWaw.png)
<figcaption>theme_service.dart</figcaption>

When you have created it already then it’s about time we run the builder and let it generate boilerplate code for us! Open up a terminal or use your existing terminal, then execute the command below

```
flutter pub run build_runner build
```

It would take a moment to auto generate the code for us. So please wait. :) It should look something like this if you have done things correctly.

![](https://miro.medium.com/max/700/1*lUH7_7YWjVEjUJ6fha5rJA.png)
<figcaption>terminal</figcaption>

Basically it created a locator.config.dart file and it registered the ThemeService class as a singleton, this we can now access our ThemeService globally in our application if you might need theming in other parts of the code.

This is what the auto-generated code looks like…

![](https://miro.medium.com/max/684/1*AtpTCvI_I2KaSKpbPL-_sw.png)
<figcaption>locator.config.dart</figcaption>

## Theme Definition

Right after we have set up our `ThemeService` class and registered it as a singleton, we then define our theme data inside the `ThemeService` class, our `ThemeService` class is using a mixin `ReactiveServiceMixin` since this will be handling the reactive values in the service.

We then import `observable_ish` inside this `ThemeService` class since we will be using it inside the class as we would be toggling over dark theme and light theme during run time. Then we also import material package since we will be using classes like `ThemeData`, `ThemeMode` and other widgets related to create our theme. Then we also instantiate reactive values from `observable_ish` and give it a type of `ThemeMode` since we will be toggling over dark and light mode.

![](https://miro.medium.com/max/692/1*Foatkh6Cdreu7G06Ut0P4A.png)
<figcaption>theme_service.dart (Part 1)</figcaption>

![](https://miro.medium.com/max/563/1*5bWPlUkeAYoo6gEjTpMt1w.png)
<figcaption>theme_service.dart (Part 2)</figcaption>

After defining our properties for light theme and dark theme, we can then make our application toggle between themes.

## Toggle Theme

Now back into our `main.dart`, put `setupLocator()` before `runApp()` since we want to instantiate those services before the app starts. It should look something like this,

![](https://miro.medium.com/max/603/1*J-sQ_AI3jA9FOHVjhszKSw.png)
<figcaption>main.dart</figcaption>

And then wrap our `MaterialApp()` in a `ViewModelBuilder.reactive()` named constructor, create a `MainViewModel` class under and give the `ViewModelBuilder` a type of `MainViewModel`.

![](https://miro.medium.com/max/617/1*Hqt5VFD4pzhP_hxDjpSHKQ.png)

Here we added reference to our ThemeService that was registered as a singleton as we were setting it up. This means we have access to the methods and properties inside our ThemeService and since our MainViewModel extends ReactiveViewModel, it has a required override annotation, in it we put all of our dependencies in an array, in our case we only have _themeService in it because it is the only service we only want to listen to for changes.

If you have noticed, we have a property added in our MaterialApp widget, there we put our home screen as it’s the first view that gets rendered when our app starts.

![](https://miro.medium.com/max/432/1*5jZjvoLvoHxjJLW7ybxtcA.png)
<figcaption>home screen</figcaption>

To create this view, as convention being followed from the stack architecture, let us create a directory inside /lib and name it as “ui” and inside /ui directory we create another directory called as “views”, inside this directory is where we put all of our user interface code along with its `viewmodel` of each views. And lastly, we want the home screen, so we create another folder called as “home” and inside this folder we create 2 files, `home_view.dart` & `home_viewmodel.dart` Inside `home_view.dart` is where we put our UI related code and all logic inside `home_viewmodel.dart`

Inside our `home_view.dart` we create a Scaffold that is wrapped inside a `ViewModelBuilder` of type `HomeViewModel` so we have access to methods from the `ViewModel` that this view is coupling with. Then as the body of our Scaffold we put a `RaisedButton` widget, and on tap we toggle the theme between light and dark.

![](https://miro.medium.com/max/683/1*7dZwftOi5tR9p19CI_rtkA.png)
<figcaption>home_view.dart</figcaption>

And the code for the home_viewmodel.dart …

![](https://miro.medium.com/max/634/1*U-PVzGrp61IhVY-ZuVW18Q.png)
<figcaption>home_viewmodel.dart</figcaption>

Inside the view model is we will be using the `ThemeService` again as dependency so we can make use of the `toggleTheme()` method from the `ThemeService` class to be able to switch between light and dark theme.

And from there, we can now toggle between dark and light theme!
Thanks for following through and I hope you have liked it. But if you have a better way of implementing this one then let me know I would appreciate it :)

Cheers!