Initial commit: Flutter 无书应用项目
This commit is contained in:
806
lib/views/home/home_page.dart
Normal file
806
lib/views/home/home_page.dart
Normal file
@@ -0,0 +1,806 @@
|
||||
/// 时间: 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 'home_part.dart';
|
||||
import 'home_components.dart';
|
||||
import 'home-load.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 = '';
|
||||
final String _historyKey = 'poetry_history';
|
||||
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;
|
||||
bool _isLoadingPrevious = 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();
|
||||
// 延迟加载诗词,确保页面先显示
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_loadPoetry();
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
debugPrint('加载诗词失败: $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) {
|
||||
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) {
|
||||
debugPrint('加载指定诗词失败: $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;
|
||||
|
||||
// 立即切换按钮状态和显示加载
|
||||
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());
|
||||
} 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) {
|
||||
print('加载历史记录失败: $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) {
|
||||
print('保存历史记录失败: $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;
|
||||
|
||||
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 {
|
||||
// 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,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user