This commit is contained in:
Developer
2026-04-03 03:26:06 +08:00
parent 3063deb34c
commit cba04235c8
49 changed files with 3955 additions and 1421 deletions

View File

@@ -30,7 +30,7 @@ class _CarePageState extends State<CarePage> {
backgroundColor: isDark ? const Color(0xFF121212) : Colors.white,
appBar: AppBar(
title: Text(
'关怀',
'关怀 Beta',
style: TextStyle(
color: isDark ? Colors.white : primaryColor,
fontWeight: FontWeight.bold,
@@ -183,27 +183,31 @@ class _CarePageState extends State<CarePage> {
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: _buildUserTypeButton(
'儿童',
_careController.userType == '儿童',
isDark,
primaryColor,
Obx(() {
final themeController = Get.find<ThemeController>();
final currentPrimaryColor = themeController.currentThemeColor;
return Row(
children: [
Expanded(
child: _buildUserTypeButton(
'儿童',
_careController.userType == '儿童',
isDark,
currentPrimaryColor,
),
),
),
const SizedBox(width: 16),
Expanded(
child: _buildUserTypeButton(
'学生',
_careController.userType == '学生',
isDark,
primaryColor,
const SizedBox(width: 16),
Expanded(
child: _buildUserTypeButton(
'学生',
_careController.userType == '学生',
isDark,
currentPrimaryColor,
),
),
),
],
),
],
);
}),
const SizedBox(height: 16),
Container(
width: double.infinity,

View File

@@ -10,6 +10,7 @@ import '../../../services/get/theme_controller.dart';
import '../../../services/get/care_controller.dart';
import '../../../constants/app_constants.dart';
import '../home_part.dart';
import '../components/skeleton_widgets.dart';
import 'care_widgets.dart';
import 'pinyin_helper.dart';
@@ -75,15 +76,18 @@ class _CarePoetryPageState extends State<CarePoetryPage>
final isDark = themeController.isDarkModeRx.value;
final primaryColor = themeController.currentThemeColor;
final poetryData = homeController.poetryData.value;
final isLoadingNext = homeController.isLoadingNext.value;
// 当诗词数据变化时,重新播放动画
if (!isLoadingNext) {
_animationController.reset();
_animationController.forward();
}
if (poetryData == null) {
return const Center(child: CircularProgressIndicator());
}
// 当诗词数据变化时,重新播放动画
_animationController.reset();
_animationController.forward();
return Scaffold(
backgroundColor: isDark ? const Color(0xFF121212) : Colors.grey[50],
body: SafeArea(
@@ -144,7 +148,12 @@ class _CarePoetryPageState extends State<CarePoetryPage>
const SizedBox(height: 16),
// 出处
if (careController.selectedOptions.contains('出处'))
_buildPoetrySource(poetryData, isDark, primaryColor),
_buildPoetrySource(
poetryData,
isDark,
primaryColor,
isLoadingNext,
),
if (careController.selectedOptions.contains('出处'))
const SizedBox(height: 24),
if (!careController.selectedOptions.contains('问候语') &&
@@ -152,7 +161,12 @@ class _CarePoetryPageState extends State<CarePoetryPage>
const SizedBox(height: 24),
// 诗词标题
if (careController.selectedOptions.contains('诗词'))
_buildPoetryTitle(poetryData, isDark, primaryColor),
_buildPoetryTitle(
poetryData,
isDark,
primaryColor,
isLoadingNext,
),
const SizedBox(height: 24),
@@ -170,6 +184,7 @@ class _CarePoetryPageState extends State<CarePoetryPage>
poetryData,
isDark,
primaryColor,
isLoadingNext,
),
),
@@ -186,13 +201,23 @@ class _CarePoetryPageState extends State<CarePoetryPage>
// 译文
if (careController.selectedOptions.contains('译文'))
_buildPoetryTranslation(poetryData, isDark, primaryColor),
_buildPoetryTranslation(
poetryData,
isDark,
primaryColor,
isLoadingNext,
),
const SizedBox(height: 24),
// 更多
if (careController.selectedOptions.contains('更多'))
_buildPoetryMore(poetryData, isDark, primaryColor),
_buildPoetryMore(
poetryData,
isDark,
primaryColor,
isLoadingNext,
),
const SizedBox(height: 48),
],
@@ -209,22 +234,48 @@ class _CarePoetryPageState extends State<CarePoetryPage>
dynamic poetryData,
bool isDark,
Color primaryColor,
bool isLoading,
) {
final baseColor = isDark ? const Color(0xFF3A3A3A) : Colors.grey[300];
final highlightColor = isDark ? const Color(0xFF4A4A4A) : Colors.grey[100];
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100],
borderRadius: BorderRadius.circular(12),
),
child: Text(
poetryData.name ?? '未知标题',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: primaryColor,
),
textAlign: TextAlign.center,
),
child: isLoading
? Center(
child: Column(
children: [
SkeletonContainer(
width: 180,
height: 32,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
const SizedBox(height: 8),
SkeletonContainer(
width: 120,
height: 20,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
],
),
)
: Text(
poetryData.name ?? '未知标题',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: primaryColor,
),
textAlign: TextAlign.center,
),
);
}
@@ -232,6 +283,7 @@ class _CarePoetryPageState extends State<CarePoetryPage>
dynamic poetryData,
bool isDark,
Color primaryColor,
bool isLoading,
) {
final themeController = Get.find<ThemeController>();
final careController = Get.find<CareController>();
@@ -239,6 +291,8 @@ class _CarePoetryPageState extends State<CarePoetryPage>
final content = poetryData.name ?? '';
final lines = content.split('\n');
final showPinyin = careController.pinyinEnabled;
final baseColor = isDark ? const Color(0xFF3A3A3A) : Colors.grey[300];
final highlightColor = isDark ? const Color(0xFF4A4A4A) : Colors.grey[100];
return Container(
padding: const EdgeInsets.all(16),
@@ -248,95 +302,128 @@ class _CarePoetryPageState extends State<CarePoetryPage>
: accentColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: lines.asMap().entries.map<Widget>((entry) {
int index = entry.key;
String line = entry.value;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Column(
child: isLoading
? Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (showPinyin && line.trim().isNotEmpty)
Wrap(
alignment: WrapAlignment.center,
children: PinyinHelper.convertToCharPinyinList(line)
.asMap()
.entries
.map<Widget>((charEntry) {
int charIndex = charEntry.key;
var item = charEntry.value;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: AnimatedOpacity(
opacity: 1.0,
duration: Duration(
milliseconds: 300 + charIndex * 100,
),
curve: Curves.easeOut,
child: Column(
children: [
Text(
item['pinyin'] ?? '',
style: TextStyle(
fontSize: 12,
color: isDark
? Colors.grey[400]
: Colors.grey[600],
height: 1.2,
),
textAlign: TextAlign.center,
),
Text(
item['char'] ?? '',
style: TextStyle(
fontSize: 20,
color: primaryColor,
height: 1.6,
),
textAlign: TextAlign.center,
),
],
),
),
);
})
.toList(),
),
if (!showPinyin || line.trim().isEmpty)
Wrap(
alignment: WrapAlignment.center,
children: line.split('').asMap().entries.map<Widget>((
charEntry,
) {
int charIndex = charEntry.key;
String char = charEntry.value;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: AnimatedOpacity(
opacity: 1.0,
duration: Duration(
milliseconds: 300 + charIndex * 100,
),
curve: Curves.easeOut,
child: Text(
char,
style: TextStyle(
fontSize: 20,
color: primaryColor,
height: 1.6,
),
textAlign: TextAlign.center,
),
),
);
}).toList(),
),
SkeletonContainer(
width: double.infinity,
height: 28,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
const SizedBox(height: 12),
SkeletonContainer(
width: double.infinity,
height: 28,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
const SizedBox(height: 12),
SkeletonContainer(
width: 200,
height: 28,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: lines.asMap().entries.map<Widget>((entry) {
int index = entry.key;
String line = entry.value;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Column(
children: [
if (showPinyin && line.trim().isNotEmpty)
Wrap(
alignment: WrapAlignment.center,
children: PinyinHelper.convertToCharPinyinList(line)
.asMap()
.entries
.map<Widget>((charEntry) {
int charIndex = charEntry.key;
var item = charEntry.value;
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 4,
),
child: AnimatedOpacity(
opacity: 1.0,
duration: Duration(
milliseconds: 300 + charIndex * 100,
),
curve: Curves.easeOut,
child: Column(
children: [
Text(
item['pinyin'] ?? '',
style: TextStyle(
fontSize: 12,
color: isDark
? Colors.grey[400]
: Colors.grey[600],
height: 1.2,
),
textAlign: TextAlign.center,
),
Text(
item['char'] ?? '',
style: TextStyle(
fontSize: 20,
color: primaryColor,
height: 1.6,
),
textAlign: TextAlign.center,
),
],
),
),
);
})
.toList(),
),
if (!showPinyin || line.trim().isEmpty)
Wrap(
alignment: WrapAlignment.center,
children: line.split('').asMap().entries.map<Widget>((
charEntry,
) {
int charIndex = charEntry.key;
String char = charEntry.value;
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 4,
),
child: AnimatedOpacity(
opacity: 1.0,
duration: Duration(
milliseconds: 300 + charIndex * 100,
),
curve: Curves.easeOut,
child: Text(
char,
style: TextStyle(
fontSize: 20,
color: primaryColor,
height: 1.6,
),
textAlign: TextAlign.center,
),
),
);
}).toList(),
),
],
),
);
}).toList(),
),
);
}).toList(),
),
);
}
@@ -344,8 +431,11 @@ class _CarePoetryPageState extends State<CarePoetryPage>
dynamic poetryData,
bool isDark,
Color primaryColor,
bool isLoading,
) {
final url = poetryData.url ?? '未知作者';
final baseColor = isDark ? const Color(0xFF3A3A3A) : Colors.grey[300];
final highlightColor = isDark ? const Color(0xFF4A4A4A) : Colors.grey[100];
return Container(
padding: const EdgeInsets.all(16),
@@ -353,15 +443,25 @@ class _CarePoetryPageState extends State<CarePoetryPage>
color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100],
borderRadius: BorderRadius.circular(12),
),
child: Text(
url,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: primaryColor,
),
textAlign: TextAlign.center,
),
child: isLoading
? Center(
child: SkeletonContainer(
width: 200,
height: 24,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
)
: Text(
url,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: primaryColor,
),
textAlign: TextAlign.center,
),
);
}
@@ -369,8 +469,11 @@ class _CarePoetryPageState extends State<CarePoetryPage>
dynamic poetryData,
bool isDark,
Color primaryColor,
bool isLoading,
) {
final translation = poetryData.introduce ?? '暂无译文';
final baseColor = isDark ? const Color(0xFF3A3A3A) : Colors.grey[300];
final highlightColor = isDark ? const Color(0xFF4A4A4A) : Colors.grey[100];
return Container(
padding: const EdgeInsets.all(16),
@@ -378,46 +481,118 @@ class _CarePoetryPageState extends State<CarePoetryPage>
color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100],
borderRadius: BorderRadius.circular(12),
),
child: Text(
translation,
style: TextStyle(
fontSize: 16,
color: isDark ? Colors.grey[300] : Colors.grey[700],
height: 1.6,
),
textAlign: TextAlign.center,
),
child: isLoading
? Column(
children: [
SkeletonContainer(
width: 100,
height: 20,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
const SizedBox(height: 12),
SkeletonContainer(
width: double.infinity,
height: 16,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
const SizedBox(height: 8),
SkeletonContainer(
width: double.infinity,
height: 16,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
const SizedBox(height: 8),
SkeletonContainer(
width: 200,
height: 16,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
],
)
: Text(
translation,
style: TextStyle(
fontSize: 16,
color: isDark ? Colors.grey[300] : Colors.grey[700],
height: 1.6,
),
textAlign: TextAlign.center,
),
);
}
Widget _buildPoetryMore(dynamic poetryData, bool isDark, Color primaryColor) {
Widget _buildPoetryMore(
dynamic poetryData,
bool isDark,
Color primaryColor,
bool isLoading,
) {
final baseColor = isDark ? const Color(0xFF3A3A3A) : Colors.grey[300];
final highlightColor = isDark ? const Color(0xFF4A4A4A) : Colors.grey[100];
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100],
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
Text(
'更多信息',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: primaryColor,
child: isLoading
? Column(
children: [
SkeletonContainer(
width: 120,
height: 22,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
const SizedBox(height: 12),
SkeletonContainer(
width: double.infinity,
height: 14,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
const SizedBox(height: 8),
SkeletonContainer(
width: 250,
height: 14,
borderRadius: 4,
baseColor: baseColor,
highlightColor: highlightColor,
),
],
)
: Column(
children: [
Text(
'更多信息',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: primaryColor,
),
),
const SizedBox(height: 12),
Text(
'诗词解析、背景知识等内容将在此显示',
style: TextStyle(
fontSize: 14,
color: isDark ? Colors.grey[300] : Colors.grey[700],
),
textAlign: TextAlign.center,
),
],
),
),
const SizedBox(height: 12),
Text(
'诗词解析、背景知识等内容将在此显示',
style: TextStyle(
fontSize: 14,
color: isDark ? Colors.grey[300] : Colors.grey[700],
),
textAlign: TextAlign.center,
),
],
),
);
}

