/// 时间: 2026-04-02 /// 功能: 关怀模式诗词页面 /// 介绍: 关怀模式下显示的诗词页面,根据关怀设置显示不同内容 /// 最新变化: 2026-04-02 初始创建 import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../services/get/home_controller.dart'; 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'; class CarePoetryPage extends StatefulWidget { const CarePoetryPage({super.key}); @override State createState() => _CarePoetryPageState(); } class _CarePoetryPageState extends State with SingleTickerProviderStateMixin { String _getTimeOfDayGreeting() { final hour = DateTime.now().hour; if (hour >= 5 && hour < 7) { return '清晨了,呼吸新鲜空气'; } else if (hour >= 7 && hour < 9) { return '早上好,元气满满'; } else if (hour >= 9 && hour < 12) { return '上午好,努力工作'; } else if (hour >= 12 && hour < 14) { return '中午了,吃顿好的'; } else if (hour >= 14 && hour < 17) { return '下午了,喝杯咖啡'; } else if (hour >= 17 && hour < 19) { return '傍晚了,休息一下'; } else if (hour >= 19 && hour < 22) { return '晚上好,放松身心'; } else { return '深夜了,注意身体'; } } late AnimationController _animationController; late Animation _fadeAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 500), vsync: this, ); _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeOut), ); _animationController.forward(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final homeController = Get.find(); final themeController = Get.find(); final careController = Get.find(); return Obx(() { 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()); } return Scaffold( backgroundColor: isDark ? const Color(0xFF121212) : Colors.grey[50], body: SafeArea( child: GestureDetector( onTap: () async { try { await homeController.loadNextPoetry(); } catch (e) { print('加载诗词失败: $e'); } }, child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: FadeTransition( opacity: _fadeAnimation, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ // 关怀模式开关 CarePageHeaderToggle(isDark: isDark), const SizedBox(height: 16), // 问候语bar if (careController.selectedOptions.contains('问候语')) Container( width: double.infinity, padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), decoration: BoxDecoration( gradient: LinearGradient( colors: [primaryColor.withAlpha(204), primaryColor], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Icon(Icons.wb_sunny, color: Colors.white, size: 20), const SizedBox(width: 8), Expanded( child: Text( _getTimeOfDayGreeting(), style: const TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500, ), overflow: TextOverflow.ellipsis, maxLines: 1, ), ), ], ), ), if (careController.selectedOptions.contains('问候语')) const SizedBox(height: 16), // 出处 if (careController.selectedOptions.contains('出处')) _buildPoetrySource( poetryData, isDark, primaryColor, isLoadingNext, ), if (careController.selectedOptions.contains('出处')) const SizedBox(height: 24), if (!careController.selectedOptions.contains('问候语') && !careController.selectedOptions.contains('出处')) const SizedBox(height: 24), // 诗词标题 if (careController.selectedOptions.contains('诗词')) _buildPoetryTitle( poetryData, isDark, primaryColor, isLoadingNext, ), const SizedBox(height: 24), // 诗词内容 if (careController.selectedOptions.contains('诗词')) GestureDetector( onTap: () async { try { await homeController.loadNextPoetry(); } catch (e) { print('加载诗词失败: $e'); } }, child: _buildPoetryContent( poetryData, isDark, primaryColor, isLoadingNext, ), ), const SizedBox(height: 24), // 原文 if (careController.selectedOptions.contains('原文')) _buildPoetryOriginal(poetryData, isDark, primaryColor), if (careController.selectedOptions.contains('原文')) const SizedBox(height: 24), const SizedBox(height: 24), // 译文 if (careController.selectedOptions.contains('译文')) _buildPoetryTranslation( poetryData, isDark, primaryColor, isLoadingNext, ), const SizedBox(height: 24), // 更多 if (careController.selectedOptions.contains('更多')) _buildPoetryMore( poetryData, isDark, primaryColor, isLoadingNext, ), const SizedBox(height: 48), ], ), ), ), ), ), ); }); } Widget _buildPoetryTitle( 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: 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, ), ); } Widget _buildPoetryContent( dynamic poetryData, bool isDark, Color primaryColor, bool isLoading, ) { final themeController = Get.find(); final careController = Get.find(); final accentColor = themeController.currentAccentColor; 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), decoration: BoxDecoration( color: isDark ? accentColor.withOpacity(0.2) : accentColor.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: isLoading ? Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ 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((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((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(( 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(), ), ); } Widget _buildPoetrySource( 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), decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], borderRadius: BorderRadius.circular(12), ), 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, ), ); } Widget _buildPoetryTranslation( 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), decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], borderRadius: BorderRadius.circular(12), ), 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, 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: 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, ), ], ), ); } Widget _buildPoetryOriginal( dynamic poetryData, bool isDark, Color primaryColor, ) { final original = poetryData.drtime ?? '暂无原文'; final careController = Get.find(); final showPinyin = careController.pinyinEnabled; final lines = original.split('\n'); return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: lines.asMap().entries.map((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((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: 16, color: primaryColor, height: 1.6, ), textAlign: TextAlign.center, ), ], ), ), ); }) .toList(), ), if (!showPinyin || line.trim().isEmpty) Text( line, style: TextStyle( fontSize: 16, color: primaryColor, height: 1.6, ), textAlign: TextAlign.center, ), ], ), ); }).toList(), ), ); } }