Flutter theme with Riverpod (2.0 generator)

2 min readJul 23, 2023

In this article, we are going to build a Flutter app that stores a user-selected theme in its settings and allows it to be switched on the fly, using Riverpod 2.0 and a generator.

In brief, the complete example is available on Github https://github.com/awaik/flutter_swith_theme_riverpod

So, let’s get started. Firstly, we need to create a SharedPrefs class to retain the user’s selected theme between app runs.

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AppSharedPrefs {
static AppSharedPrefs? _instance;
static SharedPreferences? _prefs;

factory AppSharedPrefs() {
if (_instance == null) {
throw Exception('AppSharedPrefs is not initialized. '
'Please call AppSharedPrefs.ensureInitialized before.');
return _instance!;

const AppSharedPrefs._();

static ensureInitialized() async {
_prefs ??= await SharedPreferences.getInstance();
_instance ??= const AppSharedPrefs._();

static const _themeKey = 'theme';

ThemeMode themeMode() {
final themeValue = _prefs!.getInt(_themeKey);
if (themeValue == null) return ThemeMode.system;

return ThemeMode.values[themeValue];

Future<void> updateThemeMode(ThemeMode theme) async {
await _prefs!.setInt(_themeKey, theme.index);

Next, we should initialize Shared Preferencies at the start. We do it by adding one line to the main.dart

await AppSharedPrefs.ensureInitialized();

Next, we create a simple riverpod class, to manage the theme state

import 'package:flashcards/core/shared_prefs/app_shared_prefs.dart';
import 'package:flutter/material.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'theme_provider.g.dart';

class ThemeState extends _$ThemeState {
ThemeMode build() {
return AppSharedPrefs().themeMode();

ThemeMode getTheme() {
return state;

void setTheme(ThemeMode mode) {
state = mode;

and generate providers with the command

 dart run build_runner build --delete-conflicting-outputs 

This is pretty much it. But let's dive into what is going on here.

First, we can read the documentation https://docs-v2.riverpod.dev/docs/concepts/about_code_generation and understand different defining a provider syntax. In our case, we use a Class-Based synchronous provider to have the ability to mutate a state.

As we have only one state — we return ThemeMode as a result. But in case we need to manage a lot of states for some screens, we can use ViewModel class with our custom variables and manage complicated states, animations and etc. But this is a topic for a separate article.

So, we made two methods

  1. getTheme — we can use it to get a state once.
  2. setTheme — to change it and save the state to SharedPrefs.

Now is the time to put it into the app. And it is a simple and beautiful code

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_swith_theme_riverpod/core/shared_prefs/app_shared_prefs.dart';
import 'package:flutter_swith_theme_riverpod/core/theme_state/theme_provider.dart';

void main() async {
await AppSharedPrefs.ensureInitialized();

runApp(const ProviderScope(child: MyApp()));

class MyApp extends ConsumerWidget {
const MyApp({super.key});

Widget build(BuildContext context, WidgetRef ref) {
final themeMode = ref.watch(themeStateProvider);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(useMaterial3: true),
darkTheme: ThemeData.dark(useMaterial3: true),
themeMode: themeMode,
home: Scaffold(
appBar: AppBar(
title: Text(themeMode.name),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'The current theme is:',
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(themeStateProvider.notifier).setTheme(),
tooltip: 'Change theme',
child: const Icon(Icons.color_lens_outlined),
), // This trailing comma makes auto-formatting nicer for build methods.

This code is clean and suited for production projects.

In case of any questions feel free to ask them on GitHub. The full code is here https://github.com/awaik/flutter_swith_theme_riverpod