深色模式、首页设置页面和功能优化

This commit is contained in:
Developer
2026-04-02 07:06:55 +08:00
parent f0a62ed68b
commit 954d173329
88 changed files with 12157 additions and 7578 deletions

View File

@@ -0,0 +1,240 @@
// 时间: 2026-04-02
// 功能: 主题控制器 - 管理深色模式和主题设置
// 介绍: 使用 GetX 管理主题状态,支持状态持久化到 SharedPreferences
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../models/night-mode/theme_model.dart';
/// 主题控制器
/// 管理应用的主题模式、深色模式状态,并持久化到 SharedPreferences
class ThemeController extends GetxController {
// SharedPreferences 实例
SharedPreferences? _prefs;
// 存储键名
static const String _darkModeKey = 'darkMode';
static const String _themeModeKey = 'themeMode';
static const String _themeColorIndexKey = 'themeColorIndex';
static const String _accentColorIndexKey = 'accentColorIndex';
static const String _fontSizeIndexKey = 'fontSizeIndex';
static const String _enableAnimationKey = 'enableAnimation';
static const String _enableBlurEffectKey = 'enableBlurEffect';
// 可观察状态
final _isDarkMode = false.obs;
final _themeMode = AppThemeMode.system.obs;
final _themeColorIndex = 0.obs;
final _accentColorIndex = 0.obs;
final _fontSizeIndex = 1.obs;
final _enableAnimation = true.obs;
final _enableBlurEffect = true.obs;
// Getters
bool get isDarkMode => _isDarkMode.value;
AppThemeMode get themeMode => _themeMode.value;
int get themeColorIndex => _themeColorIndex.value;
int get accentColorIndex => _accentColorIndex.value;
int get fontSizeIndex => _fontSizeIndex.value;
bool get enableAnimation => _enableAnimation.value;
bool get enableBlurEffect => _enableBlurEffect.value;
/// 获取当前 Flutter ThemeMode
ThemeMode get currentThemeMode {
if (_isDarkMode.value) {
return ThemeMode.dark;
}
return _themeMode.value.themeMode;
}
/// 获取 Rx 状态(供 Obx 使用)
RxBool get isDarkModeRx => _isDarkMode;
Rx<AppThemeMode> get themeModeRx => _themeMode;
RxInt get themeColorIndexRx => _themeColorIndex;
RxInt get accentColorIndexRx => _accentColorIndex;
RxInt get fontSizeIndexRx => _fontSizeIndex;
RxBool get enableAnimationRx => _enableAnimation;
RxBool get enableBlurEffectRx => _enableBlurEffect;
@override
void onInit() {
super.onInit();
_loadThemeSettings();
}
/// SharedPreferences 实例(公开访问,供其他组件使用)
SharedPreferences? get prefs => _prefs;
/// 加载主题设置
Future<void> _loadThemeSettings() async {
_prefs = await SharedPreferences.getInstance();
_isDarkMode.value = _prefs?.getBool(_darkModeKey) ?? false;
_themeMode.value = AppThemeMode.values[
(_prefs?.getInt(_themeModeKey) ?? 0).clamp(0, AppThemeMode.values.length - 1)
];
_themeColorIndex.value = _prefs?.getInt(_themeColorIndexKey) ?? 0;
_accentColorIndex.value = _prefs?.getInt(_accentColorIndexKey) ?? 0;
_fontSizeIndex.value = _prefs?.getInt(_fontSizeIndexKey) ?? 1;
_enableAnimation.value = _prefs?.getBool(_enableAnimationKey) ?? true;
_enableBlurEffect.value = _prefs?.getBool(_enableBlurEffectKey) ?? true;
// 应用主题模式
_applyThemeMode();
}
/// 保存主题设置
Future<void> _saveThemeSettings() async {
_prefs ??= await SharedPreferences.getInstance();
await _prefs?.setBool(_darkModeKey, _isDarkMode.value);
await _prefs?.setInt(_themeModeKey, _themeMode.value.index);
await _prefs?.setInt(_themeColorIndexKey, _themeColorIndex.value);
await _prefs?.setInt(_accentColorIndexKey, _accentColorIndex.value);
await _prefs?.setInt(_fontSizeIndexKey, _fontSizeIndex.value);
await _prefs?.setBool(_enableAnimationKey, _enableAnimation.value);
await _prefs?.setBool(_enableBlurEffectKey, _enableBlurEffect.value);
}
/// 应用主题模式到 GetX
void _applyThemeMode() {
Get.changeThemeMode(currentThemeMode);
}
/// 切换深色模式
/// [enabled] true 开启深色模式, false 关闭深色模式
Future<void> toggleDarkMode(bool enabled) async {
if (_isDarkMode.value == enabled) return;
_isDarkMode.value = enabled;
await _saveThemeSettings();
_applyThemeMode();
// 显示提示
Get.snackbar(
'主题切换',
enabled ? '已切换到深色模式 🌙' : '已切换到浅色模式 ☀️',
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 2),
margin: const EdgeInsets.all(16),
borderRadius: 12,
);
}
/// 设置主题模式
Future<void> setThemeMode(AppThemeMode mode) async {
if (_themeMode.value == mode) return;
_themeMode.value = mode;
await _saveThemeSettings();
_applyThemeMode();
}
/// 切换主题模式(循环切换: system -> light -> dark -> system
Future<void> cycleThemeMode() async {
final currentIndex = _themeMode.value.index;
final nextIndex = (currentIndex + 1) % AppThemeMode.values.length;
await setThemeMode(AppThemeMode.values[nextIndex]);
}
/// 设置主题色索引
Future<void> setThemeColorIndex(int index) async {
if (_themeColorIndex.value == index) return;
_themeColorIndex.value = index;
await _saveThemeSettings();
}
/// 设置强调色索引
Future<void> setAccentColorIndex(int index) async {
if (_accentColorIndex.value == index) return;
_accentColorIndex.value = index;
await _saveThemeSettings();
}
/// 设置字体大小索引
Future<void> setFontSizeIndex(int index) async {
if (_fontSizeIndex.value == index) return;
_fontSizeIndex.value = index;
await _saveThemeSettings();
}
/// 切换动画效果
Future<void> toggleAnimation(bool enabled) async {
if (_enableAnimation.value == enabled) return;
_enableAnimation.value = enabled;
await _saveThemeSettings();
}
/// 切换模糊效果
Future<void> toggleBlurEffect(bool enabled) async {
if (_enableBlurEffect.value == enabled) return;
_enableBlurEffect.value = enabled;
await _saveThemeSettings();
}
/// 获取主题配置
ThemeConfig get themeConfig {
return ThemeConfig(
isDarkMode: _isDarkMode.value,
themeMode: _themeMode.value,
themeColorIndex: _themeColorIndex.value,
accentColorIndex: _accentColorIndex.value,
fontSizeIndex: _fontSizeIndex.value,
enableAnimation: _enableAnimation.value,
enableBlurEffect: _enableBlurEffect.value,
);
}
/// 应用完整主题配置
Future<void> applyThemeConfig(ThemeConfig config) async {
_isDarkMode.value = config.isDarkMode;
_themeMode.value = config.themeMode;
_themeColorIndex.value = config.themeColorIndex;
_accentColorIndex.value = config.accentColorIndex;
_fontSizeIndex.value = config.fontSizeIndex;
_enableAnimation.value = config.enableAnimation;
_enableBlurEffect.value = config.enableBlurEffect;
await _saveThemeSettings();
_applyThemeMode();
}
/// 重置为默认主题设置
Future<void> resetToDefault() async {
_isDarkMode.value = false;
_themeMode.value = AppThemeMode.system;
_themeColorIndex.value = 0;
_accentColorIndex.value = 0;
_fontSizeIndex.value = 1;
_enableAnimation.value = true;
_enableBlurEffect.value = true;
await _saveThemeSettings();
_applyThemeMode();
Get.snackbar(
'主题重置',
'已恢复默认主题设置',
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 2),
margin: const EdgeInsets.all(16),
borderRadius: 12,
);
}
/// 判断当前是否为深色模式(考虑系统设置)
bool isDarkModeEffective(BuildContext context) {
if (_isDarkMode.value) return true;
if (_themeMode.value == AppThemeMode.dark) return true;
if (_themeMode.value == AppThemeMode.system) {
return MediaQuery.platformBrightnessOf(context) == Brightness.dark;
}
return false;
}
}