feat: 诗词答题页面主题色支持与代码重构
- 创建 poetry-page.dart,提取 UI 组件(PoetryOptionItem、PoetryOptionsLayout、PoetryTag) - 修改 poetry.dart,使用新组件,添加主题色支持 - 修改 flow-anim.dart,添加主题色支持 - 修改 distinguish.dart,添加主题色支持 - 支持动态主题色切换 - 支持深色模式 - 保持页面布局不变
This commit is contained in:
@@ -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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 写入统计数据到笔记
|
||||
|
||||
Reference in New Issue
Block a user