It'sPhil
It'sPhil

Reputation: 117

How to use SharedPreferences on switch with changing the theme flutter

I've implemented the theme for the app theme_managers.dart and I've done SharedPreferences on the theme.dart. But the problem is the SharedPreferences on the switch it's working when. I reopen the app it still getting data from last action but the theme(dark mode) get reset all the time when reopen the app.

I don’t understand if I need to put the SharedPreferences on the theme_manager.dart or not. If you know Please point out the problem or some code. Thanks

Please look though my code and you’ll understand the problem.

In theme.dart(some) :

bool colorMode = false;

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

  getSwitchValues() async {
    colorMode = await loadbool();
    setState(() {});
  }

  Future<bool> savebool(bool value) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    themeManager.toggleTheme(value);
    prefs.setBool("colorMode", value);
    return prefs.setBool("colorMode", value);
  }

  Future<bool> loadbool() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool? colorMode = prefs.getBool("colorMode");

    return colorMode!;
  }
//Switch
               Switch(
                activeColor: Colors.grey,
                value: colorMode,
                onChanged: (bool value) {
                  setState(() {
                    themeManager.toggleTheme(value);
                    colorMode = value;
                    savebool(value);
                  });
                }),

In theme_manager.dart :

class ThemeManager extends ChangeNotifier {

  ThemeMode _themeMode = ThemeMode.light;

  get themeMode => _themeMode;

  toggleTheme(bool isDark){
    _themeMode = isDark? ThemeMode.dark :ThemeMode.light;
    notifyListeners();
  }
}

In main.dart(some) :

ThemeManager themeManager = ThemeManager();

@override
  void initState() {
    themeManager.addListener(themeListener);
    super.initState();
  }

  @override
  void dispose() {
    themeManager.removeListener(themeListener);
    super.dispose();
  }

  themeListener() {
    if (mounted) {
      setState(() {});
    }
  }

MultiProvider(
         Provider(create: (_) => User),
        ChangeNotifierProvider(create: (context) => themeManager)
      ],
      child: MaterialApp(
        title: 'My app',
        themeMode: themeManager.themeMode,
        theme: ThemeData.light(),
        darkTheme: ThemeData.dark(),
        home: const LoginScreen(),
        debugShowCheckedModeBanner: false,
      ),
    );

I forgot to mention my theme_constant.dart :

const colorPrimary = Colors.black;
const colorAccent = Colors.black;

ThemeData lightTheme = ThemeData(
    brightness: Brightness.light,
    primaryColor: colorPrimary,
    floatingActionButtonTheme:
        const FloatingActionButtonThemeData(backgroundColor: colorAccent),
    elevatedButtonTheme: ElevatedButtonThemeData(
        style: ButtonStyle(
            padding: MaterialStateProperty.all<EdgeInsetsGeometry>(
                const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20.0)),
            shape: MaterialStateProperty.all<OutlinedBorder>(
                RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(20.0))),
            backgroundColor: MaterialStateProperty.all<Color>(colorAccent))),
    inputDecorationTheme: InputDecorationTheme(
        border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(20.0),
            borderSide: BorderSide.none),
        filled: true,
        fillColor: Colors.grey.withOpacity(0.1)));

ThemeData darkTheme = ThemeData(
  brightness: Brightness.dark,
  switchTheme: SwitchThemeData(
    trackColor: MaterialStateProperty.all<Color>(Colors.black),
    thumbColor: MaterialStateProperty.all<Color>(Colors.black),
  ),
  inputDecorationTheme: InputDecorationTheme(
      border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(0.0),
          borderSide: BorderSide.none),
      filled: true,
      fillColor: Colors.black.withOpacity(0.0)),
  elevatedButtonTheme: ElevatedButtonThemeData(
      style: ButtonStyle(
          padding: MaterialStateProperty.all<EdgeInsetsGeometry>(
              const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20.0)),
          shape: MaterialStateProperty.all<OutlinedBorder>(
              RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(20.0))),
          backgroundColor: MaterialStateProperty.all<Color>(Colors.white),
          foregroundColor: MaterialStateProperty.all<Color>(Colors.black),
          overlayColor: MaterialStateProperty.all<Color>(Colors.black))),
);

I am not sure If the problem is from here too?

Upvotes: 0

Views: 203

Answers (2)

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63594

Material directly using themeManager.themeMode which returns the ThemeMode.light

 themeMode: themeManager.themeMode,

You might create a method, and make sure to get data from this future before providing on materialApp

class ThemeManager extends ChangeNotifier {
  ThemeMode _themeMode = ThemeMode.light;

  ThemeMode get themeMode => _themeMode;

  Future<void> initTheme() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool? colorMode = prefs.getBool("colorMode");
    // switch if needed
    _themeMode = colorMode == true ? ThemeMode.dark : ThemeMode.light;
    notifyListeners();
  }

Upvotes: 0

Legostein
Legostein

Reputation: 82

Try to load the ThemeMode before calling runApp() in your main method, e. g. by adding this to your main method:

void main() async {
  ThemeManager themeManager = ThemeManager();
  await themeManager.loadTheme(); // load the theme before running the app

  runApp(
    MultiProvider(
      providers: [
        Provider(create: (_) => User),
        ChangeNotifierProvider(create: (context) => themeManager),
      ],
      child: MaterialApp(
        title: 'My app',
        themeMode: themeManager.themeMode, // now the theme mode is the one loaded from shared prefs
        theme: ThemeData.light(),
        darkTheme: ThemeData.dark(),
        home: const LoginScreen(),
        debugShowCheckedModeBanner: false,
      ),
    ),
  );
}

And for this to work, add the loadTheme() method to your ThemeManager class:

class ThemeManager extends ChangeNotifier {

  ThemeMode _themeMode = ThemeMode.light;

  get themeMode => _themeMode;

  toggleTheme(bool isDark){
    _themeMode = isDark? ThemeMode.dark :ThemeMode.light;
    notifyListeners();
  }

  Future<void> loadTheme() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool isDark = prefs.getBool("colorMode") ?? false;
    _themeMode = isDark ? ThemeMode.dark : ThemeMode.light;
  }
}

Upvotes: 1

Related Questions