Initial commit: Flutter 无书应用项目

This commit is contained in:
Developer
2026-03-30 02:35:31 +08:00
commit 9175ff9905
566 changed files with 103261 additions and 0 deletions

View File

@@ -0,0 +1,526 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../constants/app_constants.dart';
/// 时间: 2026-03-27
/// 功能: 主题个性化设置页面
/// 介绍: 允许用户自定义应用主题、颜色、字体大小等
class AppDiyPage extends StatefulWidget {
const AppDiyPage({super.key});
@override
State<AppDiyPage> createState() => _AppDiyPageState();
}
class _AppDiyPageState extends State<AppDiyPage> {
// 主题设置
bool _isDarkMode = false;
int _themeColorIndex = 0;
int _fontSizeIndex = 1; // 0: 小, 1: 中, 2: 大
bool _showGuideOnStartup = true;
int _cardSizeIndex = 1; // 0: 小, 1: 中, 2: 大
bool _enableAnimation = true;
bool _enableBlurEffect = true;
bool _enableSystemNavigation = false;
int _accentColorIndex = 0;
// 滚动控制
final ScrollController _scrollController = ScrollController();
bool _isScrolling = true;
late Timer _scrollTimer;
// 主题颜色选项
final List<Color> _themeColors = [
AppConstants.primaryColor, // 默认紫色
Colors.blue, // 蓝色
Colors.green, // 绿色
Colors.orange, // 橙色
Colors.red, // 红色
Colors.teal, // 青色
];
// 强调色选项
final List<Color> _accentColors = [
AppConstants.primaryColor, // 默认紫色
Colors.yellow, // 黄色
Colors.pink, // 粉色
Colors.cyan, // 青色
Colors.purple, // 深紫色
];
// 字体大小选项
final List<String> _fontSizes = ['', '', ''];
// 卡片大小选项
final List<String> _cardSizes = ['', '', ''];
@override
void initState() {
super.initState();
_loadSettings();
_startScrolling();
}
@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();
}
}
void _loadSettings() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_isDarkMode = prefs.getBool('darkMode') ?? false;
_themeColorIndex = prefs.getInt('themeColorIndex') ?? 0;
_fontSizeIndex = prefs.getInt('fontSizeIndex') ?? 1;
_showGuideOnStartup = prefs.getBool('showGuideOnStartup') ?? true;
_cardSizeIndex = prefs.getInt('cardSizeIndex') ?? 1;
_enableAnimation = prefs.getBool('enableAnimation') ?? true;
_enableBlurEffect = prefs.getBool('enableBlurEffect') ?? true;
_enableSystemNavigation =
prefs.getBool('enableSystemNavigation') ?? false;
_accentColorIndex = prefs.getInt('accentColorIndex') ?? 0;
});
}
void _saveSettings() async {
final prefs = await SharedPreferences.getInstance();
prefs.setBool('darkMode', _isDarkMode);
prefs.setInt('themeColorIndex', _themeColorIndex);
prefs.setInt('fontSizeIndex', _fontSizeIndex);
prefs.setBool('showGuideOnStartup', _showGuideOnStartup);
prefs.setInt('cardSizeIndex', _cardSizeIndex);
prefs.setBool('enableAnimation', _enableAnimation);
prefs.setBool('enableBlurEffect', _enableBlurEffect);
prefs.setBool('enableSystemNavigation', _enableSystemNavigation);
prefs.setInt('accentColorIndex', _accentColorIndex);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('个性化'),
backgroundColor: _isDarkMode ? Colors.grey[900] : Colors.white,
foregroundColor: _isDarkMode ? Colors.white : AppConstants.primaryColor,
elevation: 0,
),
backgroundColor: _isDarkMode ? Colors.grey[900] : Colors.grey[50],
body: ListView(
padding: const EdgeInsets.all(16),
children: [
// 主题模式
_buildSection('显示设置'),
_buildSwitchItem('深色模式', _isDarkMode, (value) {
setState(() {
_isDarkMode = value;
_saveSettings();
});
}, icon: Icons.dark_mode),
// 主题颜色
_buildSection('主题颜色'),
_buildColorSelector('色彩', _themeColors, _themeColorIndex, (index) {
setState(() {
_themeColorIndex = index;
_saveSettings();
});
}),
_buildColorSelector('强调色', _accentColors, _accentColorIndex, (index) {
setState(() {
_accentColorIndex = index;
_saveSettings();
});
}),
// 字体大小
_buildSection('字体设置'),
_buildOptionSelector('字体大小', _fontSizes, _fontSizeIndex, (index) {
if (index != null) {
setState(() {
_fontSizeIndex = index;
_saveSettings();
});
}
}, icon: Icons.font_download),
// 卡片大小
_buildSection('界面设置'),
_buildOptionSelector('卡片阴影', _cardSizes, _cardSizeIndex, (index) {
if (index != null) {
setState(() {
_cardSizeIndex = index;
_saveSettings();
});
}
}, icon: Icons.crop_square),
// 启动显示
_buildSwitchItem('启动时显示引导页', _showGuideOnStartup, (value) {
setState(() {
_showGuideOnStartup = value;
_saveSettings();
});
}, icon: Icons.info_outline),
// 动画效果
_buildSwitchItem('启用动画效果', _enableAnimation, (value) {
setState(() {
_enableAnimation = value;
_saveSettings();
});
}, icon: Icons.animation),
// 模糊效果
_buildSwitchItem('启用模糊效果', _enableBlurEffect, (value) {
setState(() {
_enableBlurEffect = value;
_saveSettings();
});
}, icon: Icons.blur_on),
// 系统导航
_buildSwitchItem('软件悬浮球', _enableSystemNavigation, (value) {
setState(() {
_enableSystemNavigation = value;
_saveSettings();
});
}, icon: Icons.navigation),
// 设计风格
_buildSection('设计风格'),
_buildDesignStyleCard(),
const SizedBox(height: 40),
],
),
);
}
Widget _buildSection(String title) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
child: Text(
title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: _isDarkMode ? Colors.grey[300] : Colors.grey[700],
),
),
);
}
Widget _buildSwitchItem(
String title,
bool value,
ValueChanged<bool> onChanged, {
required IconData icon,
}) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration(
color: _isDarkMode ? 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[_themeColorIndex]),
title: Text(
title,
style: TextStyle(color: _isDarkMode ? Colors.white : Colors.black87),
),
trailing: Switch(
value: value,
onChanged: onChanged,
activeThumbColor: _themeColors[_themeColorIndex],
),
),
);
}
Widget _buildOptionSelector(
String title,
List<String> options,
int selectedIndex,
ValueChanged<int?> onChanged, {
required IconData icon,
}) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration(
color: _isDarkMode ? 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[_themeColorIndex]),
title: Text(
title,
style: TextStyle(color: _isDarkMode ? Colors.white : Colors.black87),
),
trailing: DropdownButton<int>(
value: selectedIndex,
onChanged: (value) {
if (value != null) {
onChanged(value);
}
},
items: options.asMap().entries.map((entry) {
return DropdownMenuItem<int>(
value: entry.key,
child: Text(
entry.value,
style: TextStyle(
color: _isDarkMode ? Colors.white : Colors.black87,
),
),
);
}).toList(),
dropdownColor: _isDarkMode ? Colors.grey[800] : Colors.white,
style: TextStyle(color: _isDarkMode ? Colors.white : Colors.black87),
),
),
);
}
Widget _buildColorSelector(
String title,
List<Color> colors,
int selectedIndex,
ValueChanged<int> onChanged,
) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration(
color: _isDarkMode ? 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: _isDarkMode ? 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: _isDarkMode ? Colors.white : Colors.black,
width: 2,
)
: null,
),
),
);
}).toList(),
),
),
);
}
Widget _buildDesignStyleCard() {
return Container(
margin: const EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration(
color: _isDarkMode ? 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: _isDarkMode ? Colors.teal[300] : Colors.teal[700],
size: 20,
),
),
const SizedBox(width: 12),
Text(
'设计样式&主题风格',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: _isDarkMode ? Colors.white : Colors.black87,
),
),
],
),
),
const Divider(height: 1),
Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
GestureDetector(
onTap: _toggleScroll,
child: Container(
height: 40,
child: SingleChildScrollView(
controller: _scrollController,
scrollDirection: Axis.horizontal,
child: Row(
children: [
_buildStyleChip(
'Material 2',
Icons.style,
isMd: true,
),
const SizedBox(width: 8),
_buildStyleChip(
'Material 3',
Icons.auto_awesome,
isMd: true,
),
const SizedBox(width: 8),
_buildStyleChip('透明毛玻璃', Icons.blur_on),
const SizedBox(width: 8),
_buildStyleChip('沉浸式渐变色', Icons.color_lens),
const SizedBox(width: 8),
_buildStyleChip('动态光感效果', Icons.lightbulb_outline),
const SizedBox(width: 8),
],
),
),
),
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
_themeColors[_themeColorIndex].withAlpha(10),
_themeColors[_themeColorIndex].withAlpha(5),
],
),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(
Icons.lightbulb_outline,
size: 16,
color: _themeColors[_themeColorIndex],
),
const SizedBox(width: 8),
Expanded(
child: Text(
'采用现代Material Design设计语言\n参考透明毛玻璃、沉浸式渐变色和动态光感等效果',
style: TextStyle(
fontSize: 12,
color: _isDarkMode
? Colors.grey[300]
: Colors.grey[700],
),
),
),
],
),
),
],
),
),
],
),
);
}
Widget _buildStyleChip(String label, IconData icon, {bool isMd = false}) {
final color = isMd
? _themeColors[_themeColorIndex]
: _isDarkMode
? 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)),
],
),
);
}
}