MaterialApp
嘅theme
同darkTheme
themeMode
static ThemeData get lightTheme => FlexThemeData.light(
colorScheme: const ColorScheme(
brightness: Brightness.light,
primary: Color(0xffc62828),
onPrimary: Color(0xfffeeeee),
...
inverseSurface: Color(0xff3d2e2d),
onInverseSurface: Color(0xfffbeeec),
inversePrimary: Color(0xffffb3aa),
shadow: Color(0xff000000),
),
scaffoldBackground: const Color(0xfff9f9f9),
surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold,
blendLevel: 15,
appBarStyle: FlexAppBarStyle.background,
tooltipsMatchBackground: true,
tabBarStyle: FlexTabBarStyle.forBackground,
visualDensity: FlexColorScheme.comfortablePlatformDensity,
tones: FlexTones.vividSurfaces(Brightness.light),
useMaterial3: true,
fontFamily: GoogleFonts.roboto().fontFamily, // set google fonts
);
child: MaterialApp(
title: 'Pokepedia',
debugShowCheckedModeBanner: false,
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: currentThemeMode,
...
),
themeData
有多啲控制 可以用 ThemeExtension
去define你自己嘅 Color
或者 TextTheme
Color
light mode 時係黑色, dark mode 時係白色theme
度用 copyWith
加入你嘅 ThemeExtension
MaterialApp(
theme: AppTheme.lightTheme.copyWith(
extensions: <ThemeExtension<dynamic>>[
CustomColors.light,
],
),
darkTheme: AppTheme.darkTheme.copyWith(
extensions: <ThemeExtension<dynamic>>[
CustomColors.dark,
],
),
Theme.of(context).extension<YourThemeExtexsion>()!
去用你define 嘅ThemeExtension
final customColors = Theme.of(context).extension<CustomColors>()!;
Theme.of(context)
extension BuildContextX on BuildContext {
ThemeData get theme => Theme.of(this);
TextTheme get textTheme => theme.textTheme;
TextTheme get primaryTextTheme => theme.primaryTextTheme;
ColorScheme get colorScheme => theme.colorScheme;
CustomColors get customColors => theme.extension<CustomColors>()!;
}
Container(
color: context.customColors.inverseTheme,
),
SharedPreferences
係1個key value databaseSharedPreferences
instancefinal sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.setString('themeMode', 'light');
final String? themeMode = sharedPreferences.getString('themeMode');
SharedPreferences
read data 唔係 asynchronousThemeMode
abstract class ISettingsRepository {
Future<void> saveThemeMode(ThemeMode themeMode);
ThemeMode loadThemeMode();
}
class SettingsRepository implements ISettingsRepository {
SettingsRepository({required SharedPreferences sharedPreferences})
: _sharedPreferences = sharedPreferences;
final SharedPreferences _sharedPreferences;
@override
Future<void> saveThemeMode(ThemeMode themeMode) {
String stringToSave;
switch (themeMode) {
case ThemeMode.light:
stringToSave = 'light';
break;
...
}
await _sharedPreferences.setString('themeMode', stringToSave);
}
@override
ThemeMode loadThemeMode() {
ThemeMode result;
final themeMode = _sharedPreferences.getString('themeMode');
switch (themeMode) {
case 'light':
result = ThemeMode.light;
break;
...
default:
result = ThemeMode.system;
break;
}
return result;
}
}
StateNotifier
去manage ThemeMode
class ThemeModeStateNotifier extends StateNotifier<ThemeMode> {
ThemeModeStateNotifier({required ISettingsRepository repository}) : _repository = repository,
super(ThemeMode.system);
final ISettingsRepository _repository;
Future<void> setThemeMode(ThemeMode themeMode) async {
state = themeMode;
await _repository.saveThemeMode(themeMode);
}
void loadThemeMode() {
state = _repository.loadThemeMode();
}
}
themeModeStateNotifierProvider
嘅時候 會load埋 ThemeMode
final themeModeStateNotifierProvider = StateNotifierProvider<ThemeModeStateNotifier, ThemeMode>((ref) {
return ThemeModeStateNotifier(
repository: ref.watch(settingsRepositoryProvider),
)..loadThemeMode();
});
final settingsRepositoryProvider = Provider<ISettingsRepository>(
(ref) => SettingsRepository(sharedPreferences: ref.watch(sharedPreferencesProvider)),
);
SharedPreferences.getInstance()
係 asynchronousFutureProvider
咁就會return AsyncValue<SharedPreferences>
AsyncValue
嘅時候會好麻煩FutureProvider
runApp()
之前 call SharedPreferences.getInstance()
然後再override Provider
final sharedPreferencesProvider =
Provider<SharedPreferences>((_) => throw Exception('Shared Preferences not initialized'));
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final sharedPreferences = await SharedPreferences.getInstance();
...
runApp(
ProviderScope(
overrides: [
sharedPreferencesProvider.overrideWithValue(sharedPreferences),
],
child: const PokepediaApp(),
),
);
}
MaterialApp
assign ThemeMode
ref.read(themeModeStateNotifierProvider.notifier).setThemeMode()
ThemeMode
final currentThemeMode = ref.watch(themeModeStateNotifierProvider);
MaterialApp(
...
themeMode: currentThemeMode,
...
),
// ui
onPressed: (BuildContext context) {
ref.read(themeModeStateNotifierProvider.notifier).setThemeMode(ThemeMode.light);
},
AnimatedContainer
唔workContainer