after various attempts I did it with the BLoC pattern, I don't know if it is a good method but it seems to work with no problems:
App theme models:
class MyTheme {
Brightness brightness;
Color backgroundColor;
Color scaffoldBackgroundColor;
Color primaryColor;
Brightness primaryColorBrightness;
Color accentColor;
MyTheme({
this.brightness,
this.backgroundColor,
this.scaffoldBackgroundColor,
this.primaryColor,
this.primaryColorBrightness,
this.accentColor
});
}
class AppTheme {
String name;
MyTheme theme;
AppTheme(this.name, this.theme);
}
List<AppTheme> myThemes = [
AppTheme(
'Default',
MyTheme(
brightness: Brightness.light,
backgroundColor: Colors.blue[50],
scaffoldBackgroundColor: Colors.blue[50],
primaryColor: Colors.blue,
primaryColorBrightness: Brightness.dark,
accentColor: Colors.blue[50],
)),
AppTheme(
'Teal',
MyTheme(
brightness: Brightness.light,
backgroundColor: Colors.teal[50],
scaffoldBackgroundColor: Colors.teal[50],
primaryColor: Colors.teal[600],
primaryColorBrightness: Brightness.dark,
accentColor: Colors.teal[50],
),
),
];
App BLoC class. Here I used a BehaviorSubject of RxDart.
class AppBloc {
final _theme = BehaviorSubject<AppTheme>();
Function(AppTheme) get inTheme => _theme.sink.add;
Stream<AppTheme> get outTheme => _theme.stream;
AppBloc() {
print('-------APP BLOC INIT--------');
// Send to stream the initial theme
inTheme(myThemes[0]);
}
dispose() {
print('---------APP BLOC DISPOSE-----------');
_theme.close();
}
}
In the settings page of the app I use the _theme stream to set the current theme of a dropdown menu with the themes list. With the onChanged handler, when a user clicks on the theme it is sent to stream:
StreamBuilder(
stream: widget.bloc.outTheme,
builder: (context, AsyncSnapshot<AppTheme> snapshot) {
return snapshot.hasData
? DropdownButton<AppTheme>(
hint: Text("Status"),
value: snapshot.data,
items: myThemes.map((AppTheme appTheme) {
return DropdownMenuItem<AppTheme>(
value: appTheme,
child: Text(appTheme.name),
);
}).toList(),
onChanged: widget.bloc.inTheme,
)
: Container();
}),
And finally in the homepage, with a StreamBuilder I use the _theme stream to set the selected ThemeData:
StreamBuilder(
stream: _bloc.outTheme,
builder: (context, AsyncSnapshot<AppTheme> snapshot) {
return MaterialApp(
theme: snapshot.hasData ? _buildThemeData(snapshot.data) : ThemeData(),
home: HomePage());
}),
_BuildThemeData method to get the ThemeData from the theme model:
_buildThemeData(AppTheme appTheme) {
return ThemeData(
brightness: appTheme.theme.brightness,
backgroundColor: appTheme.theme.backgroundColor,
scaffoldBackgroundColor: appTheme.theme.scaffoldBackgroundColor,
primaryColor: appTheme.theme.primaryColor,
primaryColorBrightness: appTheme.theme.primaryColorBrightness,
accentColor: appTheme.theme.accentColor
);
}
I hope this is useful to you.