652 lines
21 KiB
Dart
652 lines
21 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 '../../models/colors/theme_colors.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;
|
|
final primaryColor = themeController.currentThemeColor;
|
|
return Scaffold(
|
|
backgroundColor: isDark
|
|
? const Color(0xFF1A1A1A)
|
|
: const Color(0xFFF2F2F7),
|
|
appBar: _buildAppBar(controller, isDark, primaryColor),
|
|
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, primaryColor),
|
|
),
|
|
),
|
|
_buildPagination(controller, isDark, primaryColor),
|
|
],
|
|
),
|
|
);
|
|
});
|
|
}
|
|
|
|
PreferredSizeWidget _buildAppBar(
|
|
HistoryController controller,
|
|
bool isDark,
|
|
Color primaryColor,
|
|
) {
|
|
return AppBar(
|
|
title: Text(
|
|
'历史记录',
|
|
style: TextStyle(
|
|
color: 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: Icon(CupertinoIcons.chart_bar, color: primaryColor),
|
|
),
|
|
CupertinoButton(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
onPressed: controller.exportHistory,
|
|
child: Icon(CupertinoIcons.share, color: 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,
|
|
Color primaryColor,
|
|
) {
|
|
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,
|
|
primaryColor,
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildHistoryItem(
|
|
BuildContext context,
|
|
HistoryController controller,
|
|
Map<String, dynamic> item,
|
|
int actualIndex,
|
|
bool isDark,
|
|
Color primaryColor,
|
|
) {
|
|
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: primaryColor.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(22),
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
'${actualIndex + 1}',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
color: 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,
|
|
) {
|
|
final themeController = Get.find<ThemeController>();
|
|
final primaryColor = themeController.currentThemeColor;
|
|
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('提示', '分享功能开发中...', colorText: primaryColor);
|
|
},
|
|
child: const Text('分享'),
|
|
),
|
|
CupertinoActionSheetAction(
|
|
onPressed: () {
|
|
Get.back();
|
|
Get.snackbar('提示', '查看详情功能开发中...', colorText: primaryColor);
|
|
},
|
|
child: const Text('查看详情'),
|
|
),
|
|
],
|
|
cancelButton: CupertinoActionSheetAction(
|
|
onPressed: () => Get.back(),
|
|
child: const Text('取消'),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildPagination(
|
|
HistoryController controller,
|
|
bool isDark,
|
|
Color primaryColor,
|
|
) {
|
|
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
|
|
? 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
|
|
? 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,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|