深色模式、首页设置页面和功能优化

This commit is contained in:
Developer
2026-04-02 07:06:55 +08:00
parent f0a62ed68b
commit 954d173329
88 changed files with 12157 additions and 7578 deletions

View File

@@ -2,12 +2,14 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../../constants/app_constants.dart';
import '../../../controllers/shared_preferences_storage_controller.dart';
import '../../../controllers/history_controller.dart';
import '../../../services/network_listener_service.dart';
import '../../../services/get/theme_controller.dart';
/// 时间: 2026-03-28
/// 功能: 答题记录页面
@@ -22,11 +24,10 @@ class DistinguishPage extends StatefulWidget {
}
class _DistinguishPageState extends State<DistinguishPage> {
// 答题记录列表
final ThemeController _themeController = Get.find<ThemeController>();
List<Map<String, dynamic>> _answerRecords = [];
bool _isLoading = true;
// 统计数据
int _totalQuestions = 0;
int _correctAnswers = 0;
int _wrongAnswers = 0;
@@ -140,22 +141,21 @@ class _DistinguishPageState extends State<DistinguishPage> {
}
}
/// 显示统计弹窗
void _showStatisticsDialog() {
final isDark = _themeController.isDarkMode;
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => _buildStatisticsSheet(),
builder: (context) => _buildStatisticsSheet(isDark),
);
}
/// 构建统计弹窗
Widget _buildStatisticsSheet() {
Widget _buildStatisticsSheet(bool isDark) {
return Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
),
child: SingleChildScrollView(
child: Padding(
@@ -164,20 +164,17 @@ class _DistinguishPageState extends State<DistinguishPage> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 顶部拖动条
Center(
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey[300],
color: isDark ? Colors.grey[600] : Colors.grey[300],
borderRadius: BorderRadius.circular(2),
),
),
),
const SizedBox(height: 20),
// 标题
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -196,17 +193,16 @@ class _DistinguishPageState extends State<DistinguishPage> {
),
),
const SizedBox(width: 12),
const Text(
Text(
'本次答题记录',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Colors.black87,
color: isDark ? Colors.white : Colors.black87,
),
),
],
),
// 复制内容按钮
if (_answerRecords.isNotEmpty)
Container(
decoration: BoxDecoration(
@@ -244,8 +240,6 @@ class _DistinguishPageState extends State<DistinguishPage> {
],
),
const SizedBox(height: 24),
// 统计卡片
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
@@ -253,7 +247,7 @@ class _DistinguishPageState extends State<DistinguishPage> {
gradient: LinearGradient(
colors: [
AppConstants.primaryColor.withAlpha(10),
Colors.white,
isDark ? const Color(0xFF2A2A2A) : Colors.white,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
@@ -266,33 +260,52 @@ class _DistinguishPageState extends State<DistinguishPage> {
),
child: Column(
children: [
_buildStatRow('已答题', '$_totalQuestions'),
_buildStatRow('正确', '$_correctAnswers', isGreen: true),
_buildStatRow('错误', '$_wrongAnswers', isRed: true),
_buildStatRow('已答题', '$_totalQuestions', isDark),
_buildStatRow(
'正确',
'$_correctAnswers',
isDark,
isGreen: true,
),
_buildStatRow(
'错误',
'$_wrongAnswers',
isDark,
isRed: true,
),
_buildStatRow(
'正确率',
'${_correctRate.toStringAsFixed(1)}%',
isDark,
isGreen: _correctRate >= 60,
),
_buildStatRow(
'错误率',
'${_wrongRate.toStringAsFixed(1)}%',
isDark,
isRed: _wrongRate > 40,
),
_buildStatRow(
'平均用时',
'${_averageTime.toStringAsFixed(1)}',
isDark,
),
_buildStatRow('提示次数', '$_hintCount', isDark),
_buildStatRow('跳过次数', '$_skipCount', isDark),
Divider(
height: 24,
color: isDark ? Colors.grey[700] : Colors.grey[300],
),
_buildStatRow(
'诗词水平',
_poetryLevel,
isDark,
isHighlight: true,
),
_buildStatRow('提示次数', '$_hintCount'),
_buildStatRow('跳过次数', '$_skipCount'),
const Divider(height: 24),
_buildStatRow('诗词水平', _poetryLevel, isHighlight: true),
],
),
),
const SizedBox(height: 24),
// 复制按钮
SizedBox(
width: double.infinity,
child: Container(
@@ -350,15 +363,15 @@ class _DistinguishPageState extends State<DistinguishPage> {
);
}
/// 构建统计行
Widget _buildStatRow(
String label,
String value, {
String value,
bool isDark, {
bool isGreen = false,
bool isRed = false,
bool isHighlight = false,
}) {
Color valueColor = Colors.black87;
Color valueColor = isDark ? Colors.white : Colors.black87;
if (isGreen) valueColor = Colors.green;
if (isRed) valueColor = Colors.red;
if (isHighlight) valueColor = AppConstants.primaryColor;
@@ -368,7 +381,13 @@ class _DistinguishPageState extends State<DistinguishPage> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: TextStyle(fontSize: 15, color: Colors.grey[700])),
Text(
label,
style: TextStyle(
fontSize: 15,
color: isDark ? Colors.grey[400] : Colors.grey[700],
),
),
Text(
value,
style: TextStyle(
@@ -483,96 +502,105 @@ $_poetryLevel
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'答题记录',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
backgroundColor: AppConstants.primaryColor,
foregroundColor: Colors.white,
elevation: 0,
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppConstants.primaryColor,
AppConstants.primaryColor.withAlpha(180),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
return Obx(() {
final isDark = _themeController.isDarkMode;
return Scaffold(
appBar: AppBar(
title: Text(
'答题记录',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: isDark ? Colors.white : Colors.white,
),
),
),
actions: [
// 统计按钮
IconButton(
onPressed: _showStatisticsDialog,
icon: const Icon(Icons.analytics_outlined),
tooltip: '查看统计',
backgroundColor: AppConstants.primaryColor,
foregroundColor: Colors.white,
elevation: 0,
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppConstants.primaryColor,
AppConstants.primaryColor.withAlpha(180),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
// 清空按钮
if (_answerRecords.isNotEmpty)
actions: [
IconButton(
onPressed: _clearRecords,
icon: const Icon(Icons.delete_outline),
tooltip: '清空记录',
onPressed: _showStatisticsDialog,
icon: const Icon(Icons.analytics_outlined),
tooltip: '查看统计',
),
],
),
body: Container(
color: Colors.grey[50],
child: SafeArea(
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _answerRecords.isEmpty
? _buildEmptyView()
: _buildRecordList(),
if (_answerRecords.isNotEmpty)
IconButton(
onPressed: _clearRecords,
icon: const Icon(Icons.delete_outline),
tooltip: '清空记录',
),
],
),
),
);
body: Container(
color: isDark ? const Color(0xFF1A1A1A) : Colors.grey[50],
child: SafeArea(
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _answerRecords.isEmpty
? _buildEmptyView(isDark)
: _buildRecordList(isDark),
),
),
);
});
}
/// 构建空记录视图
Widget _buildEmptyView() {
Widget _buildEmptyView(bool isDark) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.menu_book_outlined, size: 80, color: Colors.grey[300]),
Icon(
Icons.menu_book_outlined,
size: 80,
color: isDark ? Colors.grey[600] : Colors.grey[300],
),
const SizedBox(height: 16),
Text(
'暂无答题记录',
style: TextStyle(
fontSize: 18,
color: Colors.grey[500],
color: isDark ? Colors.grey[400] : Colors.grey[500],
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
Text(
'快去答题吧!',
style: TextStyle(fontSize: 14, color: Colors.grey[400]),
style: TextStyle(
fontSize: 14,
color: isDark ? Colors.grey[500] : Colors.grey[400],
),
),
],
),
);
}
/// 构建记录列表
Widget _buildRecordList() {
Widget _buildRecordList(bool isDark) {
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: _answerRecords.length,
itemBuilder: (context, index) {
final record = _answerRecords[index];
return _buildRecordCard(record, index);
return _buildRecordCard(record, index, isDark);
},
);
}
/// 构建记录卡片
Widget _buildRecordCard(Map<String, dynamic> record, int index) {
Widget _buildRecordCard(Map<String, dynamic> record, int index, bool isDark) {
final question = record['question'] ?? '未知题目';
final author = record['author'] ?? '未知作者';
final tags = (record['tags'] as List<dynamic>?)?.cast<String>() ?? [];
@@ -582,11 +610,13 @@ $_poetryLevel
return Container(
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: Colors.white,
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(10),
color: isDark
? Colors.black.withAlpha(30)
: Colors.black.withAlpha(10),
blurRadius: 8,
offset: const Offset(0, 2),
),
@@ -597,11 +627,9 @@ $_poetryLevel
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题和答对/答错标识
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 序号
Container(
width: 28,
height: 28,
@@ -621,17 +649,16 @@ $_poetryLevel
),
),
const SizedBox(width: 12),
// 题目
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
question,
style: const TextStyle(
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black87,
color: isDark ? Colors.white : Colors.black87,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
@@ -641,7 +668,7 @@ $_poetryLevel
'—— $author',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
color: isDark ? Colors.grey[400] : Colors.grey[600],
fontStyle: FontStyle.italic,
),
),
@@ -649,7 +676,6 @@ $_poetryLevel
),
),
const SizedBox(width: 8),
// 答对/答错标识
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
@@ -657,8 +683,8 @@ $_poetryLevel
),
decoration: BoxDecoration(
color: isCorrect
? Colors.green.withAlpha(20)
: Colors.red.withAlpha(20),
? Colors.green.withAlpha(isDark ? 40 : 20)
: Colors.red.withAlpha(isDark ? 40 : 20),
borderRadius: BorderRadius.circular(12),
),
child: Row(
@@ -684,10 +710,8 @@ $_poetryLevel
],
),
const SizedBox(height: 12),
// 标签和时间
Row(
children: [
// 标签
Expanded(
child: tags.isNotEmpty
? Wrap(
@@ -724,20 +748,26 @@ $_poetryLevel
'暂无标签',
style: TextStyle(
fontSize: 12,
color: Colors.grey[400],
color: isDark ? Colors.grey[500] : Colors.grey[400],
fontStyle: FontStyle.italic,
),
),
),
// 时间
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.access_time, size: 12, color: Colors.grey[400]),
Icon(
Icons.access_time,
size: 12,
color: isDark ? Colors.grey[500] : Colors.grey[400],
),
const SizedBox(width: 4),
Text(
answerTime,
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
style: TextStyle(
fontSize: 12,
color: isDark ? Colors.grey[400] : Colors.grey[500],
),
),
],
),

File diff suppressed because it is too large Load Diff