Files
wushu/lib/services/get/theme_controller.dart
2026-04-02 07:06:55 +08:00

241 lines
7.7 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 时间: 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;
}
}