feat: 诗词答题页面主题色支持与代码重构

- 创建 poetry-page.dart,提取 UI 组件(PoetryOptionItem、PoetryOptionsLayout、PoetryTag)
- 修改 poetry.dart,使用新组件,添加主题色支持
- 修改 flow-anim.dart,添加主题色支持
- 修改 distinguish.dart,添加主题色支持
- 支持动态主题色切换
- 支持深色模式
- 保持页面布局不变
This commit is contained in:
Developer
2026-04-03 00:38:17 +08:00
parent 7872f2e78a
commit c12f26bd4d
4 changed files with 790 additions and 612 deletions

View File

@@ -11,6 +11,7 @@ import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../../models/colors/app_colors.dart';
import '../../../models/colors/theme_colors.dart';
import '../../../controllers/shared_preferences_storage_controller.dart';
import '../../../controllers/history_controller.dart';
import '../../../services/network_listener_service.dart';
@@ -262,16 +263,8 @@ class _DistinguishPageState extends State<DistinguishPage> {
child: Column(
children: [
_buildStatRow('已答题', '$_totalQuestions'),
_buildStatRow(
'正确',
'$_correctAnswers',
isGreen: true,
),
_buildStatRow(
'错误',
'$_wrongAnswers',
isRed: true,
),
_buildStatRow('正确', '$_correctAnswers', isGreen: true),
_buildStatRow('错误', '$_wrongAnswers', isRed: true),
_buildStatRow(
'正确率',
'${_correctRate.toStringAsFixed(1)}%',
@@ -288,15 +281,8 @@ class _DistinguishPageState extends State<DistinguishPage> {
),
_buildStatRow('提示次数', '$_hintCount'),
_buildStatRow('跳过次数', '$_skipCount'),
Divider(
height: 24,
color: AppColors.divider,
),
_buildStatRow(
'诗词水平',
_poetryLevel,
isHighlight: true,
),
Divider(height: 24, color: AppColors.divider),
_buildStatRow('诗词水平', _poetryLevel, isHighlight: true),
],
),
),
@@ -378,10 +364,7 @@ class _DistinguishPageState extends State<DistinguishPage> {
children: [
Text(
label,
style: TextStyle(
fontSize: 15,
color: AppColors.secondaryText,
),
style: TextStyle(fontSize: 15, color: AppColors.secondaryText),
),
Text(
value,
@@ -453,7 +436,10 @@ $_poetryLevel
builder: (context) => AlertDialog(
backgroundColor: AppColors.surface,
title: Text('确认清空', style: TextStyle(color: AppColors.primaryText)),
content: Text('确定要清空所有答题记录吗?此操作不可恢复。', style: TextStyle(color: AppColors.secondaryText)),
content: Text(
'确定要清空所有答题记录吗?此操作不可恢复。',
style: TextStyle(color: AppColors.secondaryText),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
@@ -500,6 +486,9 @@ $_poetryLevel
Widget build(BuildContext context) {
return Obx(() {
final isDark = _themeController.isDarkMode;
final primaryColor = ThemeColors.getThemeColor(
_themeController.themeColorIndexRx.value,
);
return Scaffold(
appBar: AppBar(
title: Text(
@@ -510,16 +499,13 @@ $_poetryLevel
color: Colors.white,
),
),
backgroundColor: AppColors.primary,
backgroundColor: primaryColor,
foregroundColor: Colors.white,
elevation: 0,
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.primary,
AppColors.primary.withAlpha(180),
],
colors: [primaryColor, primaryColor.withAlpha(180)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
@@ -540,7 +526,7 @@ $_poetryLevel
],
),
body: Container(
color: AppColors.background,
color: isDark ? const Color(0xFF1A1A1A) : AppColors.background,
child: SafeArea(
child: _isLoading
? const Center(child: CircularProgressIndicator())
@@ -577,10 +563,7 @@ $_poetryLevel
const SizedBox(height: 8),
Text(
'快去答题吧!',
style: TextStyle(
fontSize: 14,
color: AppColors.tertiaryText,
),
style: TextStyle(fontSize: 14, color: AppColors.tertiaryText),
),
],
),
@@ -591,195 +574,210 @@ $_poetryLevel
Widget _buildRecordList() {
return Obx(() {
final isDark = _themeController.isDarkMode;
final primaryColor = ThemeColors.getThemeColor(
_themeController.themeColorIndexRx.value,
);
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, primaryColor, isDark);
},
);
});
}
Widget _buildRecordCard(Map<String, dynamic> record, int index) {
Widget _buildRecordCard(
Map<String, dynamic> record,
int index,
Color primaryColor,
bool isDark,
) {
final question = record['question'] ?? '未知题目';
final author = record['author'] ?? '未知作者';
final tags = (record['tags'] as List<dynamic>?)?.cast<String>() ?? [];
final isCorrect = record['isCorrect'] ?? false;
final answerTime = _formatTime(record['answerTime']);
return Obx(() {
final isDark = _themeController.isDarkMode;
return Container(
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: AppColors.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(isDark ? 30 : 10),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: AppColors.primary.withAlpha(20),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
'${index + 1}',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: AppColors.primary,
),
return Container(
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF2A2A2A) : AppColors.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(isDark ? 30 : 10),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: primaryColor.withAlpha(20),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text(
'${index + 1}',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: primaryColor,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
question,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.primaryText,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
'—— $author',
style: TextStyle(
fontSize: 12,
color: AppColors.secondaryText,
fontStyle: FontStyle.italic,
),
),
],
),
),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 4,
),
decoration: BoxDecoration(
color: isCorrect
? AppColors.iosGreen.withAlpha(20)
: AppColors.iosRed.withAlpha(20),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
isCorrect ? Icons.check_circle : Icons.cancel,
size: 14,
color: isCorrect ? AppColors.iosGreen : AppColors.iosRed,
),
const SizedBox(width: 4),
Text(
isCorrect ? '答对' : '答错',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: isCorrect ? AppColors.iosGreen : AppColors.iosRed,
),
),
],
),
),
],
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: tags.isNotEmpty
? Wrap(
spacing: 6,
runSpacing: 6,
children: tags.map((tag) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 3,
),
decoration: BoxDecoration(
color: AppColors.primary.withAlpha(15),
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: AppColors.primary.withAlpha(
50,
),
width: 0.5,
),
),
child: Text(
tag,
style: TextStyle(
fontSize: 11,
color: AppColors.primary,
fontWeight: FontWeight.w500,
),
),
);
}).toList(),
)
: Text(
'暂无标签',
style: TextStyle(
fontSize: 12,
color: AppColors.tertiaryText,
fontStyle: FontStyle.italic,
),
),
),
Row(
mainAxisSize: MainAxisSize.min,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.access_time,
size: 12,
color: AppColors.tertiaryText,
),
const SizedBox(width: 4),
Text(
answerTime,
question,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: isDark
? Colors.grey[300]
: AppColors.primaryText,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
'—— $author',
style: TextStyle(
fontSize: 12,
color: AppColors.secondaryText,
color: isDark
? Colors.grey[500]
: AppColors.secondaryText,
fontStyle: FontStyle.italic,
),
),
],
),
],
),
],
),
),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 4,
),
decoration: BoxDecoration(
color: isCorrect
? AppColors.iosGreen.withAlpha(20)
: AppColors.iosRed.withAlpha(20),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
isCorrect ? Icons.check_circle : Icons.cancel,
size: 14,
color: isCorrect
? AppColors.iosGreen
: AppColors.iosRed,
),
const SizedBox(width: 4),
Text(
isCorrect ? '答对' : '答错',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: isCorrect
? AppColors.iosGreen
: AppColors.iosRed,
),
),
],
),
),
],
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: tags.isNotEmpty
? Wrap(
spacing: 6,
runSpacing: 6,
children: tags.map((tag) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 3,
),
decoration: BoxDecoration(
color: primaryColor.withAlpha(15),
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: primaryColor.withAlpha(50),
width: 0.5,
),
),
child: Text(
tag,
style: TextStyle(
fontSize: 11,
color: primaryColor,
fontWeight: FontWeight.w500,
),
),
);
}).toList(),
)
: Text(
'暂无标签',
style: TextStyle(
fontSize: 12,
color: isDark
? Colors.grey[500]
: AppColors.tertiaryText,
fontStyle: FontStyle.italic,
),
),
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.access_time,
size: 12,
color: isDark ? Colors.grey[500] : AppColors.tertiaryText,
),
const SizedBox(width: 4),
Text(
answerTime,
style: TextStyle(
fontSize: 12,
color: isDark
? Colors.grey[400]
: AppColors.secondaryText,
),
),
],
),
],
),
],
),
);
});
),
);
}
// 写入统计数据到笔记