You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

395 lines
12 KiB

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:intl/intl.dart';
import '../controllers/translation_controller.dart';
import '../controllers/translation_history_controller.dart';
import '../bindings/translation_detail_binding.dart';
import 'translation_detail_view.dart';
import '../../../core/theme/app_colors.dart';
import '../../../data/services/language_manager.dart';
class TranslationHistoryView extends GetView<TranslationHistoryController> {
const TranslationHistoryView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
backgroundColor: isDarkMode ? AppColors.darkBackground : Color(0xFFF5F5F8),
appBar: _buildAppBar(isDarkMode),
body: Obx(() {
if (!controller.hasHistory) {
return Center(
child: Text(
'noTranslationHistory'.tr,
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey,
),
),
);
}
if (controller.isLoading.value) {
return Center(
child: CircularProgressIndicator(
color: isDarkMode ? AppColors.primary : Colors.blue,
),
);
}
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
itemCount: controller.sortedDates.length,
itemBuilder: (context, index) {
final date = controller.sortedDates[index];
final items = controller.groupedHistory.value[date]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(top: 24.h, bottom: 12.h, left: 12.w),
child: Text(
date,
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
letterSpacing: 1.0,
),
),
),
_buildDateGroupContainer(items, isDarkMode),
],
);
},
);
}),
);
}
// 构建日期组容器
Widget _buildDateGroupContainer(List<TranslationItem> items, bool isDarkMode) {
return Container(
margin: EdgeInsets.only(bottom: 16.h),
decoration: BoxDecoration(
color: isDarkMode ? AppColors.cardBackground : Colors.white,
borderRadius: BorderRadius.circular(16.r),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(isDarkMode ? 30 : 8),
blurRadius: 8,
offset: Offset(0, 2),
),
],
),
child: ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemCount: items.length,
separatorBuilder: (context, index) => Divider(
height: 1,
thickness: 0.5,
color: isDarkMode ? Colors.grey[800] : Colors.grey[200],
indent: 0,
endIndent: 0,
),
itemBuilder: (context, index) {
return _buildHistoryItemInGroup(items[index], isDarkMode);
},
),
);
}
// 构建组内的历史记录项
Widget _buildHistoryItemInGroup(TranslationItem item, bool isDarkMode) {
return InkWell(
onTap: () {
// 点击查看详情
_showTranslationDetail(item);
},
splashColor: Colors.blue.withOpacity(0.1),
highlightColor: Colors.blue.withOpacity(0.05),
borderRadius: BorderRadius.circular(8.r),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 源文本
Text(
item.sourceText,
style: TextStyle(
fontSize: 15.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 6.h),
// 翻译文本
Text(
item.translatedText,
style: TextStyle(
fontSize: 14.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 8.h),
// 时间和语种信息行
Row(
children: [
// 时间信息
Text(
_formatSessionTime(item.timestamp),
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[600],
),
),
SizedBox(width: 12.w),
// 语种信息
Expanded(
child: Text(
_formatLanguagePair(item),
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[600],
),
overflow: TextOverflow.ellipsis,
),
),
],
),
],
),
),
SizedBox(width: 12.w),
// 删除会话按钮
InkWell(
onTap: () => _showDeleteSessionConfirmDialog(item.sessionId),
borderRadius: BorderRadius.circular(6.r),
splashColor: Colors.red.withOpacity(0.1),
highlightColor: Colors.red.withOpacity(0.05),
child: Container(
padding: EdgeInsets.all(8.w),
child: Icon(
Icons.delete_outline,
color: isDarkMode ? Colors.grey[500] : Colors.grey[400],
size: 18.sp,
),
),
),
SizedBox(width: 8.w),
Icon(
Icons.chevron_right,
color: isDarkMode ? Colors.grey[600] : Colors.grey[350],
size: 20.sp,
),
],
),
),
);
}
void _showTranslationDetail(TranslationItem item) {
// 获取该会话的所有翻译项
final List<TranslationItem> sessionItems = controller.getSessionItems(item.sessionId);
Get.to(
() => TranslationDetailView(),
arguments: {
'item': item,
'sessionItems': sessionItems,
'historyController': controller,
},
binding: TranslationDetailBinding(),
);
}
// 格式化会话时间
String _formatSessionTime(DateTime timestamp) {
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
final itemDate = DateTime(timestamp.year, timestamp.month, timestamp.day);
if (itemDate == today) {
// 今天:只显示时间 HH:mm
return DateFormat('HH:mm').format(timestamp);
} else {
// 其他日期:显示月日和时间 MM-dd HH:mm
return DateFormat('MM-dd HH:mm').format(timestamp);
}
}
// 格式化语种对信息
String _formatLanguagePair(TranslationItem item) {
final languageManager = Get.find<LanguageManager>();
// 获取源语言和目标语言的中文名称
final sourceName = languageManager.getChineseNameByAsrCode(item.sourceLanguageCode) ?? '未知语言';
final targetName = languageManager.getChineseNameByAsrCode(item.targetLanguageCode) ?? '未知语言';
// 使用双向箭头符号表示翻译方向
return '$sourceName ⇄ $targetName';
}
// 显示删除会话确认对话框
void _showDeleteSessionConfirmDialog(String sessionId) {
final isDarkMode = Get.isDarkMode;
Get.dialog(
AlertDialog(
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white,
title: Text(
'删除会话记录',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.black,
),
),
content: Text(
'确定要删除该会话的所有翻译记录吗?此操作无法撤销。',
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[300] : Colors.black87,
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr,
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
),
),
),
TextButton(
onPressed: () {
Get.back();
// 删除指定会话的历史记录
controller.deleteSessionHistory(sessionId);
},
child: Text(
'confirm'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
),
],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r),
),
),
);
}
void _showClearHistoryConfirmDialog() {
final isDarkMode = Get.isDarkMode;
Get.dialog(
AlertDialog(
backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white,
title: Text(
'clearHistory'.tr,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.black,
),
),
content: Text(
'clearHistoryConfirm'.tr,
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[300] : Colors.black87,
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'cancel'.tr,
style: TextStyle(
fontSize: 16.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[700],
),
),
),
TextButton(
onPressed: () {
// 清除历史记录
controller.translationController.clearTranslationHistory();
Get.back();
},
child: Text(
'confirm'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
),
],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r),
),
),
);
}
// 构建应用栏
PreferredSizeWidget _buildAppBar(bool isDarkMode) {
return AppBar(
backgroundColor: isDarkMode ? AppColors.cardBackground : Color(0xFFF5F5F8),
elevation: 0,
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: isDarkMode ? Colors.white : Colors.black,
size: 20.sp,
),
onPressed: () => Get.back(),
),
title: Text(
'translationHistory'.tr,
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black,
fontSize: 18.sp,
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
actions: [
IconButton(
icon: Icon(
Icons.delete_outline,
color: isDarkMode ? Colors.white : Colors.black,
size: 24.sp,
),
onPressed: () {
_showClearHistoryConfirmDialog();
},
),
],
);
}
}