😋 初始化仓库
This commit is contained in:
368
lib/screens/settings_screen.dart
Normal file
368
lib/screens/settings_screen.dart
Normal file
@@ -0,0 +1,368 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../providers/auth_provider.dart';
|
||||
import '../providers/theme_provider.dart';
|
||||
import '../providers/evaluation_provider.dart';
|
||||
import '../widgets/confirm_dialog.dart';
|
||||
import 'login_screen.dart';
|
||||
|
||||
/// Settings screen for app configuration
|
||||
///
|
||||
/// Provides theme customization, logout, and data management
|
||||
class SettingsScreen extends StatelessWidget {
|
||||
const SettingsScreen({super.key});
|
||||
|
||||
Future<void> _handleLogout(BuildContext context) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => const ConfirmDialog(
|
||||
title: '退出登录',
|
||||
content: '确定要退出登录吗?',
|
||||
confirmText: '退出',
|
||||
cancelText: '取消',
|
||||
),
|
||||
);
|
||||
|
||||
if (confirmed != true || !context.mounted) return;
|
||||
|
||||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||||
final evaluationProvider = Provider.of<EvaluationProvider>(
|
||||
context,
|
||||
listen: false,
|
||||
);
|
||||
|
||||
await authProvider.logout();
|
||||
evaluationProvider.reset();
|
||||
|
||||
if (!context.mounted) return;
|
||||
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(builder: (context) => const LoginScreen()),
|
||||
(route) => false,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleClearData(BuildContext context) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => const ConfirmDialog(
|
||||
title: '清除数据',
|
||||
content: '确定要清除所有本地数据吗?\n这将删除评教历史记录。',
|
||||
confirmText: '清除',
|
||||
cancelText: '取消',
|
||||
),
|
||||
);
|
||||
|
||||
if (confirmed != true || !context.mounted) return;
|
||||
|
||||
final evaluationProvider = Provider.of<EvaluationProvider>(
|
||||
context,
|
||||
listen: false,
|
||||
);
|
||||
await evaluationProvider.clearEvaluationHistory();
|
||||
|
||||
if (!context.mounted) return;
|
||||
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(const SnackBar(content: Text('数据已清除')));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('设置')),
|
||||
body: ListView(
|
||||
children: [
|
||||
// Theme section
|
||||
_buildSectionHeader(context, '外观设置'),
|
||||
_buildThemeModeSelector(context),
|
||||
_buildColorSchemeSelector(context),
|
||||
const Divider(height: 32),
|
||||
|
||||
// Account section
|
||||
_buildSectionHeader(context, '账号管理'),
|
||||
_buildAccountInfo(context),
|
||||
_buildLogoutTile(context),
|
||||
const Divider(height: 32),
|
||||
|
||||
// Data section
|
||||
_buildSectionHeader(context, '数据管理'),
|
||||
_buildClearDataTile(context),
|
||||
const Divider(height: 32),
|
||||
|
||||
// About section
|
||||
_buildSectionHeader(context, '关于'),
|
||||
_buildAboutTile(context),
|
||||
_buildFontLicenseTile(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSectionHeader(BuildContext context, String title) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
child: Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildThemeModeSelector(BuildContext context) {
|
||||
return Consumer<ThemeProvider>(
|
||||
builder: (context, themeProvider, child) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.brightness_6),
|
||||
title: const Text('主题模式'),
|
||||
subtitle: Text(
|
||||
themeProvider.getThemeModeName(themeProvider.themeMode),
|
||||
),
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => _ThemeModeDialog(
|
||||
currentMode: themeProvider.themeMode,
|
||||
onModeSelected: (mode) {
|
||||
themeProvider.setThemeMode(mode);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildColorSchemeSelector(BuildContext context) {
|
||||
return Consumer<ThemeProvider>(
|
||||
builder: (context, themeProvider, child) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.palette),
|
||||
title: const Text('颜色方案'),
|
||||
subtitle: Text(
|
||||
themeProvider.getColorSchemeName(themeProvider.colorScheme),
|
||||
),
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => _ColorSchemeDialog(
|
||||
currentScheme: themeProvider.colorScheme,
|
||||
onSchemeSelected: (scheme) {
|
||||
themeProvider.setColorScheme(scheme);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAccountInfo(BuildContext context) {
|
||||
return Consumer<AuthProvider>(
|
||||
builder: (context, authProvider, child) {
|
||||
final credentials = authProvider.credentials;
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.account_circle),
|
||||
title: const Text('当前账号'),
|
||||
subtitle: Text(credentials?.userId ?? '未登录'),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLogoutTile(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: Icon(Icons.logout, color: Theme.of(context).colorScheme.error),
|
||||
title: Text(
|
||||
'退出登录',
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.error),
|
||||
),
|
||||
onTap: () => _handleLogout(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildClearDataTile(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.delete_outline),
|
||||
title: const Text('清除本地数据'),
|
||||
subtitle: const Text('删除评教历史记录'),
|
||||
onTap: () => _handleClearData(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAboutTile(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.info_outline),
|
||||
title: const Text('关于应用'),
|
||||
subtitle: const Text('版本 1.0.0'),
|
||||
onTap: () {
|
||||
showAboutDialog(
|
||||
context: context,
|
||||
applicationName: '自动评教系统',
|
||||
applicationVersion: '1.0.0',
|
||||
applicationIcon: Icon(
|
||||
Icons.school,
|
||||
size: 48,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
children: [
|
||||
const Text('AUFE自动评教工具'),
|
||||
const SizedBox(height: 8),
|
||||
const Text('帮助学生快速完成课程评教任务'),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFontLicenseTile(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.font_download),
|
||||
title: const Text('字体许可'),
|
||||
subtitle: const Text('MiSans 字体使用说明'),
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('MiSans 字体知识产权许可协议'),
|
||||
content: const SingleChildScrollView(
|
||||
child: Text(
|
||||
'本应用在 Windows 平台使用 MiSans 字体。\n\n'
|
||||
'根据小米科技有限责任公司的授权,MiSans 字体可免费用于个人和商业用途。\n\n'
|
||||
'使用条件:\n'
|
||||
'• 应特别注明使用了 MiSans 字体\n'
|
||||
'• 不得对字体进行改编或二次开发\n'
|
||||
'• 不得单独分发或售卖字体文件\n'
|
||||
'• 可自由分发使用该字体创作的作品\n\n'
|
||||
'本应用遵守以上使用条款。',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('关闭'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ThemeModeDialog extends StatelessWidget {
|
||||
final ThemeMode currentMode;
|
||||
final Function(ThemeMode) onModeSelected;
|
||||
|
||||
const _ThemeModeDialog({
|
||||
required this.currentMode,
|
||||
required this.onModeSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('选择主题模式'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
RadioListTile<ThemeMode>(
|
||||
title: const Text('浅色模式'),
|
||||
value: ThemeMode.light,
|
||||
groupValue: currentMode,
|
||||
onChanged: (mode) {
|
||||
if (mode != null) onModeSelected(mode);
|
||||
},
|
||||
),
|
||||
RadioListTile<ThemeMode>(
|
||||
title: const Text('深色模式'),
|
||||
value: ThemeMode.dark,
|
||||
groupValue: currentMode,
|
||||
onChanged: (mode) {
|
||||
if (mode != null) onModeSelected(mode);
|
||||
},
|
||||
),
|
||||
RadioListTile<ThemeMode>(
|
||||
title: const Text('跟随系统'),
|
||||
value: ThemeMode.system,
|
||||
groupValue: currentMode,
|
||||
onChanged: (mode) {
|
||||
if (mode != null) onModeSelected(mode);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ColorSchemeDialog extends StatelessWidget {
|
||||
final AppColorScheme currentScheme;
|
||||
final Function(AppColorScheme) onSchemeSelected;
|
||||
|
||||
const _ColorSchemeDialog({
|
||||
required this.currentScheme,
|
||||
required this.onSchemeSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('选择颜色方案'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_buildColorOption(context, AppColorScheme.blue, '蓝色', Colors.blue),
|
||||
_buildColorOption(context, AppColorScheme.green, '绿色', Colors.green),
|
||||
_buildColorOption(
|
||||
context,
|
||||
AppColorScheme.purple,
|
||||
'紫色',
|
||||
Colors.purple,
|
||||
),
|
||||
_buildColorOption(
|
||||
context,
|
||||
AppColorScheme.orange,
|
||||
'橙色',
|
||||
Colors.orange,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildColorOption(
|
||||
BuildContext context,
|
||||
AppColorScheme scheme,
|
||||
String name,
|
||||
Color color,
|
||||
) {
|
||||
return RadioListTile<AppColorScheme>(
|
||||
title: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(name),
|
||||
],
|
||||
),
|
||||
value: scheme,
|
||||
groupValue: currentScheme,
|
||||
onChanged: (scheme) {
|
||||
if (scheme != null) onSchemeSelected(scheme);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user