import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../constants/app_constants.dart'; import '../../../services/get/theme_controller.dart'; /// 时间: 2026-03-27 /// 功能: 主题个性化设置页面 /// 介绍: 允许用户自定义应用主题、颜色、字体大小等 class AppDiyPage extends StatefulWidget { const AppDiyPage({super.key}); @override State createState() => _AppDiyPageState(); } class _AppDiyPageState extends State { // GetX ThemeController late ThemeController _themeController; // 本地状态(不通过ThemeController管理的设置) bool _showGuideOnStartup = true; int _cardSizeIndex = 1; // 0: 小, 1: 中, 2: 大 bool _enableSystemNavigation = false; // 滚动控制 final ScrollController _scrollController = ScrollController(); bool _isScrolling = true; late Timer _scrollTimer; // 主题颜色选项 final List _themeColors = [ AppConstants.primaryColor, // 默认紫色 Colors.blue, // 蓝色 Colors.green, // 绿色 Colors.orange, // 橙色 Colors.red, // 红色 Colors.teal, // 青色 ]; // 强调色选项 final List _accentColors = [ AppConstants.primaryColor, // 默认紫色 Colors.yellow, // 黄色 Colors.pink, // 粉色 Colors.cyan, // 青色 Colors.purple, // 深紫色 ]; // 字体大小选项 final List _fontSizes = ['小', '中', '大']; // 卡片大小选项 final List _cardSizes = ['小', '中', '大']; @override void initState() { super.initState(); // 获取 ThemeController _themeController = Get.find(); _loadLocalSettings(); _startScrolling(); // 延迟显示开发中提示对话框 WidgetsBinding.instance.addPostFrameCallback((_) { _showDevNoticeDialog(); }); } // 显示开发中提示对话框 void _showDevNoticeDialog() { showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Row( children: [ Icon(Icons.construction, color: AppConstants.primaryColor), const SizedBox(width: 8), const Text('开发中'), ], ), content: const Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '个性化设置开发中', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), ), SizedBox(height: 12), Text('• 当前仅支持设置深色模式'), Text('• 其他设置仅当前页面生效'), Text('• 后续版本将陆续支持'), Text('• 可提前预览主题风格设置'), SizedBox(height: 12), Text( '感谢您的耐心等待!', style: TextStyle(color: Colors.grey, fontSize: 12), ), ], ), actions: [ ElevatedButton( onPressed: () => Navigator.of(context).pop(), style: ElevatedButton.styleFrom( backgroundColor: AppConstants.primaryColor, foregroundColor: Colors.white, ), child: const Text('我知道了'), ), ], ); }, ); } @override void dispose() { _scrollController.dispose(); _scrollTimer.cancel(); super.dispose(); } void _startScrolling() { _isScrolling = true; _scrollTimer = Timer.periodic(const Duration(milliseconds: 30), (timer) { if (_scrollController.hasClients) { _scrollController.jumpTo(_scrollController.offset + 1); // 当滚动到末尾时,重新开始滚动 if (_scrollController.offset >= _scrollController.position.maxScrollExtent) { _scrollController.jumpTo(0); } } }); } void _stopScrolling() { _isScrolling = false; _scrollTimer.cancel(); } void _toggleScroll() { if (_isScrolling) { _stopScrolling(); } else { _startScrolling(); } } /// 加载本地设置(不通过ThemeController管理的设置) void _loadLocalSettings() async { // ThemeController 会自动加载主题相关设置 // 这里只加载本地独有的设置 setState(() { _showGuideOnStartup = _themeController.prefs?.getBool('showGuideOnStartup') ?? true; _cardSizeIndex = _themeController.prefs?.getInt('cardSizeIndex') ?? 1; _enableSystemNavigation = _themeController.prefs?.getBool('enableSystemNavigation') ?? false; }); } /// 保存本地设置 void _saveLocalSettings() async { await _themeController.prefs?.setBool( 'showGuideOnStartup', _showGuideOnStartup, ); await _themeController.prefs?.setInt('cardSizeIndex', _cardSizeIndex); await _themeController.prefs?.setBool( 'enableSystemNavigation', _enableSystemNavigation, ); } @override Widget build(BuildContext context) { // 使用 Obx 监听 ThemeController 的状态变化 return Obx(() { final isDark = _themeController.isDarkModeRx.value; final themeColorIdx = _themeController.themeColorIndexRx.value; return Scaffold( appBar: AppBar( title: const Text('个性化'), backgroundColor: isDark ? Colors.grey[900] : Colors.white, foregroundColor: isDark ? Colors.white : AppConstants.primaryColor, elevation: 0, ), backgroundColor: isDark ? Colors.grey[900] : Colors.grey[50], body: ListView( padding: const EdgeInsets.all(16), children: [ // 主题模式 _buildSection('显示设置', isDark), _buildSwitchItem( '深色模式', _themeController.isDarkModeRx.value, (value) => _themeController.toggleDarkMode(value), icon: Icons.dark_mode, isDark: isDark, themeColorIdx: themeColorIdx, ), // 主题颜色 _buildSection('主题颜色', isDark), _buildColorSelector( '色彩', _themeColors, _themeController.themeColorIndexRx.value, (index) => _themeController.setThemeColorIndex(index), isDark: isDark, ), _buildColorSelector( '强调色', _accentColors, _themeController.accentColorIndexRx.value, (index) => _themeController.setAccentColorIndex(index), isDark: isDark, ), // 字体大小 _buildSection('字体设置', isDark), _buildOptionSelector( '字体大小', _fontSizes, _themeController.fontSizeIndexRx.value, (index) { if (index != null) { _themeController.setFontSizeIndex(index); } }, icon: Icons.font_download, isDark: isDark, themeColorIdx: themeColorIdx, ), // 卡片大小 _buildSection('界面设置', isDark), _buildOptionSelector( '卡片阴影', _cardSizes, _cardSizeIndex, (index) { if (index != null) { setState(() { _cardSizeIndex = index; }); _saveLocalSettings(); } }, icon: Icons.crop_square, isDark: isDark, themeColorIdx: themeColorIdx, ), // 启动显示 _buildSwitchItem( '启动时显示引导页', _showGuideOnStartup, (value) { setState(() { _showGuideOnStartup = value; }); _saveLocalSettings(); }, icon: Icons.info_outline, isDark: isDark, themeColorIdx: themeColorIdx, ), // 动画效果 _buildSwitchItem( '启用动画效果', _themeController.enableAnimationRx.value, (value) => _themeController.toggleAnimation(value), icon: Icons.animation, isDark: isDark, themeColorIdx: themeColorIdx, ), // 模糊效果 _buildSwitchItem( '启用模糊效果', _themeController.enableBlurEffectRx.value, (value) => _themeController.toggleBlurEffect(value), icon: Icons.blur_on, isDark: isDark, themeColorIdx: themeColorIdx, ), // 系统导航 _buildSwitchItem( '软件悬浮球', _enableSystemNavigation, (value) { setState(() { _enableSystemNavigation = value; }); _saveLocalSettings(); }, icon: Icons.navigation, isDark: isDark, themeColorIdx: themeColorIdx, ), _buildSwitchItem( '转场动画', _themeController.enableAnimationRx.value, (value) => _themeController.toggleAnimation(value), icon: Icons.track_changes, isDark: isDark, themeColorIdx: themeColorIdx, ), // 设计风格 _buildSection('设计风格', isDark), _buildDesignStyleCard(isDark, themeColorIdx), const SizedBox(height: 40), ], ), ); }); } Widget _buildSection(String title, bool isDark) { return Padding( padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8), child: Text( title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: isDark ? Colors.grey[300] : Colors.grey[700], ), ), ); } Widget _buildSwitchItem( String title, bool value, ValueChanged onChanged, { required IconData icon, required bool isDark, required int themeColorIdx, }) { return Container( margin: const EdgeInsets.symmetric(vertical: 4), decoration: BoxDecoration( color: isDark ? Colors.grey[800] : Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withAlpha(5), blurRadius: 2, offset: const Offset(0, 1), ), ], ), child: ListTile( leading: Icon(icon, color: _themeColors[themeColorIdx]), title: Text( title, style: TextStyle(color: isDark ? Colors.white : Colors.black87), ), trailing: Switch( value: value, onChanged: onChanged, activeThumbColor: _themeColors[themeColorIdx], ), ), ); } Widget _buildOptionSelector( String title, List options, int selectedIndex, ValueChanged onChanged, { required IconData icon, required bool isDark, required int themeColorIdx, }) { return Container( margin: const EdgeInsets.symmetric(vertical: 4), decoration: BoxDecoration( color: isDark ? Colors.grey[800] : Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withAlpha(5), blurRadius: 2, offset: const Offset(0, 1), ), ], ), child: ListTile( leading: Icon(icon, color: _themeColors[themeColorIdx]), title: Text( title, style: TextStyle(color: isDark ? Colors.white : Colors.black87), ), trailing: DropdownButton( value: selectedIndex, onChanged: (value) { if (value != null) { onChanged(value); } }, items: options.asMap().entries.map((entry) { return DropdownMenuItem( value: entry.key, child: Text( entry.value, style: TextStyle(color: isDark ? Colors.white : Colors.black87), ), ); }).toList(), dropdownColor: isDark ? Colors.grey[800] : Colors.white, style: TextStyle(color: isDark ? Colors.white : Colors.black87), ), ), ); } Widget _buildColorSelector( String title, List colors, int selectedIndex, ValueChanged onChanged, { required bool isDark, }) { return Container( margin: const EdgeInsets.symmetric(vertical: 4), decoration: BoxDecoration( color: isDark ? Colors.grey[800] : Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withAlpha(5), blurRadius: 2, offset: const Offset(0, 1), ), ], ), child: ListTile( title: Text( title, style: TextStyle(color: isDark ? Colors.white : Colors.black87), ), trailing: Row( mainAxisSize: MainAxisSize.min, children: colors.asMap().entries.map((entry) { return GestureDetector( onTap: () => onChanged(entry.key), child: Container( width: 32, height: 32, margin: const EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration( color: entry.value, shape: BoxShape.circle, border: entry.key == selectedIndex ? Border.all( color: isDark ? Colors.white : Colors.black, width: 2, ) : null, ), ), ); }).toList(), ), ), ); } Widget _buildDesignStyleCard(bool isDark, int themeColorIdx) { return Container( margin: const EdgeInsets.symmetric(vertical: 4), decoration: BoxDecoration( color: isDark ? Colors.grey[800] : Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withAlpha(5), blurRadius: 2, offset: const Offset(0, 1), ), ], ), child: Column( children: [ Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.teal.withAlpha(10), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.design_services, color: isDark ? Colors.teal[300] : Colors.teal[700], size: 20, ), ), const SizedBox(width: 12), Text( '设计样式&主题风格', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: isDark ? Colors.white : Colors.black87, ), ), ], ), ), const Divider(height: 1), Padding( padding: const EdgeInsets.all(16), child: Column( children: [ GestureDetector( onTap: _toggleScroll, child: SizedBox( height: 40, child: SingleChildScrollView( controller: _scrollController, scrollDirection: Axis.horizontal, child: Row( children: [ _buildStyleChip( 'Material 2', Icons.style, isMd: true, isDark: isDark, themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), _buildStyleChip( 'Material 3', Icons.auto_awesome, isMd: true, isDark: isDark, themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), _buildStyleChip( '透明毛玻璃', Icons.blur_on, isDark: isDark, themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), _buildStyleChip( '沉浸式渐变色', Icons.color_lens, isDark: isDark, themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), _buildStyleChip( '动态光感效果', Icons.lightbulb_outline, isDark: isDark, themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), ], ), ), ), ), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( gradient: LinearGradient( colors: [ _themeColors[themeColorIdx].withAlpha(10), _themeColors[themeColorIdx].withAlpha(5), ], ), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Icon( Icons.lightbulb_outline, size: 16, color: _themeColors[themeColorIdx], ), const SizedBox(width: 8), Expanded( child: Text( '采用现代Material Design设计语言,\n参考透明毛玻璃、沉浸式渐变色和动态光感等效果', style: TextStyle( fontSize: 12, color: isDark ? Colors.grey[300] : Colors.grey[700], ), ), ), ], ), ), ], ), ), ], ), ); } Widget _buildStyleChip( String label, IconData icon, { bool isMd = false, required bool isDark, required int themeColorIdx, }) { final color = isMd ? _themeColors[themeColorIdx] : isDark ? Colors.blue[400]! : Colors.blue[600]!; return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: color.withAlpha(10), borderRadius: BorderRadius.circular(16), border: Border.all(color: color.withAlpha(50), width: 1), ), child: Row( children: [ Icon(icon, size: 14, color: color), const SizedBox(width: 4), Text(label, style: TextStyle(fontSize: 12, color: color)), ], ), ); } }