I'm working with Flutter Bloc for state management. I have a ThemeBloc that toggles between light and dark modes, and I want to trigger AppBloc to perform an action whenever the theme changes. However, changes in ThemeBloc do not reflect in AppBloc.
theme_bloc.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
part 'theme_event.dart';
part 'theme_state.dart';
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
ThemeMode _themeMode = ThemeMode.system;
ThemeBloc() : super(ThemeStateInitial(themeMode: ThemeMode.system)) {
on<ThemeEventToggle>((event, emit) {
_themeMode = _themeMode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
emit(ThemeStateChanged(themeMode: _themeMode));
});
}
}
theme_event.dart
part of 'theme_bloc.dart';
sealed class ThemeEvent extends Equatable {
const ThemeEvent();
@override
List<Object?> get props => [];
}
class ThemeEventToggle extends ThemeEvent {
const ThemeEventToggle();
}
theme_state.dart
part of 'theme_bloc.dart';
sealed class ThemeState extends Equatable {
final ThemeMode themeMode;
const ThemeState({required this.themeMode});
@override
List<Object> get props => [themeMode];
}
class ThemeStateInitial extends ThemeState {
const ThemeStateInitial({required super.themeMode});
}
class ThemeStateChanged extends ThemeState {
const ThemeStateChanged({required super.themeMode});
}
app_bloc.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
part 'app_event.dart';
part 'app_state.dart';
class AppBloc extends Bloc<AppEvent, AppState> {
AppBloc() : super(AppStateInitial()) {
on<AppEventReload>((event, emit) {
emit(AppStateLoaded());
});
}
}
main.dart
void main() {
runApp(
MultiBlocProvider(
providers: [
BlocProvider(create: (context) => ThemeBloc()),
BlocProvider(create: (context) => AppBloc()),
],
child: MyApp(),
),
);
}
.
ThemeBloc → Handles light/dark theme switching. AppBloc → Manages general app state like user data and settings.
When ThemeBloc toggles the theme, AppBloc doesn’t react.
Theme change only affects the current page, other pages stay on the old theme.
When ThemeBloc is triggered, the theme only changes on this page.
class SettingsPage extends StatefulWidget {
SettingsPage({super.key});
@override
State<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> {
@override
Widget build(BuildContext context) {
return BlocBuilder<AppBloc, AppState>(
builder: (context, state) {
final isDarkMode = (context.read<ThemeBloc>().state is ThemeStateChanged)
? (context.read<ThemeBloc>().state as ThemeStateChanged).themeMode ==
ThemeMode.dark : false;
return _buildToggleTile(
Icons.dark_mode,
'Karanlık Mod',
isDarkMode,
() {
context.read<ThemeBloc>().add(ThemeEventToggle());
},
);
},
);
}
If your app’s other pages aren’t updating, ensure that you’ve wrapped your app’s root widget with BlocBuilder, as shown below. This will automatically update your Material widget, thereby changing the theme for all screens.
Try taking reference from the below code :
class _SettingsPageState extends State<SettingsPage> {
@override
Widget build(BuildContext context) {
return BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, themeState) {
final isDarkMode = themeState.themeMode == ThemeMode.dark;
return _buildToggleTile(
Icons.dark_mode,
'Karanlık Mod',
isDarkMode,
() {
context.read<ThemeBloc>().add(const ThemeEventToggle());
},
);
},
);
}
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, themeState) {
return MaterialApp(
title: 'Your App',
theme: ThemeData.light(), // Your light theme
darkTheme: ThemeData.dark(), // Your dark theme
themeMode: themeState.themeMode,
home: HomePage(),
// Other MaterialApp properties
);
},
);
}
}