Home > Blockchain >  How to set ThemeMode in splash screen using value stored in sqflite FLUTTER
How to set ThemeMode in splash screen using value stored in sqflite FLUTTER

Time:01-20

I have a Flutter Application where an sqflite database stored the user preference of ThemeMode (viz Dark, Light and System). I have created a splash screen using flutter_native_splash which supports dark mode too.
The Problem is this that I want the splash screen to follow the users stored value for theme mode. Currently, the code I am using is as follows:

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

  static ValueNotifier<ThemeMode> themeNotifier = ValueNotifier(ThemeMode.system);

  @override
  State<MyRoot> createState() => _MyRootState();
}


class _MyRootState extends State<MyRoot> {
  DatabaseHelper? databaseHelper = DatabaseHelper.dhInstance;
  ThemeMode? tmSaved;

  @override
  void initState() {
    Future.delayed(Duration.zero, () async => await loadData());
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    //to prevent auto rotation of the app
    SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
    return ValueListenableBuilder<ThemeMode>(
      valueListenable: MyRoot.themeNotifier,
      builder: (_, ThemeMode currentMode, __) {
        return Sizer(
          builder: (context, orientation, deviceType) {
            return MaterialApp(
              title: 'My Application',
              theme: themeLight, //dart file for theme
              darkTheme: themeDark, //dart file for theme
              themeMode: tmSaved ?? currentMode,
              initialRoute: // my initial root
              routes: {
                // my routes
                .
                .
                .
                // my routes
              },
            );
          },
        );
      },
    );
  }

  Future<void> loadData() async {
    if (databaseHelper != null) {
      ThemeMode? themeMode= await databaseHelper?.selectStoredTheme(); // function retrieving sqflite stored value and returning ThemeMode value
      if (themeMode != null) {
         MyRoot.themeNotifier.value = themeMode;
         return;
      }
    }
    MyRoot.themeNotifier.value = ThemeMode.system;
  }
}

Currently, this shows a light theme splash screen loading, then converts it into dark with a visible flicker.
ValueListenableBuilder<ThemeMode>(... is to enable real time theme change from settings page in my app which working as intended (taken from A Goodman's article: "Flutter: 2 Ways to Make a Dark/Light Mode Toggle".

main.dart has the below code:

void main() {
  runApp(MyRoot());
}

CodePudding user response:

Have you tried loading the setting from sqflite in main() before runApp? If you can manage to do so, you should be able to pass the setting as argument to MyRoot and then the widgets would be loaded from the start with the correct theme. I'm speaking in theory, I can't test what I'm suggesting right now.

Something like:

void main() async {
  ThemeMode? themeMode= await databaseHelper?.selectStoredTheme(); // function retrieving sqflite stored value and returning ThemeMode value
  runApp(MyRoot(themeMode));
}

[...]

class MyRoot extends StatefulWidget {
  ThemeMode? themeMode;

  const MyRoot(this.themeMode, {Key? key}) : super(key: key);

  static ValueNotifier<ThemeMode> themeNotifier = ValueNotifier(ThemeMode.system);

  @override
  State<MyRoot> createState() => _MyRootState();
}

EDIT

Regarding the nullable value you mentioned in comments, you can change the main like this:

void main() async {
  ThemeMode? themeMode= await databaseHelper?.selectStoredTheme(); // function retrieving sqflite stored value and returning ThemeMode value
  themeMode ??= ThemeMode.system;
  runApp(MyRoot(themeMode!));
}

which makes themeMode non-nullable, and so you can change MyRoot in this way:

class MyRoot extends StatefulWidget {
  ThemeMode themeMode;

  const MyRoot(required this.themeMode, {Key? key}) : super(key: key);

  [...]
}

Regarding the functionality of ValueNotifier, I simply thought of widget.themeMode as the initial value of your tmSaved property in your state, not as a value to be reused in the state logic. Something like this:

class _MyRootState extends State<MyRoot> {
  DatabaseHelper? databaseHelper = DatabaseHelper.dhInstance;
  late ThemeMode tmSaved;

  @override
  void initState() {
    tmSaved = widget.themeMode;
    super.initState();
  }
  [...]
}

so that your widgets would already have the saved value at the first build.

PS the code in this edit, as well as in the original part, isn't meant to be working by simply pasting it. Some things might need adjustments, like adding final to themeMode in MyRoot.

CodePudding user response:

Make your splashscreen. A main widget which get data from sqlflite And make splashscreen widget go to the your home widget with remove it using navigation pop-up

  •  Tags:  
  • Related