import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; class ThemeBuilder extends StatefulWidget { final Widget Function( BuildContext context, ThemeMode themeMode, Color? primaryColor, ) builder; final String themeModeSettingsKey; final String primaryColorSettingsKey; const ThemeBuilder({ required this.builder, this.themeModeSettingsKey = 'theme_mode', this.primaryColorSettingsKey = 'primary_color', Key? key, }) : super(key: key); @override State createState() => ThemeController(); } class ThemeController extends State { SharedPreferences? _sharedPreferences; ThemeMode? _themeMode; Color? _primaryColor; ThemeMode get themeMode => _themeMode ?? ThemeMode.system; Color? get primaryColor => _primaryColor; static ThemeController of(BuildContext context) => Provider.of( context, listen: false, ); void _loadData(_) async { final preferences = _sharedPreferences ??= await SharedPreferences.getInstance(); final rawThemeMode = preferences.getString(widget.themeModeSettingsKey); final rawColor = preferences.getInt(widget.primaryColorSettingsKey); setState(() { _themeMode = ThemeMode.values .singleWhereOrNull((value) => value.name == rawThemeMode); _primaryColor = rawColor == null ? null : Color(rawColor); }); } Future setThemeMode(ThemeMode newThemeMode) async { final preferences = _sharedPreferences ??= await SharedPreferences.getInstance(); await preferences.setString(widget.themeModeSettingsKey, newThemeMode.name); setState(() { _themeMode = newThemeMode; }); } Future setPrimaryColor(Color? newPrimaryColor) async { final preferences = _sharedPreferences ??= await SharedPreferences.getInstance(); if (newPrimaryColor == null) { await preferences.remove(widget.primaryColorSettingsKey); } else { await preferences.setInt( widget.primaryColorSettingsKey, newPrimaryColor.value, ); } setState(() { _primaryColor = newPrimaryColor; }); } @override void initState() { WidgetsBinding.instance.addPostFrameCallback(_loadData); super.initState(); } @override Widget build(BuildContext context) { return Provider( create: (_) => this, child: DynamicColorBuilder( builder: (light, _) => widget.builder( context, themeMode, primaryColor ?? light?.primary, ), ), ); } }