Files
wushu/lib/views/home/home_page.dart
Developer d6ac0ed1e4 重构
2026-03-31 05:42:47 +08:00

856 lines
26 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// 时间: 2025-03-22
/// 功能: 诗词主页(参考微信小程序布局)
/// 介绍: 展示诗词内容支持点赞、收藏、分享等功能参考wxpm小程序的index页面布局
/// 最新变化: 2025-03-22 重构代码结构,使用组件化架构简化代码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../constants/app_constants.dart';
import '../../../controllers/history_controller.dart';
import '../../../utils/http/poetry_api.dart';
import '../../../services/network_listener_service.dart';
import '../../../utils/audio_manager.dart';
import 'home_part.dart';
import 'home_components.dart';
import 'home-load.dart';
import '../profile/guide/tongji.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with TickerProviderStateMixin, NetworkListenerMixin {
PoetryData? _poetryData;
List<String> _keywordList = [];
bool _loading = false;
bool _isLiked = false;
bool _isLoadingLike = false;
String _errorMessage = '';
String _starDisplay = '';
List<Map<String, dynamic>> _historyList = [];
int _currentHistoryIndex = -1;
late AnimationController _fadeController;
late AnimationController _slideController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
// 动态加载状态
bool _isLoadingNext = false;
Map<String, bool> _sectionLoadingStates = {
'title': false,
'content': false,
'name': false,
'keywords': false,
'introduction': false,
};
@override
void initState() {
super.initState();
_initAnimations();
_loadHistory();
_initAutoRefresh();
_initDebugInfo();
_initOfflineDataManager();
_initAudioManager();
// 延迟加载诗词,确保页面先显示
WidgetsBinding.instance.addPostFrameCallback((_) {
_loadPoetry();
});
}
Future<void> _initAudioManager() async {
await AudioManager().init();
}
Future<void> _initOfflineDataManager() async {
final offlineDataManager = OfflineDataManager();
await offlineDataManager.init();
}
Future<void> _initAutoRefresh() async {
final autoRefreshManager = AutoRefreshManager();
await autoRefreshManager.init();
autoRefreshManager.setOnRefresh(() {
if (mounted) {
_loadNextPoetry();
}
});
if (autoRefreshManager.isEnabled) {
autoRefreshManager.setEnabled(true);
}
}
Future<void> _initDebugInfo() async {
final debugInfoManager = DebugInfoManager();
await debugInfoManager.init();
}
void _initAnimations() {
_fadeController = AnimationUtils.createFadeController(this);
_slideController = AnimationUtils.createSlideController(this);
_fadeAnimation = AnimationUtils.createFadeAnimation(_fadeController);
_slideAnimation = AnimationUtils.createSlideAnimation(_slideController);
}
@override
void dispose() {
_fadeController.dispose();
_slideController.dispose();
// 只停止定时器,不释放单例资源
AutoRefreshManager().stopTimer();
// 不调用DebugInfoManager的dispose因为它是单例其他页面可能还在使用
super.dispose();
}
Future<void> _loadPoetry() async {
if (_loading) return;
setState(() => _loading = true);
PoetryStateManager.triggerHapticFeedback();
try {
final offlineDataManager = OfflineDataManager();
final isOnline = await offlineDataManager.isOnline();
final hasCachedData = await offlineDataManager.hasCachedData();
if (isOnline) {
// 在线状态:从网络加载
final response = await PoetryApi.getRandomPoetry();
if (mounted && response.data != null) {
// 记录浏览统计
try {
await StatisticsManager().recordView();
await StatisticsManager().recordFirstUse();
await StatisticsManager().recordTotalView();
} catch (e) {
// 忽略错误
}
setState(() {
_poetryData = response.data;
_keywordList = PoetryDataUtils.extractKeywords(response.data);
_starDisplay = PoetryDataUtils.getStarDisplay(response.data);
_isLiked = false;
_loading = false;
_errorMessage = '';
});
_fadeController.forward();
_slideController.forward();
_checkIfLiked();
await _saveToHistory(response.data!);
DebugInfoManager().showRefreshSuccess();
} else {
// 数据为空时,显示默认内容
if (mounted) {
setState(() {
_poetryData = _createDefaultPoetryData();
_keywordList = [];
_starDisplay = '⭐⭐⭐⭐⭐';
_isLiked = false;
_loading = false;
_errorMessage = '';
});
_fadeController.forward();
_slideController.forward();
}
DebugInfoManager().showRefreshFailed();
}
} else {
// 离线状态:从本地缓存加载
if (hasCachedData) {
final poetryData = await offlineDataManager.getNextPoetry();
if (mounted && poetryData != null) {
// 记录浏览统计
try {
await StatisticsManager().recordView();
await StatisticsManager().recordFirstUse();
await StatisticsManager().recordTotalView();
} catch (e) {
// 忽略错误
}
setState(() {
_poetryData = poetryData;
_keywordList = PoetryDataUtils.extractKeywords(poetryData);
_starDisplay = PoetryDataUtils.getStarDisplay(poetryData);
_isLiked = false;
_loading = false;
_errorMessage = '';
});
_fadeController.forward();
_slideController.forward();
_checkIfLiked();
DebugInfoManager().showRefreshSuccess();
} else {
// 缓存为空时,显示错误信息
if (mounted) {
setState(() {
_loading = false;
_errorMessage = '离线模式下无缓存数据,请先在线下载';
});
}
DebugInfoManager().showRefreshFailed();
}
} else {
// 离线且无缓存时,显示错误信息
if (mounted) {
setState(() {
_loading = false;
_errorMessage = '离线模式下无缓存数据,请先在线下载';
});
}
DebugInfoManager().showRefreshFailed();
}
}
} catch (e) {
if (mounted) {
setState(() {
_loading = false;
_errorMessage = '加载失败,请检查网络连接';
});
}
DebugInfoManager().showRefreshFailed();
}
}
// 创建默认诗词数据,确保页面始终有内容显示
PoetryData _createDefaultPoetryData() {
final now = DateTime.now();
final dateStr = now.toString().substring(0, 10);
final monthStr = dateStr.substring(0, 7);
final timeStr = now.toString().substring(11, 19);
return PoetryData(
id: 1,
name: '静夜思',
alias: '李白',
keywords: '思乡,月亮,静夜',
introduce: '床前明月光,疑是地上霜。举头望明月,低头思故乡。',
drtime: '唐·李白《静夜思》',
like: 0,
url: '李白-静夜思',
tui: 1,
star: 5,
hitsTotal: 10000,
hitsMonth: 1000,
hitsDay: 100,
date: dateStr,
datem: monthStr,
time: timeStr,
createTime: timeStr,
updateTime: timeStr,
);
}
Future<void> _loadPoetryById(int poetryId) async {
if (_loading) return;
setState(() => _loading = true);
try {
final response = await PoetryApi.getPoetryById(poetryId);
if (mounted && response.data != null) {
// 记录浏览统计
try {
await StatisticsManager().recordView();
await StatisticsManager().recordFirstUse();
await StatisticsManager().recordTotalView();
} catch (e) {
// 忽略错误
}
setState(() {
_poetryData = response.data;
_keywordList = PoetryDataUtils.extractKeywords(response.data);
_starDisplay = PoetryDataUtils.getStarDisplay(response.data);
_loading = false;
_errorMessage = '';
});
_fadeController.forward();
_slideController.forward();
_checkIfLiked();
_updateCurrentHistoryIndex();
} else {
// 数据为空时,显示默认内容
if (mounted) {
setState(() {
_poetryData = _createDefaultPoetryData();
_keywordList = [];
_starDisplay = '⭐⭐⭐⭐⭐';
_isLiked = false;
_loading = false;
_errorMessage = '';
});
_fadeController.forward();
_slideController.forward();
}
}
} catch (e) {
if (mounted) {
setState(() {
_poetryData = _createDefaultPoetryData();
_keywordList = [];
_starDisplay = '⭐⭐⭐⭐⭐';
_isLiked = false;
_loading = false;
_errorMessage = '';
});
_fadeController.forward();
_slideController.forward();
}
}
}
Future<void> _toggleLike() async {
if (_poetryData == null || _isLoadingLike) return;
// 播放点赞音效(不等待完成)
AudioManager().playLikeSound();
// 立即切换按钮状态和显示加载
setState(() {
_isLoadingLike = true;
});
// 发送网络加载开始事件
startNetworkLoading('toggle_like');
try {
final response = await PoetryApi.toggleLike(_poetryData!.id);
if (mounted) {
setState(() {
// 根据API响应消息直接判断状态
_isLiked = response.message.contains('点赞成功');
// 更新诗词数据
if (response.data != null) {
_poetryData = PoetryData(
id: _poetryData!.id,
name: _poetryData!.name,
alias: _poetryData!.alias,
keywords: _poetryData!.keywords,
introduce: _poetryData!.introduce,
drtime: _poetryData!.drtime,
like: response.data!.like,
url: _poetryData!.url,
tui: _poetryData!.tui,
star: _poetryData!.star,
hitsTotal: _poetryData!.hitsTotal,
hitsMonth: _poetryData!.hitsMonth,
hitsDay: _poetryData!.hitsDay,
date: _poetryData!.date,
datem: _poetryData!.datem,
time: _poetryData!.time,
createTime: _poetryData!.createTime,
updateTime: _poetryData!.updateTime,
);
}
});
// 管理点赞存储
if (_isLiked) {
// 添加到点赞列表
await HistoryController.addToLiked(_poetryData!.toJson());
// 记录今日点赞
await StatisticsManager().recordTodayLike();
// 记录累计点赞
await StatisticsManager().recordTotalLike();
} else {
// 从点赞列表移除
await HistoryController.removeLikedPoetry(_poetryData!.id.toString());
}
// 发送点赞事件通知其他页面
sendLikeEvent(_poetryData!.id.toString(), _isLiked);
if (_isLiked) {
DebugInfoManager().showLiked();
} else {
DebugInfoManager().showUnliked();
}
PoetryStateManager.showSnackBar(
context,
response.message,
backgroundColor: AppConstants.successColor,
duration: const Duration(milliseconds: 200),
);
}
} catch (e) {
if (mounted) {
PoetryStateManager.showSnackBar(
context,
'操作失败,请重试',
backgroundColor: AppConstants.errorColor,
duration: const Duration(milliseconds: 200),
);
}
} finally {
if (mounted) {
setState(() => _isLoadingLike = false);
// 发送网络加载结束事件
endNetworkLoading('toggle_like');
}
}
}
Future<void> _loadHistory() async {
try {
final historyJson = await HistoryController.getHistory();
if (mounted) {
setState(() {
_historyList = historyJson;
// 重新计算当前诗词在历史记录中的索引
if (_poetryData != null && _historyList.isNotEmpty) {
_currentHistoryIndex = _historyList.indexWhere(
(item) => item['id'] == _poetryData!.id,
);
} else {
_currentHistoryIndex = -1;
}
});
}
} catch (e) {
// 加载失败
}
}
Future<void> _saveToHistory(PoetryData poetryData) async {
try {
final poetryMap = {
'id': poetryData.id,
'name': poetryData.name, // 诗句名称/标题
'alias': poetryData.alias, // 诗句朝代/作者
'introduce': poetryData.introduce, // 诗句译文/解释
'drtime': poetryData.drtime, // 诗句原文/内容
};
await HistoryController.addToHistory(poetryMap);
} catch (e) {
// 保存失败
}
}
void _updateCurrentHistoryIndex() {
if (_poetryData?.id != null) {
final index = _historyList.indexWhere(
(item) => item['id'] == _poetryData!.id,
);
_currentHistoryIndex = index >= 0 ? index : -1;
}
}
Future<void> _checkIfLiked() async {
// 这里可以实现检查收藏状态的逻辑
// 暂时使用简单的模拟逻辑
}
void _loadNextPoetry() async {
if (_isLoadingNext) return;
// 播放下一条音效(不等待完成)
AudioManager().playNextSound();
setState(() {
_isLoadingNext = true;
// 设置所有区域为加载状态
_sectionLoadingStates = {
'title': true,
'content': true,
'name': true,
'keywords': true,
'introduction': true,
};
});
try {
final offlineDataManager = OfflineDataManager();
final isOnline = await offlineDataManager.isOnline();
final hasCachedData = await offlineDataManager.hasCachedData();
PoetryData? newPoetryData;
if (isOnline) {
// 在线状态:从网络加载
// 确保历史记录已加载
if (_historyList.isEmpty) {
await _loadHistory();
}
if (_currentHistoryIndex < 0 ||
_currentHistoryIndex >= _historyList.length - 1) {
// 如果没有下一条了,加载新的诗词
final response = await PoetryApi.getRandomPoetry();
newPoetryData = response.data;
if (mounted && newPoetryData != null) {
await _saveToHistory(newPoetryData);
}
} else {
// 如果有下一条,加载下一条
final nextPoetry = _historyList[_currentHistoryIndex + 1];
final response = await PoetryApi.getPoetryById(nextPoetry['id']);
newPoetryData = response.data;
}
} else {
// 离线状态:从本地缓存加载
if (hasCachedData) {
newPoetryData = await offlineDataManager.getNextPoetry();
} else {
// 离线且无缓存时,显示错误信息
if (mounted) {
PoetryStateManager.showSnackBar(
context,
'离线模式下无缓存数据,请先在线下载',
backgroundColor: AppConstants.errorColor,
duration: const Duration(milliseconds: 200),
);
// 重置所有加载状态
setState(() {
_sectionLoadingStates.updateAll((key, value) => false);
});
}
DebugInfoManager().showNextFailed();
return;
}
}
if (mounted && newPoetryData != null) {
// 模拟分步加载
await _simulateSectionLoading(newPoetryData);
DebugInfoManager().showNextSuccess();
}
} catch (e) {
if (mounted) {
PoetryStateManager.showSnackBar(
context,
'加载下一条失败,建议开启离线模式',
backgroundColor: AppConstants.errorColor,
duration: const Duration(milliseconds: 200),
);
// 重置所有加载状态
setState(() {
_sectionLoadingStates.updateAll((key, value) => false);
});
}
DebugInfoManager().showNextFailed();
} finally {
if (mounted) {
setState(() {
_isLoadingNext = false;
});
}
}
}
// 模拟分步加载过程
Future<void> _simulateSectionLoading(PoetryData newPoetryData) async {
// 记录浏览统计
try {
await StatisticsManager().recordView();
await StatisticsManager().recordFirstUse();
await StatisticsManager().recordTotalView();
} catch (e) {
// 忽略错误
}
// 1. 加载标题区域
setState(() {
_sectionLoadingStates['title'] = false;
_poetryData = newPoetryData;
});
await Future.delayed(const Duration(milliseconds: 200));
// 2. 加载诗句区域
setState(() {
_sectionLoadingStates['name'] = false;
});
await Future.delayed(const Duration(milliseconds: 200));
// 3. 加载原文区域
setState(() {
_sectionLoadingStates['content'] = false;
});
await Future.delayed(const Duration(milliseconds: 200));
// 4. 加载关键词区域
setState(() {
_sectionLoadingStates['keywords'] = false;
_keywordList = PoetryDataUtils.extractKeywords(newPoetryData);
});
await Future.delayed(const Duration(milliseconds: 200));
// 5. 加载译文区域
setState(() {
_sectionLoadingStates['introduction'] = false;
_starDisplay = PoetryDataUtils.getStarDisplay(newPoetryData);
_isLiked = false;
_errorMessage = '';
});
_checkIfLiked();
_updateCurrentHistoryIndex();
}
void _loadPreviousPoetry() async {
try {
final offlineDataManager = OfflineDataManager();
final isOnline = await offlineDataManager.isOnline();
final hasCachedData = await offlineDataManager.hasCachedData();
if (isOnline) {
// 在线状态:从历史记录加载
// 确保历史记录已加载
if (_historyList.isEmpty) {
await _loadHistory();
}
if (_currentHistoryIndex <= 0) {
// 如果当前索引无效或已经是第一条,则重新加载历史记录
await _loadHistory();
// 如果历史记录为空,显示提示
if (_historyList.isEmpty) {
if (mounted) {
PoetryStateManager.showSnackBar(
context,
'暂无历史记录',
backgroundColor: AppConstants.errorColor,
duration: const Duration(milliseconds: 200),
);
}
return;
}
// 如果当前索引无效,设置为最新的一条
if (_currentHistoryIndex < 0) {
_currentHistoryIndex = 0;
}
}
// 检查是否有上一条
if (_currentHistoryIndex > 0) {
final previousPoetry = _historyList[_currentHistoryIndex - 1];
await _loadPoetryById(previousPoetry['id']);
} else {
// 如果没有上一条了,显示提示
if (mounted) {
PoetryStateManager.showSnackBar(
context,
'已经是第一条了',
backgroundColor: AppConstants.infoColor,
duration: const Duration(milliseconds: 200),
);
}
}
} else {
// 离线状态:从本地缓存加载
if (hasCachedData) {
final poetryData = await offlineDataManager.getPreviousPoetry();
if (mounted && poetryData != null) {
setState(() {
_poetryData = poetryData;
_keywordList = PoetryDataUtils.extractKeywords(poetryData);
_starDisplay = PoetryDataUtils.getStarDisplay(poetryData);
_isLiked = false;
_errorMessage = '';
});
_fadeController.forward();
_slideController.forward();
_checkIfLiked();
DebugInfoManager().showPreviousSuccess();
} else {
// 缓存为空时,显示错误信息
if (mounted) {
PoetryStateManager.showSnackBar(
context,
'离线模式下无缓存数据,请先在线下载',
backgroundColor: AppConstants.errorColor,
duration: const Duration(milliseconds: 200),
);
}
DebugInfoManager().showPreviousFailed();
}
} else {
// 离线且无缓存时,显示错误信息
if (mounted) {
PoetryStateManager.showSnackBar(
context,
'离线模式下无缓存数据,请先在线下载',
backgroundColor: AppConstants.errorColor,
duration: const Duration(milliseconds: 200),
);
}
DebugInfoManager().showPreviousFailed();
}
}
} catch (e) {
if (mounted) {
PoetryStateManager.showSnackBar(
context,
'加载上一条失败',
backgroundColor: AppConstants.errorColor,
duration: const Duration(milliseconds: 200),
);
}
}
}
Future<void> _refreshPoetry() async {
if (_poetryData?.id != null) {
// 如果有当前诗词ID则重新加载当前诗词
await _loadPoetryById(_poetryData!.id);
} else {
// 如果没有当前诗词ID则加载新的诗词
await _loadPoetry();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
body: SafeArea(child: _buildBody()),
);
}
Widget _buildBody() {
if (_loading) {
return const LoadingWidget();
}
if (_errorMessage.isNotEmpty) {
return CustomErrorWidget(
errorMessage: _errorMessage,
onRetry: _loadPoetry,
);
}
if (!PoetryDataUtils.isValidPoetryData(_poetryData)) {
return const EmptyWidget();
}
return _buildContent();
}
Widget _buildContent() {
return FutureBuilder<bool>(
future: OfflineDataManager().isOnline(),
builder: (context, snapshot) {
final isOnline = snapshot.data ?? true;
return RefreshIndicator(
onRefresh: _refreshPoetry,
child: FadeTransition(
opacity: _fadeAnimation,
child: Stack(
children: [
SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(), // 确保可以下拉刷新
padding: const EdgeInsets.symmetric(vertical: 16),
child: Column(
children: [
PoetryCard(
poetryData: _poetryData!,
keywordList: _keywordList,
onTap: _loadNextPoetry,
sectionLoadingStates: _sectionLoadingStates,
),
const SizedBox(height: 160), // 为悬浮按钮留出更多空间
],
),
),
// 调试信息气泡
Positioned(
bottom: 66,
left: 0,
right: 0,
child: Center(child: _buildDebugInfoBubble()),
),
// 悬浮上一条按钮 - 左边上方
Positioned(
left: 16,
bottom: 100,
child: FloatingPreviousButton(
onPrevious: _loadPreviousPoetry,
),
),
// 悬浮下一条按钮 - 左边下方
Positioned(
left: 16,
bottom: 32,
child: FloatingNextButton(onNext: _loadNextPoetry),
),
// 悬浮点赞按钮 - 右边(仅在线状态显示)
if (isOnline)
Positioned(
right: 16,
bottom: 32,
child: FloatingLikeButton(
isLiked: _isLiked,
isLoadingLike: _isLoadingLike,
onToggleLike: _toggleLike,
),
),
],
),
),
);
},
);
}
Widget _buildDebugInfoBubble() {
return ValueListenableBuilder<String>(
valueListenable: DebugInfoManager().messageNotifier,
builder: (context, message, child) {
if (message.isEmpty) {
return const SizedBox.shrink();
}
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: AppConstants.primaryColor.withValues(alpha: 0.9),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Text(
message,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
);
},
);
}
}