😋 初始化仓库
This commit is contained in:
390
lib/providers/theme_provider.dart
Normal file
390
lib/providers/theme_provider.dart
Normal file
@@ -0,0 +1,390 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// Color scheme options for the app
|
||||
enum AppColorScheme { blue, green, purple, orange }
|
||||
|
||||
/// Provider for managing app theme and appearance settings
|
||||
///
|
||||
/// Handles theme mode (light/dark/system), color scheme selection,
|
||||
/// and persistence of user preferences
|
||||
///
|
||||
/// Usage example:
|
||||
/// ```dart
|
||||
/// final themeProvider = Provider.of<ThemeProvider>(context);
|
||||
///
|
||||
/// // Change theme mode
|
||||
/// themeProvider.setThemeMode(ThemeMode.dark);
|
||||
///
|
||||
/// // Change color scheme
|
||||
/// themeProvider.setColorScheme(AppColorScheme.green);
|
||||
///
|
||||
/// // Get current theme data
|
||||
/// final lightTheme = themeProvider.lightTheme;
|
||||
/// final darkTheme = themeProvider.darkTheme;
|
||||
/// ```
|
||||
class ThemeProvider extends ChangeNotifier {
|
||||
static const String _themeModeKey = 'theme_mode';
|
||||
static const String _colorSchemeKey = 'color_scheme';
|
||||
|
||||
ThemeMode _themeMode = ThemeMode.system;
|
||||
AppColorScheme _colorScheme = AppColorScheme.blue;
|
||||
|
||||
ThemeProvider() {
|
||||
_loadPreferences();
|
||||
}
|
||||
|
||||
/// Get current theme mode
|
||||
ThemeMode get themeMode => _themeMode;
|
||||
|
||||
/// Get current color scheme
|
||||
AppColorScheme get colorScheme => _colorScheme;
|
||||
|
||||
/// Get light theme data
|
||||
ThemeData get lightTheme => _buildLightTheme();
|
||||
|
||||
/// Get dark theme data
|
||||
ThemeData get darkTheme => _buildDarkTheme();
|
||||
|
||||
/// Set theme mode
|
||||
///
|
||||
/// [mode] - The theme mode to set (light, dark, or system)
|
||||
/// Saves preference and notifies listeners
|
||||
Future<void> setThemeMode(ThemeMode mode) async {
|
||||
if (_themeMode == mode) return;
|
||||
|
||||
_themeMode = mode;
|
||||
notifyListeners();
|
||||
await savePreferences();
|
||||
}
|
||||
|
||||
/// Set color scheme
|
||||
///
|
||||
/// [scheme] - The color scheme to set
|
||||
/// Saves preference and notifies listeners
|
||||
Future<void> setColorScheme(AppColorScheme scheme) async {
|
||||
if (_colorScheme == scheme) return;
|
||||
|
||||
_colorScheme = scheme;
|
||||
notifyListeners();
|
||||
await savePreferences();
|
||||
}
|
||||
|
||||
/// Save preferences to local storage
|
||||
Future<void> savePreferences() async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_themeModeKey, _themeMode.name);
|
||||
await prefs.setString(_colorSchemeKey, _colorScheme.name);
|
||||
} catch (e) {
|
||||
debugPrint('Failed to save theme preferences: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Load preferences from local storage
|
||||
Future<void> _loadPreferences() async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
// Load theme mode
|
||||
final themeModeStr = prefs.getString(_themeModeKey);
|
||||
if (themeModeStr != null) {
|
||||
_themeMode = ThemeMode.values.firstWhere(
|
||||
(mode) => mode.name == themeModeStr,
|
||||
orElse: () => ThemeMode.system,
|
||||
);
|
||||
}
|
||||
|
||||
// Load color scheme
|
||||
final colorSchemeStr = prefs.getString(_colorSchemeKey);
|
||||
if (colorSchemeStr != null) {
|
||||
_colorScheme = AppColorScheme.values.firstWhere(
|
||||
(scheme) => scheme.name == colorSchemeStr,
|
||||
orElse: () => AppColorScheme.blue,
|
||||
);
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
debugPrint('Failed to load theme preferences: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Build light theme based on current color scheme
|
||||
ThemeData _buildLightTheme() {
|
||||
final colorScheme = _getColorScheme(Brightness.light);
|
||||
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.light,
|
||||
colorScheme: colorScheme,
|
||||
|
||||
// AppBar theme
|
||||
appBarTheme: AppBarTheme(
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
backgroundColor: colorScheme.primary,
|
||||
foregroundColor: colorScheme.onPrimary,
|
||||
),
|
||||
|
||||
// Card theme
|
||||
cardTheme: const CardThemeData(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
|
||||
// Input decoration theme
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: colorScheme.surfaceContainerHighest.withValues(alpha: 0.3),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: colorScheme.primary, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: colorScheme.error, width: 1),
|
||||
),
|
||||
focusedErrorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: colorScheme.error, width: 2),
|
||||
),
|
||||
),
|
||||
|
||||
// Elevated button theme
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 2,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Text button theme
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
),
|
||||
),
|
||||
|
||||
// Floating action button theme
|
||||
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
),
|
||||
|
||||
// Progress indicator theme
|
||||
progressIndicatorTheme: ProgressIndicatorThemeData(
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
|
||||
// Divider theme
|
||||
dividerTheme: DividerThemeData(
|
||||
color: colorScheme.outlineVariant,
|
||||
thickness: 1,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Build dark theme based on current color scheme
|
||||
ThemeData _buildDarkTheme() {
|
||||
final colorScheme = _getColorScheme(Brightness.dark);
|
||||
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.dark,
|
||||
colorScheme: colorScheme,
|
||||
|
||||
// AppBar theme
|
||||
appBarTheme: AppBarTheme(
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
backgroundColor: colorScheme.surface,
|
||||
foregroundColor: colorScheme.onSurface,
|
||||
),
|
||||
|
||||
// Card theme
|
||||
cardTheme: const CardThemeData(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
|
||||
// Input decoration theme
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: colorScheme.surfaceContainerHighest.withValues(alpha: 0.3),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: colorScheme.primary, width: 2),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: colorScheme.error, width: 1),
|
||||
),
|
||||
focusedErrorBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: colorScheme.error, width: 2),
|
||||
),
|
||||
),
|
||||
|
||||
// Elevated button theme
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
elevation: 2,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Text button theme
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
),
|
||||
),
|
||||
|
||||
// Floating action button theme
|
||||
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||||
elevation: 4,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
),
|
||||
|
||||
// Progress indicator theme
|
||||
progressIndicatorTheme: ProgressIndicatorThemeData(
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
|
||||
// Divider theme
|
||||
dividerTheme: DividerThemeData(
|
||||
color: colorScheme.outlineVariant,
|
||||
thickness: 1,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Get color scheme based on brightness and selected color
|
||||
ColorScheme _getColorScheme(Brightness brightness) {
|
||||
switch (_colorScheme) {
|
||||
case AppColorScheme.blue:
|
||||
return _getBlueColorScheme(brightness);
|
||||
case AppColorScheme.green:
|
||||
return _getGreenColorScheme(brightness);
|
||||
case AppColorScheme.purple:
|
||||
return _getPurpleColorScheme(brightness);
|
||||
case AppColorScheme.orange:
|
||||
return _getOrangeColorScheme(brightness);
|
||||
}
|
||||
}
|
||||
|
||||
/// Blue color scheme
|
||||
ColorScheme _getBlueColorScheme(Brightness brightness) {
|
||||
if (brightness == Brightness.light) {
|
||||
return ColorScheme.fromSeed(
|
||||
seedColor: Colors.blue,
|
||||
brightness: Brightness.light,
|
||||
);
|
||||
} else {
|
||||
return ColorScheme.fromSeed(
|
||||
seedColor: Colors.blue,
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Green color scheme
|
||||
ColorScheme _getGreenColorScheme(Brightness brightness) {
|
||||
if (brightness == Brightness.light) {
|
||||
return ColorScheme.fromSeed(
|
||||
seedColor: Colors.green,
|
||||
brightness: Brightness.light,
|
||||
);
|
||||
} else {
|
||||
return ColorScheme.fromSeed(
|
||||
seedColor: Colors.green,
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Purple color scheme
|
||||
ColorScheme _getPurpleColorScheme(Brightness brightness) {
|
||||
if (brightness == Brightness.light) {
|
||||
return ColorScheme.fromSeed(
|
||||
seedColor: Colors.purple,
|
||||
brightness: Brightness.light,
|
||||
);
|
||||
} else {
|
||||
return ColorScheme.fromSeed(
|
||||
seedColor: Colors.purple,
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Orange color scheme
|
||||
ColorScheme _getOrangeColorScheme(Brightness brightness) {
|
||||
if (brightness == Brightness.light) {
|
||||
return ColorScheme.fromSeed(
|
||||
seedColor: Colors.orange,
|
||||
brightness: Brightness.light,
|
||||
);
|
||||
} else {
|
||||
return ColorScheme.fromSeed(
|
||||
seedColor: Colors.orange,
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get color scheme name for display
|
||||
String getColorSchemeName(AppColorScheme scheme) {
|
||||
switch (scheme) {
|
||||
case AppColorScheme.blue:
|
||||
return '蓝色';
|
||||
case AppColorScheme.green:
|
||||
return '绿色';
|
||||
case AppColorScheme.purple:
|
||||
return '紫色';
|
||||
case AppColorScheme.orange:
|
||||
return '橙色';
|
||||
}
|
||||
}
|
||||
|
||||
/// Get theme mode name for display
|
||||
String getThemeModeName(ThemeMode mode) {
|
||||
switch (mode) {
|
||||
case ThemeMode.light:
|
||||
return '浅色模式';
|
||||
case ThemeMode.dark:
|
||||
return '深色模式';
|
||||
case ThemeMode.system:
|
||||
return '跟随系统';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user