关怀模式

This commit is contained in:
Developer
2026-04-02 22:30:49 +08:00
parent 09fee0694c
commit 7872f2e78a
70 changed files with 4884 additions and 2752 deletions

View File

@@ -1,10 +1,15 @@
/// 时间: 2026-03-28
/// 功能: 诗词答题页面
/// 介绍: 基于 API 接口实现的诗词答题系统,支持获取题目、提交答案、获取提示
/// 最新变化: 添加自动加载下一题开关,隐藏提示标签,使用独立逻辑管理器,支持主题色设置
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../constants/app_constants.dart';
import '../../../models/colors/app_colors.dart';
import '../../../controllers/shared_preferences_storage_controller.dart';
import '../../../services/get/theme_controller.dart';
import '../guide/tongji.dart';
@@ -13,11 +18,6 @@ import 'flow-anim.dart';
import 'distinguish.dart';
import '../settings/offline-data.dart';
/// 时间: 2026-03-28
/// 功能: 诗词答题页面
/// 介绍: 基于 API 接口实现的诗词答题系统,支持获取题目、提交答案、获取提示
/// 最新变化: 添加自动加载下一题开关,隐藏提示标签,使用独立逻辑管理器
class PoetryLevelPage extends StatefulWidget {
const PoetryLevelPage({super.key});
@@ -137,7 +137,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(initResult.message ?? '已加载离线缓存'),
backgroundColor: AppConstants.primaryColor,
backgroundColor: AppColors.primary,
duration: const Duration(seconds: 2),
),
);
@@ -153,14 +153,15 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('提示'),
content: const Text('当前无网络连接且无离线缓存数据,请先下载数据或检查网络设置。'),
backgroundColor: AppColors.surface,
title: Text('提示', style: TextStyle(color: AppColors.primaryText)),
content: Text('当前无网络连接且无离线缓存数据,请先下载数据或检查网络设置。', style: TextStyle(color: AppColors.secondaryText)),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('取消'),
child: Text('取消', style: TextStyle(color: AppColors.primary)),
),
TextButton(
onPressed: () {
@@ -171,7 +172,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
MaterialPageRoute(builder: (_) => const OfflineDataPage()),
);
},
child: const Text('去下载'),
child: Text('去下载', style: TextStyle(color: AppColors.primary)),
),
],
);
@@ -464,7 +465,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: AppConstants.primaryColor.withAlpha(20),
color: AppColors.primary.withAlpha(20),
borderRadius: BorderRadius.circular(4),
),
child: Column(
@@ -474,7 +475,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
label,
style: TextStyle(
fontSize: 10,
color: AppConstants.primaryColor,
color: AppColors.primary,
fontWeight: FontWeight.w600,
),
),
@@ -482,7 +483,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
value,
style: TextStyle(
fontSize: 12,
color: Colors.black87,
color: AppColors.primaryText,
fontWeight: FontWeight.w500,
),
),
@@ -500,150 +501,152 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
final isWrong =
_showFeedback && !_isAnswerCorrect && _selectedAnswer == optionNum;
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
child: Container(
decoration: BoxDecoration(
gradient: isSelected
? LinearGradient(
colors: isCorrect
? [Colors.green[400]!, Colors.green[300]!]
: isWrong
? [Colors.red[400]!, Colors.red[300]!]
: [
AppConstants.primaryColor,
AppConstants.primaryColor.withAlpha(200),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
color: isSelected ? null : Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isSelected
? Colors.transparent
: AppConstants.primaryColor.withAlpha(50),
width: 2,
),
boxShadow: isSelected
? [
BoxShadow(
color:
(isCorrect
? Colors.green
: isWrong
? Colors.red
: AppConstants.primaryColor)
.withAlpha(80),
blurRadius: 12,
offset: const Offset(0, 4),
),
]
: [
BoxShadow(
color: Colors.black.withAlpha(5),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: _isSubmitting || (_showFeedback && _isAnswerCorrect)
? null
: () {
if (_showFeedback) {
// 重置状态,允许重新选择
setState(() {
_showFeedback = false;
_selectedAnswer = null;
_feedbackMessage = null;
});
}
_submitAnswer(optionNum);
},
return Obx(() {
final isDark = _themeController.isDarkMode;
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
child: Container(
decoration: BoxDecoration(
gradient: isSelected
? LinearGradient(
colors: isCorrect
? [AppColors.iosGreen, AppColors.iosGreen.withAlpha(200)]
: isWrong
? [AppColors.iosRed, AppColors.iosRed.withAlpha(200)]
: [
AppColors.primary,
AppColors.primary.withAlpha(200),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
color: isSelected ? null : AppColors.surface,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 300),
width: 32,
height: 32,
decoration: BoxDecoration(
gradient: isSelected
? LinearGradient(
colors: isCorrect
? [Colors.white, Colors.white.withAlpha(230)]
: isWrong
? [Colors.white, Colors.white.withAlpha(230)]
: [Colors.white, Colors.white.withAlpha(230)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
color: isSelected
? null
: AppConstants.primaryColor.withAlpha(20),
shape: BoxShape.circle,
boxShadow: isSelected
? [
BoxShadow(
color: Colors.black.withAlpha(20),
blurRadius: 4,
offset: const Offset(0, 2),
),
]
: null,
border: Border.all(
color: isSelected
? Colors.transparent
: AppColors.primary.withAlpha(50),
width: 2,
),
boxShadow: isSelected
? [
BoxShadow(
color: (isCorrect
? AppColors.iosGreen
: isWrong
? AppColors.iosRed
: AppColors.primary)
.withAlpha(80),
blurRadius: 12,
offset: const Offset(0, 4),
),
child: Center(
child: Text(
'$optionNum',
style: TextStyle(
color: isSelected
? (isCorrect
? Colors.green
]
: [
BoxShadow(
color: Colors.black.withAlpha(isDark ? 10 : 5),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: _isSubmitting || (_showFeedback && _isAnswerCorrect)
? null
: () {
if (_showFeedback) {
// 重置状态,允许重新选择
setState(() {
_showFeedback = false;
_selectedAnswer = null;
_feedbackMessage = null;
});
}
_submitAnswer(optionNum);
},
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 300),
width: 32,
height: 32,
decoration: BoxDecoration(
gradient: isSelected
? LinearGradient(
colors: isCorrect
? [Colors.white, Colors.white.withAlpha(230)]
: isWrong
? Colors.red
: AppConstants.primaryColor)
: AppConstants.primaryColor,
fontWeight: FontWeight.bold,
fontSize: 16,
? [Colors.white, Colors.white.withAlpha(230)]
: [Colors.white, Colors.white.withAlpha(230)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
color: isSelected
? null
: AppColors.primary.withAlpha(20),
shape: BoxShape.circle,
boxShadow: isSelected
? [
BoxShadow(
color: Colors.black.withAlpha(20),
blurRadius: 4,
offset: const Offset(0, 2),
),
]
: null,
),
child: Center(
child: Text(
'$optionNum',
style: TextStyle(
color: isSelected
? (isCorrect
? AppColors.iosGreen
: isWrong
? AppColors.iosRed
: AppColors.primary)
: AppColors.primary,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
),
),
const SizedBox(width: 16),
Expanded(
child: Text(
option['content'] ?? option['text'] ?? '',
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500,
color: isSelected ? Colors.white : Colors.black87,
const SizedBox(width: 16),
Expanded(
child: Text(
option['content'] ?? option['text'] ?? '',
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500,
color: isSelected ? Colors.white : AppColors.primaryText,
),
),
),
),
if (isSelected)
Icon(
isCorrect
? Icons.check_circle
: isWrong
? Icons.cancel
: Icons.radio_button_checked,
color: Colors.white,
size: 28,
),
],
if (isSelected)
Icon(
isCorrect
? Icons.check_circle
: isWrong
? Icons.cancel
: Icons.radio_button_checked,
color: Colors.white,
size: 28,
),
],
),
),
),
),
),
),
);
);
});
}
@override
@@ -660,15 +663,15 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
color: Colors.white,
),
),
backgroundColor: AppConstants.primaryColor,
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
elevation: 0,
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppConstants.primaryColor,
AppConstants.primaryColor.withAlpha(180),
AppColors.primary,
AppColors.primary.withAlpha(180),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
@@ -707,7 +710,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
],
),
body: Container(
color: isDark ? const Color(0xFF1A1A1A) : Colors.white,
color: AppColors.background,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.only(
@@ -737,8 +740,8 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppConstants.primaryColor,
AppConstants.primaryColor.withAlpha(200),
AppColors.primary,
AppColors.primary.withAlpha(200),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
@@ -746,7 +749,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: AppConstants.primaryColor.withAlpha(
color: AppColors.primary.withAlpha(
80,
),
blurRadius: 12,
@@ -841,7 +844,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
children: [
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
AppConstants.primaryColor,
AppColors.primary,
),
strokeWidth: 3,
),
@@ -850,9 +853,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
'加载题目中...',
style: TextStyle(
fontSize: 16,
color: isDark
? Colors.grey[400]
: Colors.grey,
color: AppColors.tertiaryText,
),
),
],
@@ -870,14 +871,14 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: isDark
? Colors.red[900]!.withAlpha(30)
: Colors.red[50],
? AppColors.iosRed.withAlpha(30)
: AppColors.iosRed.withAlpha(10),
shape: BoxShape.circle,
),
child: Icon(
Icons.error_outline,
size: 64,
color: Colors.red[400],
color: AppColors.iosRed,
),
),
const SizedBox(height: 24),
@@ -886,9 +887,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: isDark
? Colors.red[300]
: Colors.red,
color: AppColors.iosRed,
),
),
const SizedBox(height: 32),
@@ -896,8 +895,8 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppConstants.primaryColor,
AppConstants.primaryColor.withAlpha(
AppColors.primary,
AppColors.primary.withAlpha(
200,
),
],
@@ -905,7 +904,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: AppConstants.primaryColor
color: AppColors.primary
.withAlpha(80),
blurRadius: 8,
offset: const Offset(0, 4),
@@ -967,15 +966,9 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
BorderRadius.circular(
16,
),
color: isDark
? const Color(
0xFF2A2A2A,
)
: Colors.white,
color: AppColors.surface,
),
),
color: AppConstants
.primaryColor,
width: 4,
),
),
@@ -986,19 +979,10 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
isDark
? const Color(
0xFF2A2A2A,
)
: Colors.white,
AppConstants
.primaryColor
AppColors.surface,
AppColors.primary
.withAlpha(5),
isDark
? const Color(
0xFF2A2A2A,
)
: Colors.white,
AppColors.surface,
],
begin: Alignment.topLeft,
end:
@@ -1023,8 +1007,8 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
width: 4,
height: 20,
decoration: BoxDecoration(
color: AppConstants
.primaryColor,
color: AppColors
.primary,
borderRadius:
BorderRadius.circular(
2,
@@ -1041,8 +1025,8 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
fontWeight:
FontWeight
.w600,
color: AppConstants
.primaryColor,
color: AppColors
.primary,
),
),
],
@@ -1058,9 +1042,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
fontWeight:
FontWeight.bold,
height: 1.5,
color: isDark
? Colors.white
: Colors.black87,
color: AppColors.primaryText,
),
),
// 标签信息
@@ -1082,8 +1064,8 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
12,
),
decoration: BoxDecoration(
color: AppConstants
.primaryColor
color: AppColors
.primary
.withAlpha(
10,
),
@@ -1141,7 +1123,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
color: AppColors.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
@@ -1162,8 +1144,8 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.white,
Colors.grey[50]!,
AppColors.surface,
AppColors.background,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
@@ -1171,7 +1153,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
borderRadius:
BorderRadius.circular(12),
border: Border.all(
color: AppConstants.primaryColor
color: AppColors.primary
.withAlpha(50),
width: 1,
),
@@ -1195,18 +1177,18 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
children: [
Icon(
Icons.arrow_back,
color: AppConstants
.primaryColor,
color: AppColors
.primary,
size: 20,
),
const SizedBox(width: 8),
const Text(
Text(
'上一题',
style: TextStyle(
fontSize: 14,
fontWeight:
FontWeight.w500,
color: Colors.black87,
color: AppColors.primaryText,
),
),
],
@@ -1221,24 +1203,20 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.white,
Colors.grey[50]!,
AppColors.primary,
AppColors.primary.withAlpha(
200,
),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius:
BorderRadius.circular(12),
border: Border.all(
color:
AppConstants.primaryColor,
width: 2,
),
boxShadow: [
BoxShadow(
color: AppConstants
.primaryColor
.withAlpha(30),
color: AppColors.primary
.withAlpha(80),
blurRadius: 8,
offset: const Offset(0, 4),
),
@@ -1247,8 +1225,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
child: ElevatedButton(
onPressed: _getHint,
style: ElevatedButton.styleFrom(
backgroundColor:
Colors.transparent,
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
padding:
const EdgeInsets.symmetric(
@@ -1263,10 +1240,9 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(
const Icon(
Icons.lightbulb_outline,
color: AppConstants
.primaryColor,
color: Colors.white,
size: 20,
),
const SizedBox(width: 8),
@@ -1275,8 +1251,8 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
style: TextStyle(
fontSize: 14,
fontWeight:
FontWeight.w600,
color: Colors.black87,
FontWeight.w500,
color: Colors.white,
),
),
],
@@ -1291,31 +1267,24 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppConstants.primaryColor,
AppConstants.primaryColor
.withAlpha(200),
AppColors.surface,
AppColors.background,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius:
BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: AppConstants
.primaryColor
.withAlpha(80),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
border: Border.all(
color: AppColors.primary
.withAlpha(50),
width: 1,
),
),
child: ElevatedButton(
child: OutlinedButton(
onPressed: _nextQuestion,
style: ElevatedButton.styleFrom(
backgroundColor:
Colors.transparent,
shadowColor: Colors.transparent,
style: OutlinedButton.styleFrom(
side: BorderSide.none,
padding:
const EdgeInsets.symmetric(
vertical: 14,
@@ -1329,19 +1298,20 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
mainAxisAlignment:
MainAxisAlignment.center,
children: [
const Text(
Text(
'下一题',
style: TextStyle(
fontSize: 14,
fontWeight:
FontWeight.w600,
color: Colors.white,
FontWeight.w500,
color: AppColors.primaryText,
),
),
const SizedBox(width: 8),
Icon(
Icons.arrow_forward,
color: Colors.white,
color: AppColors
.primary,
size: 20,
),
],
@@ -1351,6 +1321,38 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
),
],
),
if (_showFeedback && _feedbackMessage != null)
Padding(
padding: const EdgeInsets.only(top: 16),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: _isAnswerCorrect
? AppColors.iosGreen
.withAlpha(20)
: AppColors.iosRed
.withAlpha(20),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: _isAnswerCorrect
? AppColors.iosGreen
: AppColors.iosRed,
width: 1,
),
),
child: Text(
_feedbackMessage!,
style: TextStyle(
color: _isAnswerCorrect
? AppColors.iosGreen
: AppColors.iosRed,
fontSize: 14,
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.center,
),
),
),
],
),
),
@@ -1359,65 +1361,6 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
),
],
),
// 反馈信息气泡(不占用布局)
if (_showFeedback && _feedbackMessage != null)
Positioned(
top: 0,
left: 16,
right: 16,
child: AnimatedContainer(
duration: const Duration(milliseconds: 500),
curve: Curves.easeOut,
transform: Matrix4.translationValues(0, 0, 0),
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 12,
),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: _isAnswerCorrect
? [Colors.green[400]!, Colors.green[300]!]
: [Colors.orange[400]!, Colors.orange[300]!],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color:
(_isAnswerCorrect
? Colors.green
: Colors.orange)
.withAlpha(80),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
child: Row(
children: [
Icon(
_isAnswerCorrect
? Icons.celebration
: Icons.lightbulb_outline,
color: Colors.white,
size: 24,
),
const SizedBox(width: 12),
Expanded(
child: Text(
_feedbackMessage!,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
],
),
),
),
],
),
),