Files
wushu/lib/views/profile/history_page.dart
2026-04-02 07:06:55 +08:00

640 lines
20 KiB
Dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import '../../constants/app_constants.dart';
import '../../services/get/history_controller.dart';
import '../../services/get/theme_controller.dart';
class HistoryPage extends StatelessWidget {
const HistoryPage({super.key});
@override
Widget build(BuildContext context) {
final controller = Get.put(HistoryController());
final themeController = Get.find<ThemeController>();
return Obx(() {
final isDark = themeController.isDarkMode;
return Scaffold(
backgroundColor: isDark
? const Color(0xFF1A1A1A)
: const Color(0xFFF2F2F7),
appBar: _buildAppBar(controller, isDark),
body: Column(
children: [
_buildSearchBar(controller, isDark),
_buildSortOptions(controller, isDark),
_buildCountInfo(controller, isDark),
Expanded(
child: Obx(
() => controller.isLoading.value
? _buildLoadingWidget(isDark)
: controller.filteredHistoryList.isEmpty
? _buildEmptyWidget(isDark)
: _buildHistoryList(controller, isDark),
),
),
_buildPagination(controller, isDark),
],
),
);
});
}
PreferredSizeWidget _buildAppBar(HistoryController controller, bool isDark) {
return AppBar(
title: Text(
'历史记录',
style: TextStyle(
color: AppConstants.primaryColor,
fontWeight: FontWeight.w600,
fontSize: 17,
),
),
backgroundColor: isDark
? const Color(0xFF2A2A2A)
: const Color(0xFFF2F2F7),
elevation: 0,
centerTitle: true,
actions: [
Obx(
() => CupertinoButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
onPressed: controller.historyList.isEmpty
? null
: () async {
final confirmed = await Get.dialog<bool>(
CupertinoAlertDialog(
title: const Text('确认清空'),
content: const Text('确定要清空所有历史记录吗?'),
actions: [
CupertinoDialogAction(
child: const Text('取消'),
onPressed: () => Get.back(result: false),
),
CupertinoDialogAction(
isDestructiveAction: true,
child: const Text('清空'),
onPressed: () => Get.back(result: true),
),
],
),
);
if (confirmed == true) {
controller.clearHistory();
}
},
child: Icon(
CupertinoIcons.delete,
color: controller.historyList.isEmpty
? CupertinoColors.systemGrey
: CupertinoColors.systemRed,
),
),
),
CupertinoButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
onPressed: controller.showStatsDialog,
child: const Icon(
CupertinoIcons.chart_bar,
color: AppConstants.primaryColor,
),
),
CupertinoButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
onPressed: controller.exportHistory,
child: const Icon(
CupertinoIcons.share,
color: AppConstants.primaryColor,
),
),
],
);
}
Widget _buildSearchBar(HistoryController controller, bool isDark) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Container(
decoration: BoxDecoration(
color: isDark ? const Color(0xFF3A3A3A) : CupertinoColors.white,
borderRadius: BorderRadius.circular(10),
),
child: TextField(
onChanged: controller.searchHistory,
decoration: InputDecoration(
hintText: '搜索历史记录...',
hintStyle: TextStyle(
color: isDark
? Colors.grey[500]
: CupertinoColors.placeholderText,
),
prefixIcon: Icon(
CupertinoIcons.search,
color: isDark ? Colors.grey[400] : CupertinoColors.systemGrey,
),
suffixIcon: Obx(
() => controller.searchKeyword.value.isNotEmpty
? CupertinoButton(
padding: EdgeInsets.zero,
minimumSize: Size.zero,
onPressed: () => controller.searchHistory(''),
child: Icon(
CupertinoIcons.clear_circled_solid,
color: isDark
? Colors.grey[400]
: CupertinoColors.systemGrey,
size: 20,
),
)
: const SizedBox.shrink(),
),
border: InputBorder.none,
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 12,
),
),
style: TextStyle(
color: isDark ? Colors.white : CupertinoColors.label,
fontSize: 16,
),
),
),
);
}
Widget _buildSortOptions(HistoryController controller, bool isDark) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
Text(
'排序',
style: TextStyle(
fontSize: 13,
color: isDark ? Colors.grey[400] : CupertinoColors.secondaryLabel,
),
),
const SizedBox(width: 12),
Expanded(
child: GestureDetector(
onTap: () => _showSortActionSheet(controller),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
decoration: BoxDecoration(
color: isDark
? const Color(0xFF3A3A3A)
: CupertinoColors.white,
borderRadius: BorderRadius.circular(8),
),
child: Obx(
() => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
controller.sortTypes[controller.selectedSortType.value],
style: TextStyle(
fontSize: 15,
color: isDark ? Colors.white : CupertinoColors.label,
),
),
Icon(
CupertinoIcons.chevron_down,
size: 16,
color: isDark
? Colors.grey[400]
: CupertinoColors.systemGrey,
),
],
),
),
),
),
),
],
),
);
}
// === 显示排序选项 ===
void _showSortActionSheet(HistoryController controller) {
showCupertinoModalPopup(
context: Get.context!,
builder: (BuildContext context) => CupertinoActionSheet(
title: const Text('选择排序方式'),
actions: [
CupertinoActionSheetAction(
onPressed: () {
Get.back();
controller.sortHistory(0);
},
child: const Text('时间倒序'),
),
CupertinoActionSheetAction(
onPressed: () {
Get.back();
controller.sortHistory(1);
},
child: const Text('时间正序'),
),
CupertinoActionSheetAction(
onPressed: () {
Get.back();
controller.sortHistory(2);
},
child: const Text('按名称排序'),
),
],
cancelButton: CupertinoActionSheetAction(
onPressed: () => Get.back(),
child: const Text('取消'),
),
),
);
}
Widget _buildCountInfo(HistoryController controller, bool isDark) {
return Obx(
() => Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${controller.totalCount.value} 条记录',
style: TextStyle(
fontSize: 13,
color: isDark
? Colors.grey[400]
: CupertinoColors.secondaryLabel,
),
),
Text(
'${controller.currentPage.value} / ${controller.totalPages.value}',
style: TextStyle(
fontSize: 13,
color: isDark
? Colors.grey[400]
: CupertinoColors.secondaryLabel,
),
),
],
),
),
);
}
Widget _buildLoadingWidget(bool isDark) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CupertinoActivityIndicator(
radius: 20,
color: isDark ? Colors.white : null,
),
const SizedBox(height: 16),
Text(
'加载历史记录...',
style: TextStyle(
fontSize: 15,
color: isDark
? Colors.grey[400]
: CupertinoColors.secondaryLabel.resolveFrom(Get.context!),
),
),
],
),
);
}
Widget _buildEmptyWidget(bool isDark) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
CupertinoIcons.time,
size: 64,
color: isDark
? Colors.grey[600]
: CupertinoColors.systemGrey3.resolveFrom(Get.context!),
),
const SizedBox(height: 16),
Text(
'暂无历史记录',
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
color: isDark
? Colors.white
: CupertinoColors.label.resolveFrom(Get.context!),
),
),
const SizedBox(height: 8),
Text(
'浏览诗词后会自动记录在这里',
style: TextStyle(
fontSize: 14,
color: isDark
? Colors.grey[400]
: CupertinoColors.secondaryLabel.resolveFrom(Get.context!),
),
),
const SizedBox(height: 24),
CupertinoButton.filled(
onPressed: () => Get.back(),
borderRadius: BorderRadius.circular(8),
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
child: const Text(
'返回',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
),
],
),
);
}
Widget _buildHistoryList(HistoryController controller, bool isDark) {
final currentPageData = controller.getCurrentPageData();
return ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
itemCount: currentPageData.length,
separatorBuilder: (context, index) => const SizedBox(height: 8),
itemBuilder: (context, index) {
final item = currentPageData[index];
final startIndex =
(controller.currentPage.value - 1) * controller.pageSize;
final actualIndex = startIndex + index;
return _buildHistoryItem(
context,
controller,
item,
actualIndex,
isDark,
);
},
);
}
Widget _buildHistoryItem(
BuildContext context,
HistoryController controller,
Map<String, dynamic> item,
int actualIndex,
bool isDark,
) {
return Container(
decoration: BoxDecoration(
color: isDark ? const Color(0xFF2A2A2A) : CupertinoColors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: isDark
? Colors.black.withValues(alpha: 0.3)
: CupertinoColors.systemGrey4.withValues(alpha: 0.3),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: CupertinoListTile(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
leading: Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: AppConstants.primaryColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(22),
),
child: Center(
child: Text(
'${actualIndex + 1}',
style: TextStyle(
fontSize: 16,
color: AppConstants.primaryColor,
fontWeight: FontWeight.w600,
),
),
),
),
title: Text(
item['name'] ?? '未知诗词',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: isDark ? Colors.white : CupertinoColors.label,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 4),
Text(
'${item['alias'] ?? '未知朝代'}${item['date'] ?? ''}',
style: TextStyle(
fontSize: 13,
color: isDark
? Colors.grey[400]
: CupertinoColors.secondaryLabel,
),
),
if (item['introduce']?.toString().isNotEmpty == true)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
item['introduce']?.toString() ?? '',
style: TextStyle(
fontSize: 12,
color: isDark
? Colors.grey[500]
: CupertinoColors.tertiaryLabel,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
],
),
trailing: CupertinoButton(
padding: EdgeInsets.zero,
minimumSize: Size.zero,
onPressed: () =>
_showActionSheet(context, controller, actualIndex, item),
child: Icon(
CupertinoIcons.ellipsis,
color: isDark ? Colors.grey[400] : CupertinoColors.systemGrey,
),
),
onTap: () {
HapticFeedback.lightImpact();
},
),
);
}
// === 操作菜单 ===
void _showActionSheet(
BuildContext context,
HistoryController controller,
int index,
Map<String, dynamic> item,
) {
showCupertinoModalPopup(
context: context,
builder: (BuildContext context) => CupertinoActionSheet(
title: const Text('操作'),
actions: [
CupertinoActionSheetAction(
onPressed: () {
Get.back();
controller.deleteHistoryItem(index, item);
},
isDestructiveAction: true,
child: const Text('删除'),
),
CupertinoActionSheetAction(
onPressed: () {
Get.back();
Get.snackbar('提示', '分享功能开发中...');
},
child: const Text('分享'),
),
CupertinoActionSheetAction(
onPressed: () {
Get.back();
Get.snackbar('提示', '查看详情功能开发中...');
},
child: const Text('查看详情'),
),
],
cancelButton: CupertinoActionSheetAction(
onPressed: () => Get.back(),
child: const Text('取消'),
),
),
);
}
Widget _buildPagination(HistoryController controller, bool isDark) {
return Obx(
() => Visibility(
visible: controller.totalPages.value > 1,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF2A2A2A) : CupertinoColors.white,
border: Border(
top: BorderSide(
color: isDark
? Colors.grey[800]!
: CupertinoColors.separator.resolveFrom(Get.context!),
width: 0.5,
),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CupertinoButton(
onPressed: controller.currentPage.value > 1
? controller.previousPage
: null,
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
color: controller.currentPage.value > 1
? AppConstants.primaryColor
: (isDark ? Colors.grey[800] : CupertinoColors.systemGrey5),
borderRadius: BorderRadius.circular(8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
CupertinoIcons.chevron_left,
size: 16,
color: CupertinoColors.white,
),
const SizedBox(width: 4),
Text(
'上一页',
style: TextStyle(
fontSize: 14,
color: controller.currentPage.value > 1
? CupertinoColors.white
: (isDark
? Colors.grey[500]
: CupertinoColors.systemGrey),
),
),
],
),
),
Obx(
() => Text(
'${controller.currentPage.value} / ${controller.totalPages.value}',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: isDark ? Colors.white : CupertinoColors.label,
),
),
),
CupertinoButton(
onPressed:
controller.currentPage.value < controller.totalPages.value
? controller.nextPage
: null,
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
color:
controller.currentPage.value < controller.totalPages.value
? AppConstants.primaryColor
: (isDark ? Colors.grey[800] : CupertinoColors.systemGrey5),
borderRadius: BorderRadius.circular(8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'下一页',
style: TextStyle(
fontSize: 14,
color:
controller.currentPage.value <
controller.totalPages.value
? CupertinoColors.white
: (isDark
? Colors.grey[500]
: CupertinoColors.systemGrey),
),
),
const SizedBox(width: 4),
const Icon(
CupertinoIcons.chevron_right,
size: 16,
color: CupertinoColors.white,
),
],
),
),
],
),
),
),
);
}
}