Flutter State Management With Provider Package.

Without further ado, let’s get started with today’s article, where I’ll talk about how to implement dark mode in an app and manage Flutter state using the provider package.

What is state management in Flutter?

State management refers to managing the states of UI controls based on business logic requirements, as most often one or more controls are dependent upon each other.

Note: To change the state of a widget in Flutter, we use the setState method.

Example

Let’s say you have a ToDo app, and you have added an item to your list. You must refresh the page in order to see the item. In this situation, state management kicks in, allowing you to add, edit, and delete ToDo items without needing to reload the page.

You can learn more about Flutter state management by visiting the following link.

What is the provider package?

The provider package is created by Remi Rousselet to handle the state as cleanly as possible. Widgets in Provider update as soon as they become aware of changes in the state.

Example

Let’s say you have an app and you want to add dark mode features to it, but when you enable dark mode, it should change the color scheme of the whole app, not just a single page. Since setState does not reflect changes in the entire app, we need a provider package at this point.

Let’s understand some methods before using the provider package:

  • ChangeNotifierProvider: This is the app’s entry point to enable the provider package.
  • Provider.of<>(): Interacts between data holder(ChangeNotifier) and Consumer.
  • Consumer: Uses data from ChangeNotifier.
  • ChangeNotifier: The ChangeNotifier class holds data.
  • notifierListener: This method is equivalent to setState.

For more information, you can check out this link.

Implement the dark mode in the Flutter app

First, you must include these two packages in your pubspec.yaml file.

provider: ^6.0.2
shared_preferences: ^2.0.13

Do the pub get after adding these two dependencies to pubspec.yaml.

Create these files under your lib folder,

themes/theme_color_scheme.dart

import 'package:flutter/material.dart';

class ThemeColor {
  static ThemeData themeData(bool isDarkMode, BuildContext context) {
    return ThemeData(
      primarySwatch: Colors.blue,
      primaryColor: isDarkMode ? Colors.black : Colors.white,
      backgroundColor: isDarkMode ? Colors.black : Color(0xFFF1F5FB),
      indicatorColor: isDarkMode ? Color(0xFF0E1D36) : Color(0xFFCBDCF8),
      buttonColor: isDarkMode ? Color(0xFF3B3B3B) : Color(0xff133762),
      hintColor: isDarkMode ? Color(0xFF280C0B) : Color(0xff133762),
      highlightColor: isDarkMode ? Color(0xFF372901) : Color(0xff133762),
      hoverColor: isDarkMode ? Color(0xFF3A3A3B) : Color(0xff133762),
      focusColor: isDarkMode ? Color(0xFF0B2512) : Color(0xff133762),
      disabledColor: Colors.grey,
      textSelectionColor: isDarkMode ? Colors.white : Colors.black,
      cardColor: isDarkMode ? Color(0xFF151515) : Colors.white,
      canvasColor: isDarkMode ? Colors.black : Colors.grey[50],
      brightness: isDarkMode ? Brightness.dark : Brightness.light,
      buttonTheme: Theme.of(context).buttonTheme.copyWith(
          colorScheme: isDarkMode ? ColorScheme.dark() : ColorScheme.light()),
      appBarTheme: AppBarTheme(
        elevation: 0,
      ),
    );
  }
}

themes/theme_preference.dart

import 'package:shared_preferences/shared_preferences.dart';

class ThemePreference {
  static const theme_status = "THEMESTATUS";

  setDarkTheme(bool value) async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    preferences.setBool(theme_status, value);
  }

  Future<bool> getTheme() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    return preferences.getBool(theme_status) ?? false;
  }
}

themes/theme_provider.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter_dark_mode/themes/theme_preference.dart';

class ThemeProvider with ChangeNotifier {
  ThemePreference themePreference = ThemePreference();
  bool _darkTheme = false;

  bool get darkTheme => _darkTheme;

  set darkTheme(bool value) {
    _darkTheme = value;
    themePreference.setDarkTheme(value);
    notifyListeners();
  }
}

screens/home_screen.dart

import 'package:flutter/material.dart';
import 'package:flutter_dark_mode/themes/theme_provider.dart';
import 'package:provider/provider.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    final themeChange = Provider.of<ThemeProvider>(context);
    void toggleSwitch(bool value) {
      if (themeChange.darkTheme == false) {
        setState(() {
          themeChange.darkTheme = true;
        });
      } else {
        setState(() {
          themeChange.darkTheme = false;
        });
      }
    }

    return Scaffold(
      appBar: AppBar(
        title: Text("Dark Theme Demo"),
      ),
      body: SingleChildScrollView(
        child: Container(
          padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
          child: Column(
            children: [
              Container(
                padding: const EdgeInsets.only(bottom: 5),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    const Text(
                      "Dark theme",
                      style: TextStyle(fontSize: 18),
                    ),
                    Switch(
                      onChanged: toggleSwitch,
                      value: themeChange.darkTheme,
                    ),
                  ],
                ),
              ),
              const Divider(),
            ],
          ),
        ),
      ),
    );
  }
}

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_dark_mode/screens/home_screen.dart';
import 'package:flutter_dark_mode/themes/theme_color_scheme.dart';
import 'package:flutter_dark_mode/themes/theme_provider.dart';
import 'package:provider/provider.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  ThemeProvider themeChangeProvider = ThemeProvider();

  @override
  void initState() {
    super.initState();
    getCurrentAppTheme();
  }

  void getCurrentAppTheme() async {
    themeChangeProvider.darkTheme =
        await themeChangeProvider.themePreference.getTheme();
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) {
        return themeChangeProvider;
      },
      child: Consumer<ThemeProvider>(
        builder: (BuildContext context, value, child) {
          return MaterialApp(
            title: 'Dark Theme',
            debugShowCheckedModeBanner: false,
            theme: ThemeColor.themeData(themeChangeProvider.darkTheme, context),
            home: HomeScreen(),
          );
        },
      ),
    );
  }
}

Everything is done. Run your app now.

You can download the source code from the GitHub repository.

Conclusion

This article shows you how to use the provider package to manage the Flutter app state and create dark mode features in your app. Please feel free to share, like, and comment if you enjoyed this article.

Leave a Reply

Your email address will not be published.