Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting theme based on SharedPreference data

My goal for this flutter app is to change the theme (Dark, Light, System) based on the stored Shared Preferences data. I used Provider so that every time the user changes the theme, the entire app will update based on the selected theme. The issue is when the user first starts up the app, it finishes building before we can get the value of the theme from Shared Preference. Therefore we are getting a null value for the theme when the app initially loads. My code only works if the user is updating the theme value after the app finishes loading on startup.

  void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(ChangeNotifierProvider<PreferencesProvider>(
      create: (context) {
        return PreferencesProvider();
      },
      child: MyApp()));
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {

    print(SettingsSharedPreferences.getThemeString());
    return ChangeNotifierProvider<HabitProvider>(
      create: (context) {
        return HabitProvider();
      },
      child: MaterialApp(
        darkTheme: ThemeData(brightness: Brightness.dark),
        themeMode: context.watch<PreferencesProvider>().theme == "System"
            ? ThemeMode.system
            : context.watch<PreferencesProvider>().theme == "Dark"
                ? ThemeMode.dark
                : context.watch<PreferencesProvider>().theme == "Light"
                    ? ThemeMode.light
                    : ThemeMode.system,
        home: MyHomePage(title: 'My App'),
      ),
    );
  }
}

This is the Provider class. Note that the variable theme is getting its data from the stored Shared Preferences data.

class PreferencesProvider extends ChangeNotifier {
  String? theme =  SettingsSharedPreferences.getThemeString();
....
}

Below is the Shared Preference code where we get the value of theme from:

class SettingsSharedPreferences {
  static const _keytheme = "theme";
  static String _defaultTheme = "System";

  static setTheme(String theme) async {
    await sharedPreferences.setString(_keytheme, theme);
  }

  static Future<String?> getTheme() async {
    final sharedPreferences = await SharedPreferences.getInstance();
    if (sharedPreferences.getString(_keytheme) == null) {
      await setTheme(_defaultTheme);
    }
    return sharedPreferences.getString(_keytheme);
  }

  static String? getThemeString() {
    print("getThemeString");
    String? theme;
    getTheme().then((val) {
      theme = val;
    });
    return theme;
  }
}
like image 544
J0nathan Lam Avatar asked Oct 17 '25 19:10

J0nathan Lam


1 Answers

I suggest loading the preferences before the app is built and shown to the user:

Future<void> main() async {
  ...
  final preferences = await SharedPreferences.getInstance();

  runApp(MainApp(
    preferences: preferences,
  ));
}

In your case, you could pass the theme value to MyApp widget.

like image 158
Andrey Gordeev Avatar answered Oct 20 '25 10:10

Andrey Gordeev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!