Browse Source

refactor(translation): 优化历史记录和详情页的UI布局

- 调整历史记录项的删除按钮位置至右上角
- 在详情页的翻译项右侧添加删除按钮
- 改进代码格式和缩进一致性
weicu
lxm 1 year ago
parent
commit
d830028531
  1. 188
      lib/modules/translation/views/translation_detail_view.dart
  2. 91
      lib/modules/translation/views/translation_history_view.dart

188
lib/modules/translation/views/translation_detail_view.dart

@ -35,9 +35,10 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
backgroundColor: isDarkMode ? AppColors.darkBackground : Color(0xFFF5F5F8),
backgroundColor:
isDarkMode ? AppColors.darkBackground : Color(0xFFF5F5F8),
appBar: _buildAppBar(isDarkMode),
body: Obx(() {
// 显示加载状态
@ -48,7 +49,7 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
),
);
}
return Column(
children: [
_buildTabButtons(isDarkMode),
@ -58,11 +59,12 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
}),
);
}
// 构建应用栏
PreferredSizeWidget _buildAppBar(bool isDarkMode) {
return AppBar(
backgroundColor: isDarkMode ? AppColors.cardBackground : Color(0xFFF5F5F8),
backgroundColor:
isDarkMode ? AppColors.cardBackground : Color(0xFFF5F5F8),
elevation: 0,
leading: IconButton(
icon: Icon(
@ -93,7 +95,7 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
],
);
}
// 构建选项卡按钮
Widget _buildTabButtons(bool isDarkMode) {
return Padding(
@ -102,11 +104,11 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
children: [
Expanded(
child: Obx(() => _buildTabButton(
title: 'originalRecord'.tr, // 原始记录
isSelected: controller.selectedTabIndex.value == 0,
onTap: () => controller.switchTab(0),
isDarkMode: isDarkMode,
)),
title: 'originalRecord'.tr, // 原始记录
isSelected: controller.selectedTabIndex.value == 0,
onTap: () => controller.switchTab(0),
isDarkMode: isDarkMode,
)),
),
//屏蔽“记录摘要”,需要是开启
// SizedBox(width: 12.w),
@ -122,7 +124,7 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
),
);
}
// 构建内容区域
Widget _buildContentArea(bool isDarkMode) {
return Expanded(
@ -134,13 +136,13 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
children: [
_buildTimestamp(isDarkMode),
SizedBox(height: 8.h),
// 根据选中的选项卡显示不同内容
if (controller.selectedTabIndex.value == 0)
..._buildOriginalRecords(isDarkMode)
else
_buildSummaryWidget(isDarkMode),
SizedBox(height: 24.h),
],
);
@ -148,7 +150,7 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
),
);
}
// 构建时间戳
Widget _buildTimestamp(bool isDarkMode) {
return Padding(
@ -164,12 +166,14 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
),
);
}
// 构建原始记录列表
List<Widget> _buildOriginalRecords(bool isDarkMode) {
return controller.sessionItems.map((sessionItem) => _buildSessionItemWidget(sessionItem, isDarkMode)).toList();
return controller.sessionItems
.map((sessionItem) => _buildSessionItemWidget(sessionItem, isDarkMode))
.toList();
}
// 构建选项卡按钮
Widget _buildTabButton({
required String title,
@ -182,8 +186,8 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
child: Container(
height: 40.h,
decoration: BoxDecoration(
color: isSelected
? (isDarkMode ? AppColors.primary : Colors.blue)
color: isSelected
? (isDarkMode ? AppColors.primary : Colors.blue)
: (isDarkMode ? AppColors.cardBackground : Colors.white),
borderRadius: BorderRadius.circular(20.r),
boxShadow: [
@ -200,15 +204,15 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
style: TextStyle(
fontSize: 15.sp,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
color: isSelected
? Colors.white
color: isSelected
? Colors.white
: (isDarkMode ? Colors.white : Colors.black87),
),
),
),
);
}
// 构建会话详情中的翻译项
Widget _buildSessionItemWidget(TranslationItem item, bool isDarkMode) {
final context = Get.context!;
@ -218,7 +222,8 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
decoration: BoxDecoration(
color: item.isIntermediate
? Colors.grey.withOpacity(0.1) // 中间结果使用浅灰色底色
: (item.sourceLanguageCode == controller.currentItem.sourceLanguageCode
: (item.sourceLanguageCode ==
controller.currentItem.sourceLanguageCode
? Theme.of(context)
.colorScheme
.primary
@ -238,13 +243,35 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 源文本
Text(
item.sourceText,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).textTheme.bodyLarge?.color,
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 源文本
Expanded(
child: Text(
item.sourceText,
style: TextStyle(
fontSize: 16,
color: Theme.of(context).textTheme.bodyLarge?.color,
),
)),
// 删除按钮
if (!item.isIntermediate)
InkWell(
onTap: () => _showDeleteItemConfirmDialog(item),
borderRadius: BorderRadius.circular(6.r),
splashColor: Colors.red.withValues(alpha: 0.1),
highlightColor: Colors.red.withValues(alpha: 0.05),
child: Container(
padding: EdgeInsets.all(6.w),
child: Icon(
Icons.delete_outline,
size: 16.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[400],
),
),
),
],
),
if (item.translatedText.isNotEmpty) ...[
const SizedBox(height: 8),
@ -273,22 +300,6 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
Row(
mainAxisSize: MainAxisSize.min,
children: [
// 删除按钮
if (!item.isIntermediate)
InkWell(
onTap: () => _showDeleteItemConfirmDialog(item),
borderRadius: BorderRadius.circular(6.r),
splashColor: Colors.red.withValues(alpha: 0.1),
highlightColor: Colors.red.withValues(alpha: 0.05),
child: Container(
padding: EdgeInsets.all(6.w),
child: Icon(
Icons.delete_outline,
size: 16.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[400],
),
),
),
// 播放按钮
if (!item.isIntermediate) ...[
SizedBox(width: 8.w),
@ -310,25 +321,25 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
);
}
// 构建总结视图
Widget _buildSummaryWidget(bool isDarkMode) {
final String combinedSourceText = _getCombinedSourceText();
return Column(
children: [
// 摘要内容容器
_buildSummaryContainer(isDarkMode),
// 提取摘要按钮
Obx(() => _buildExtractSummaryButton(combinedSourceText, isDarkMode)),
// 重新生成按钮
Obx(() => _buildRegenerateSummaryButton(combinedSourceText, isDarkMode)),
Obx(() =>
_buildRegenerateSummaryButton(combinedSourceText, isDarkMode)),
],
);
}
// 构建摘要容器
Widget _buildSummaryContainer(bool isDarkMode) {
return Container(
@ -354,7 +365,7 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
}),
);
}
// 构建空摘要提示
Widget _buildEmptySummaryPrompt(bool isDarkMode) {
return Padding(
@ -372,7 +383,7 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
),
);
}
// 构建摘要内容
Widget _buildSummaryContent(bool isDarkMode) {
return Column(
@ -417,9 +428,12 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
Material(
color: Colors.transparent,
child: InkWell(
onTap: () => controller.playText(controller.summaryResult.value),
onTap: () =>
controller.playText(controller.summaryResult.value),
borderRadius: BorderRadius.circular(20.r),
splashColor: isDarkMode ? AppColors.primary.withOpacity(0.2) : Colors.blue.withOpacity(0.2),
splashColor: isDarkMode
? AppColors.primary.withOpacity(0.2)
: Colors.blue.withOpacity(0.2),
child: Padding(
padding: EdgeInsets.all(8.r),
child: Icon(
@ -437,7 +451,9 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
child: InkWell(
onTap: _copySummaryToClipboard,
borderRadius: BorderRadius.circular(20.r),
splashColor: isDarkMode ? AppColors.primary.withOpacity(0.2) : Colors.blue.withOpacity(0.2),
splashColor: isDarkMode
? AppColors.primary.withOpacity(0.2)
: Colors.blue.withOpacity(0.2),
child: Padding(
padding: EdgeInsets.all(8.r),
child: Icon(
@ -454,7 +470,7 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
],
);
}
// 复制摘要到剪贴板
void _copySummaryToClipboard() {
Clipboard.setData(ClipboardData(text: controller.summaryResult.value));
@ -465,16 +481,19 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
duration: Duration(seconds: 2),
);
}
// 构建提取摘要按钮
Widget _buildExtractSummaryButton(String combinedSourceText, bool isDarkMode) {
final bool isDisabled = controller.isGeneratingSummary.value || controller.summaryResult.value.isNotEmpty;
Widget _buildExtractSummaryButton(
String combinedSourceText, bool isDarkMode) {
final bool isDisabled = controller.isGeneratingSummary.value ||
controller.summaryResult.value.isNotEmpty;
return Container(
width: double.infinity,
margin: EdgeInsets.only(bottom: 16.h),
child: ElevatedButton(
onPressed: isDisabled ? null : () => _extractSummary(combinedSourceText),
onPressed:
isDisabled ? null : () => _extractSummary(combinedSourceText),
style: ElevatedButton.styleFrom(
backgroundColor: isDarkMode ? AppColors.primary : Colors.blue,
foregroundColor: Colors.white,
@ -483,14 +502,18 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
borderRadius: BorderRadius.circular(16.r),
),
elevation: 0,
disabledBackgroundColor: controller.isGeneratingSummary.value
? isDarkMode ? AppColors.primary.withAlpha(128) : Colors.blue.withAlpha(128)
disabledBackgroundColor: controller.isGeneratingSummary.value
? isDarkMode
? AppColors.primary.withAlpha(128)
: Colors.blue.withAlpha(128)
: Colors.grey.withAlpha(128),
),
child: controller.isGeneratingSummary.value
? _buildGeneratingIndicator(isDarkMode)
: Text(
controller.summaryResult.value.isEmpty ? 'extractSummary'.tr : 'summaryGenerated'.tr, // 提取摘要 : 已生成摘要
controller.summaryResult.value.isEmpty
? 'extractSummary'.tr
: 'summaryGenerated'.tr, // 提取摘要 : 已生成摘要
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
@ -499,7 +522,7 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
),
);
}
// 构建生成中指示器
Widget _buildGeneratingIndicator(bool isDarkMode) {
return Row(
@ -524,13 +547,15 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
],
);
}
// 构建重新生成按钮
Widget _buildRegenerateSummaryButton(String combinedSourceText, bool isDarkMode) {
if (controller.summaryResult.value.isEmpty || controller.isGeneratingSummary.value) {
Widget _buildRegenerateSummaryButton(
String combinedSourceText, bool isDarkMode) {
if (controller.summaryResult.value.isEmpty ||
controller.isGeneratingSummary.value) {
return SizedBox.shrink();
}
return Container(
width: double.infinity,
margin: EdgeInsets.only(bottom: 16.h),
@ -554,17 +579,17 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
),
);
}
// 提取摘要方法
void _extractSummary(String text) async {
final result = await controller.extractSummary(text);
// 检查是否超时,如果超时则显示重试选项
if (result.contains('超时')) {
_showTimeoutDialog(text);
}
}
// 显示超时对话框
void _showTimeoutDialog(String text) {
Get.dialog(
@ -720,11 +745,13 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
// 分享原始记录
final String sourceText = _getCombinedSourceText();
final String translatedText = _getCombinedTranslatedText();
shareText = '${'originalText'.tr}:\n$sourceText\n\n${'translatedText'.tr}:\n$translatedText'; // 原文:译文:
shareText =
'${'originalText'.tr}:\n$sourceText\n\n${'translatedText'.tr}:\n$translatedText'; // 原文:译文:
} else {
// 分享摘要
if (controller.summaryResult.value.isNotEmpty) {
shareText = '${'sessionSummary'.tr}:\n${controller.summaryResult.value}'; // 会话摘要:
shareText =
'${'sessionSummary'.tr}:\n${controller.summaryResult.value}'; // 会话摘要:
} else {
Get.snackbar(
'cannotShare'.tr, // 无法分享
@ -735,11 +762,12 @@ class TranslationDetailView extends GetView<TranslationDetailController> {
return;
}
}
// 调用系统分享
Share.share(
shareText,
subject: '${'translationSessionRecord'.tr} - ${DateFormat('yyyy-MM-dd HH:mm').format(controller.currentItem.timestamp)}', // 翻译会话记录
subject:
'${'translationSessionRecord'.tr} - ${DateFormat('yyyy-MM-dd HH:mm').format(controller.currentItem.timestamp)}', // 翻译会话记录
);
}
}
}

91
lib/modules/translation/views/translation_history_view.dart

@ -15,9 +15,10 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
backgroundColor: isDarkMode ? AppColors.darkBackground : Color(0xFFF5F5F8),
backgroundColor:
isDarkMode ? AppColors.darkBackground : Color(0xFFF5F5F8),
appBar: _buildAppBar(isDarkMode),
body: Obx(() {
if (!controller.hasHistory) {
@ -46,7 +47,7 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
itemBuilder: (context, index) {
final date = controller.sortedDates[index];
final items = controller.groupedHistory.value[date]!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -70,9 +71,10 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
}),
);
}
// 构建日期组容器
Widget _buildDateGroupContainer(List<TranslationItem> items, bool isDarkMode) {
Widget _buildDateGroupContainer(
List<TranslationItem> items, bool isDarkMode) {
return Container(
margin: EdgeInsets.only(bottom: 16.h),
decoration: BoxDecoration(
@ -104,7 +106,7 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
),
);
}
// 构建组内的历史记录项
Widget _buildHistoryItemInGroup(TranslationItem item, bool isDarkMode) {
return InkWell(
@ -117,10 +119,11 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
borderRadius: BorderRadius.circular(8.r),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 16.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
child: Stack(
children: [
Expanded(
// 主要内容区域
Padding(
padding: EdgeInsets.only(right: 50.w), // 为右侧图标留出空间
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -155,7 +158,8 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
_formatSessionTime(item.timestamp),
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[600],
color:
isDarkMode ? Colors.grey[500] : Colors.grey[600],
),
),
SizedBox(width: 12.w),
@ -165,7 +169,9 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
_formatLanguagePair(item),
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.grey[500] : Colors.grey[600],
color: isDarkMode
? Colors.grey[500]
: Colors.grey[600],
),
overflow: TextOverflow.ellipsis,
),
@ -175,37 +181,45 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
],
),
),
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,
// 右上角删除按钮
Positioned(
top: 0,
right: -8.w,
child: 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,
// 右下角箭头图标
Positioned(
bottom: 0,
right: 0.w, // 与删除图标垂直对齐
child: 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);
final List<TranslationItem> sessionItems =
controller.getSessionItems(item.sessionId);
Get.to(
() => TranslationDetailView(),
@ -238,8 +252,12 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
final languageManager = Get.find<LanguageManager>();
// 获取源语言和目标语言的中文名称
final sourceName = languageManager.getChineseNameByAsrCode(item.sourceLanguageCode) ?? 'unknownLanguage'.tr; // 未知语言
final targetName = languageManager.getChineseNameByAsrCode(item.targetLanguageCode) ?? 'unknownLanguage'.tr; // 未知语言
final sourceName =
languageManager.getChineseNameByAsrCode(item.sourceLanguageCode) ??
'unknownLanguage'.tr; // 未知语言
final targetName =
languageManager.getChineseNameByAsrCode(item.targetLanguageCode) ??
'unknownLanguage'.tr; // 未知语言
// 使用双向箭头符号表示翻译方向
return '$sourceName ⇄ $targetName';
@ -355,11 +373,12 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
),
);
}
// 构建应用栏
PreferredSizeWidget _buildAppBar(bool isDarkMode) {
return AppBar(
backgroundColor: isDarkMode ? AppColors.cardBackground : Color(0xFFF5F5F8),
backgroundColor:
isDarkMode ? AppColors.cardBackground : Color(0xFFF5F5F8),
elevation: 0,
leading: IconButton(
icon: Icon(
@ -392,4 +411,4 @@ class TranslationHistoryView extends GetView<TranslationHistoryController> {
],
);
}
}
}

Loading…
Cancel
Save