Flutter State Management With Provider Package

In today's article, I'll discuss Flutter state management using the provider package, as well as dark mode implementation in an app using the provider package, so let's get started without further delay.

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.

Examples

Let's say you have a ToDo app, and you have added an item to your list. To see the item, you need to refresh the page. In that case, state management comes into play and you can add, edit, and delete ToDo items without having to refresh 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.

Implement the dark mode in the Flutter app

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.

Reference

You can download the source code from the GitHub repository.

Link:https://github.com/socialmad/flutter_dark_mode

Conclusion

In this article, we saw how you can use the provider package to manage the Flutter app state and create dark mode features in your app using the provider package. If you like this article feel free to like, comment and share.

Thanks for reading…