I'm trying to implement a feature whose job is to switch beetween light and dark mode using BLoC and SharedPreferences. Through debug prints I know that the DarkModeCubit is working properly. However the MainApp doesn't receive the new state immediately but only after hot restart. I don't know why.
Here is my Main App
void main() async {
WidgetsFlutterBinding.ensureInitialized(); // essential
await Firebase
.initializeApp(); // needed for Firebase, included Authentication and Firestore
//
// Initialization of all blocs used by most pages
//
runApp(
MultiBlocProvider(
providers: [
BlocProvider(create: ((context) => AuthenticationBloc())),
BlocProvider(create: ((context) => RefreshUserBloc())),
BlocProvider(create: ((context) => GetCurrentUserDocCubit())),
BlocProvider(create: ((context) => DarkModeCubit(PrefsState())))
],
child: MainApp(),
),
);
}
//
// Class of the Material App, the top of the widget tree
//
class MainApp extends StatefulWidget {
const MainApp({super.key});
@override
State<MainApp> createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
final AppRouter _appRouter = AppRouter();
@override
void initState() {
super.initState();
//
// When the app starts we check if the user is already logged in. If so, we go to the home page, otherwise we go to the login page
//
WidgetsBinding.instance.addPostFrameCallback((_) {
BlocProvider.of<AuthenticationBloc>(context).add(AuthenticationStarted());
});
}
@override
Widget build(BuildContext context) {
//
// Build method of the Material App
//
return BlocBuilder<DarkModeCubit, ThemeMode>(
builder: (context, themeMode) {
debugPrint('MainApp: $themeMode');
return MaterialApp(
debugShowCheckedModeBanner: false,
//
// Theme of the app, with the colorScheme and the textTheme
//
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: themeMode,
//
// onGenerateRoute is the chosen routing system. It is defined in the app_router.dart file.
// When a route is called via Navigator.of(context).pushNamed('/routeName'), the onGenerateRoute method is called,
// and it returns the page associated with the routeName.
//
onGenerateRoute: _appRouter.onGenerateRoute,
//
// The initial route is the first route that is shown when the app starts.
// It is set to a BlocBuilder that listens to the AuthenticationBloc, and it redirects to the login page if the user is not logged in,
// otherwise it redirects to the home page.
//
initialRoute: '/',
);
},
);
}
}
Here is the Cubit
class DarkModeCubit extends Cubit<ThemeMode> {
final PrefsState prefs;
DarkModeCubit(this.prefs) : super(ThemeMode.light) {
_loadTheme();
}
///
/// Method that loads the current {isDarkTheme}
///
void _loadTheme() async {
final isDarkTheme = await prefs.getThemePreference();
emit(isDarkTheme ? ThemeMode.dark : ThemeMode.light);
}
///
/// Method that changes the {isDarkTheme}
///
void toggleTheme({required bool isDarkTheme}) async {
await prefs.setThemePreference(isDarkTheme);
emit(isDarkTheme ? ThemeMode.dark : ThemeMode.light);
debugPrint('DarkModeCubit: $state');
}
}
Here is my PrefsState
class PrefsState {
/// Key that stores the location of the dark theme.
static const _isDarkThemeKey = 'isDarkTheme';
/// Method that retrieves the bool that indicates whether the theme is dark or light.
Future<bool> getThemePreference() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool(_isDarkThemeKey) ?? false;
}
/// Method that set the {isDarkTheme} property in the local storage.
Future<void> setThemePreference(bool isDarkTheme) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_isDarkThemeKey, isDarkTheme);
}
}
After reading your code it seems that your problem is with how you create the bloc providers in the widget tree:
That parenthesis wrapping your
createmake it seems that there is a function within a function, remove it from all your providers so they initialize correctly.