View File

@@ -61,30 +61,30 @@ class CareModeToggle extends StatelessWidget {
final themeController = Get.find<ThemeController>();
final primaryColor = themeController.currentThemeColor;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
margin: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(isDark ? 40 : 20),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(Icons.people, color: primaryColor, size: 20),
const SizedBox(width: 12),
GestureDetector(
onTap: () => Get.to(() => const CarePage()),
child: Text(
return GestureDetector(
onTap: () => Get.to(() => const CarePage()),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
margin: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(isDark ? 40 : 20),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(Icons.people, color: primaryColor, size: 20),
const SizedBox(width: 12),
Text(
'关怀',
style: TextStyle(
fontSize: 16,
@@ -92,16 +92,21 @@ class CareModeToggle extends StatelessWidget {
color: isDark ? Colors.white : Colors.black,
),
),
],
),
GestureDetector(
onTap: onToggle,
child: Switch(
value: isEnabled,
onChanged: (_) => onToggle(),
activeColor: primaryColor,
inactiveTrackColor: isDark
? Colors.grey[700]
: Colors.grey[300],
),
],
),
Switch(
value: isEnabled,
onChanged: (_) => onToggle(),
activeColor: primaryColor,
inactiveTrackColor: isDark ? Colors.grey[700] : Colors.grey[300],
),
],
),
],
),
),
);
}