深色模式、首页设置页面和功能优化
This commit is contained in:
240
lib/services/get/theme_controller.dart
Normal file
240
lib/services/get/theme_controller.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user