😋 初始化仓库

This commit is contained in:
2025-11-13 09:14:49 +08:00
commit 347d264437
133 changed files with 11214 additions and 0 deletions

View 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);
},
);
}
}