Skip to content

Instantly share code, notes, and snippets.

@exavolt
Last active September 29, 2020 18:36
Show Gist options
  • Save exavolt/c27d8791d8a7c025358fc5ff0fe4663b to your computer and use it in GitHub Desktop.
Save exavolt/c27d8791d8a7c025358fc5ff0fe4663b to your computer and use it in GitHub Desktop.
Switch theme mode (system, light, dark) dynamically
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
// Wrap your application instance with this class.
//
// class MyApp extends StatelessWidget {
// // This widget is the root of your application.
// @override
// Widget build(BuildContext context) {
// return ThemeModeApp((BuildContext context, ThemeMode themeMode) {
// return MaterialApp(
// title: 'MyApp',
// theme: ThemeData.light(),
// darkTheme: ThemeData.dark(),
// home: HomeView(),
// themeMode: themeMode,
// );
// },
// }
// }
//
// And then somewhere in your app (e.g., settings view):
//
// ThemeModeApp.of(context).themeMode = ThemeMode.dark; // or ThemeMode.light or ThemeMode.system
//
// This is similar to dynamic_theme package but this focuses only on the theme mode.
class ThemeModeApp extends StatefulWidget {
final Function(BuildContext context, ThemeMode themeMode) appBuilder;
final String preferencesKeyPrefix;
ThemeModeApp(this.appBuilder, {this.preferencesKeyPrefix});
static _ThemeModeAppState of(BuildContext context, {bool root = false}) =>
root
? context.findRootAncestorStateOfType<_ThemeModeAppState>()
: context.findAncestorStateOfType<_ThemeModeAppState>();
@override
_ThemeModeAppState createState() => _ThemeModeAppState();
}
class _ThemeModeAppState extends State<ThemeModeApp> {
_ThemeModePreferences _preferences;
@override
Widget build(BuildContext context) {
return widget.appBuilder(context, _preferences.themeMode);
}
@override
void initState() {
super.initState();
_preferences = _ThemeModePreferences(widget.preferencesKeyPrefix);
_preferences.addListener(_onPreferencesUpdate);
_preferences.loadState();
}
@override
void dispose() {
_preferences.removeListener(_onPreferencesUpdate);
super.dispose();
}
set themeMode(ThemeMode mode) {
_preferences.themeMode = mode;
}
ThemeMode get themeMode => _preferences.themeMode;
void _onPreferencesUpdate() {
setState(() {});
}
}
// Do NOT use this in a Provider
class _ThemeModePreferences extends ChangeNotifier {
final String preferencesKeyPrefix;
_ThemeModePreferences(this.preferencesKeyPrefix);
bool _stateLoaded = false;
ThemeMode _themeMode = ThemeMode.system;
ThemeMode get themeMode => _themeMode;
set themeMode(ThemeMode value) {
_storeThemeMode(value);
}
void _storeThemeMode(ThemeMode value) async {
if (_themeMode == value) {
return;
}
SharedPreferences prefs = await SharedPreferences.getInstance();
_themeMode = value;
await prefs.setInt(
_preferenceKey(_themeModePreferenceFieldName), _themeMode.index);
notifyListeners();
}
Future loadState() async {
if (_stateLoaded) {
return;
}
_stateLoaded = true;
SharedPreferences prefs = await SharedPreferences.getInstance();
final themeModeIndex =
prefs.getInt(_preferenceKey(_themeModePreferenceFieldName));
if (themeModeIndex != null) {
final themeMode = ThemeMode.values[themeModeIndex];
if (_themeMode != themeMode) {
_themeMode = themeMode;
notifyListeners();
}
}
}
static const _themeModePreferenceFieldName = 'themeMode';
String _preferenceKey(String fieldName) {
if (preferencesKeyPrefix?.isNotEmpty == true) {
if (preferencesKeyPrefix.endsWith('.')) {
return preferencesKeyPrefix + fieldName;
}
return preferencesKeyPrefix + '.' + fieldName;
}
if (preferencesKeyPrefix == null) {
return 'app.' + fieldName;
}
return fieldName;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment