Files
kuaishai2/lib/features/settings/pages/settings_page.dart
Developer 5d28bf631b chore(project): 初始化项目基础配置文件
- 添加 CodeGraph、Android 和通用 gitignore 配置
- 创建项目元数据文件跟踪 Flutter 项目属性
- 添加 Codex AI 指导文档 AGENTS.md 说明项目架构
- 配置代码分析选项 analysis_options.yaml
- 设置 Android 应用清单权限和 Kiosk 模式配置
- 实现中英文国际化支持 AppLocalizations
- 配置 GoRouter 应用路由导航
- 创建明亮工业控制风格的主题配置 AppTheme
2026-06-04 11:19:44 +08:00

382 lines
13 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../core/localization/app_localizations.dart';
import '../../../core/localization/locale_provider.dart';
import '../../../core/theme/app_theme.dart';
import '../../../shared/widgets/common_button.dart';
import '../services/settings_service.dart';
/// 系统设置页面
class SettingsPage extends ConsumerStatefulWidget {
const SettingsPage({super.key});
@override
ConsumerState<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends ConsumerState<SettingsPage> {
String _currentVersion = 'V1.0.0';
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
// locale 用于语言切换,通过 ref.watch 保持监听
return Scaffold(
body: Container(
color: AppTheme.backgroundColor,
child: Row(
children: [
// 左侧导航菜单
SizedBox(
width: 280,
child: Container(
color: Colors.white,
child: Column(
children: [
// 返回按钮
Container(
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
IconButton(
icon: const Icon(Icons.arrow_back),
color: AppTheme.textPrimary,
onPressed: () => context.go('/'),
),
Text(
'返回首页',
style: TextStyle(
color: AppTheme.textSecondary,
fontSize: 14,
),
),
],
),
),
// 设置标题
Container(
height: 60,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppTheme.primaryColor.withValues(alpha: 0.1),
),
child: Row(
children: [
Icon(Icons.settings, color: AppTheme.primaryColor, size: 24),
const SizedBox(width: 12),
Text(
l10n?.settings ?? '系统设置',
style: TextStyle(
color: AppTheme.primaryColor,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
),
),
// 软件升级
_buildMenuItem(
icon: Icons.system_update,
title: l10n?.upgrade ?? '软件升级',
onTap: () {},
),
// 语言设置
_buildMenuItem(
icon: Icons.language,
title: l10n?.language ?? '语言设置',
onTap: () => _showLanguageDialog(),
),
// 安全设置
_buildMenuItem(
icon: Icons.lock,
title: l10n?.password ?? '密码修改',
onTap: () => _showPasswordDialog(),
),
// U盘导入
_buildMenuItem(
icon: Icons.usb,
title: l10n?.usbImport ?? 'U盘导入',
onTap: () => _showUsbImportDialog(),
),
],
),
),
),
// 右侧内容区域
Expanded(
child: Container(
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n?.upgrade ?? '软件升级',
style: TextStyle(
color: AppTheme.textPrimary,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 24),
// 版本信息
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppTheme.backgroundColor,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(Icons.info_outline, color: AppTheme.primaryColor),
const SizedBox(width: 12),
Text(
'当前版本: $_currentVersion',
style: TextStyle(color: AppTheme.textPrimary),
),
],
),
),
const SizedBox(height: 24),
// 检查更新按钮
CommonButton(
text: '检查更新',
icon: Icons.refresh,
type: ButtonType.primary,
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('已是最新版本'),
backgroundColor: AppTheme.successColor,
),
);
},
),
],
),
),
),
],
),
),
);
}
/// 导航菜单项
Widget _buildMenuItem({
required IconData icon,
required String title,
required VoidCallback onTap,
}) {
return ListTile(
leading: Icon(icon, color: AppTheme.textSecondary),
title: Text(title, style: TextStyle(color: AppTheme.textPrimary)),
trailing: Icon(Icons.chevron_right, color: AppTheme.idleColor),
onTap: onTap,
);
}
/// 显示语言选择对话框
void _showLanguageDialog() {
final locale = ref.read(localeProvider);
final currentLang = locale.languageCode;
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text('语言设置'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
RadioListTile<String>(
title: Text('简体中文'),
value: 'zh',
groupValue: currentLang,
onChanged: (value) {
ref.read(localeProvider.notifier).setChinese();
Navigator.of(ctx).pop();
},
),
RadioListTile<String>(
title: Text('English'),
value: 'en',
groupValue: currentLang,
onChanged: (value) {
ref.read(localeProvider.notifier).setEnglish();
Navigator.of(ctx).pop();
},
),
],
),
),
);
}
/// 显示密码修改对话框
void _showPasswordDialog() {
final oldPasswordController = TextEditingController();
final newPasswordController = TextEditingController();
final confirmPasswordController = TextEditingController();
String? errorMessage;
showDialog(
context: context,
builder: (ctx) => StatefulBuilder(
builder: (context, setState) => AlertDialog(
title: Text('密码修改'),
content: SizedBox(
width: 300,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: oldPasswordController,
decoration: InputDecoration(
labelText: '原密码',
errorText: null,
),
obscureText: true,
),
const SizedBox(height: 12),
TextField(
controller: newPasswordController,
decoration: InputDecoration(
labelText: '新密码',
helperText: '至少6位字符',
),
obscureText: true,
),
const SizedBox(height: 12),
TextField(
controller: confirmPasswordController,
decoration: InputDecoration(labelText: '确认新密码'),
obscureText: true,
),
if (errorMessage != null)
Padding(
padding: const EdgeInsets.only(top: 12),
child: Text(
errorMessage!,
style: TextStyle(color: AppTheme.errorColor, fontSize: 12),
),
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(),
child: Text('取消'),
),
ElevatedButton(
onPressed: () async {
// 验证逻辑
final oldPassword = oldPasswordController.text.trim();
final newPassword = newPasswordController.text.trim();
final confirmPassword = confirmPasswordController.text.trim();
// 检查空值
if (oldPassword.isEmpty || newPassword.isEmpty || confirmPassword.isEmpty) {
setState(() => errorMessage = '请填写所有字段');
return;
}
// 检查新密码长度
if (newPassword.length < 6) {
setState(() => errorMessage = '新密码至少6位字符');
return;
}
// 检查新密码一致性
if (newPassword != confirmPassword) {
setState(() => errorMessage = '两次输入的新密码不一致');
return;
}
// 验证原密码
final isValid = await SettingsService.instance.verifyPassword(oldPassword);
if (!isValid) {
setState(() => errorMessage = '原密码错误');
return;
}
// 保存新密码
final success = await SettingsService.instance.setPassword(newPassword);
Navigator.of(ctx).pop();
if (success) {
ScaffoldMessenger.of(this.context).showSnackBar(
SnackBar(
content: Text('密码已修改'),
backgroundColor: AppTheme.successColor,
),
);
} else {
ScaffoldMessenger.of(this.context).showSnackBar(
SnackBar(
content: Text('密码修改失败'),
backgroundColor: AppTheme.errorColor,
),
);
}
},
child: Text('确认'),
),
],
),
),
);
}
/// 显示U盘导入对话框
void _showUsbImportDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('U盘导入'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.usb, size: 48, color: AppTheme.warningColor),
const SizedBox(height: 16),
Text('未检测到U盘'),
const SizedBox(height: 8),
Text(
'请插入U盘后重试',
style: TextStyle(color: AppTheme.textSecondary, fontSize: 12),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('关闭'),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('正在检测U盘...'),
backgroundColor: AppTheme.primaryColor,
),
);
},
child: Text('重新检测'),
),
],
),
);
}
}