Search code examples
flutterdart-async

Use shared_preferences to get theme at startup


How do I set the theme of my app based on what's stored in shared_preferences if all calls to shared_preferences are async?

For example, I have a ThemeService which looks up the set theme from shared_preferences and returns it, this works for things like toggling it in the UI, but how do I load this at startup?

class ThemeService {

  static String key = "isDark";

  /// Return the ThemeData based on what is persisted.
  Future<ThemeData> getTheme() async {
    final prefs = await SharedPreferences.getInstance();

    final isDarkMode = prefs.getBool(key) ?? false;

    if (isDarkMode) {
      return ThemeDark().theme;
    } else {
      return ThemeLight().theme;
    }
  }

  /// Toggle the theme between light/dark and persist the chosen value.
  Future<void> toggleTheme() async {
    final prefs = await SharedPreferences.getInstance();

    final isDarkMode = prefs.getBool(key) ?? false;

    if (isDarkMode) {
      Get.changeTheme(ThemeLight().theme);
      await prefs.setBool(key, false);
    } else {
      Get.changeTheme(ThemeDark().theme);
      await prefs.setBool(key, true);
    }
  }
}

And I want to be able to use it as such:

class App extends StatelessWidget {

  final ThemeService themeService = Get.find<ThemeService>();

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
        debugShowCheckedModeBanner: false,
        initialBinding: InitialBinding(),
        initialRoute: initialRoute(),
        theme: themeService.getTheme(), // Its a future, so can't do this...
        getPages: AppPages.routes);
  }
}

New to flutter so have I just missed a concept or a pattern here? Is there some way I should be accessing the preferences as to not need async/await?


Solution

  • As suggested in the comments, the solution is to wrap the GetMaterialApp in a FutureBuilder

      @override
      Widget build(BuildContext context) {
        return FutureBuilder<ThemeData>(
            future: ThemeService().getTheme(),
            builder: (BuildContext context, AsyncSnapshot<ThemeData> snapshot) {
              return GetMaterialApp(
                  debugShowCheckedModeBanner: false,
                  initialBinding: InitialBinding(),
                  initialRoute: initialRoute(),
                  theme: snapshot.data,
                  darkTheme: darkTheme,
                  getPages: AppPages.routes);
            });
      }