|
|
@ -1,12 +1,10 @@ |
|
|
import 'dart:io'; |
|
|
import 'dart:io'; |
|
|
|
|
|
|
|
|
import 'package:common_utils/common_utils.dart'; |
|
|
|
|
|
import 'package:flutter/material.dart'; |
|
|
import 'package:flutter/material.dart'; |
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
|
import 'package:get/get.dart'; |
|
|
import 'package:get/get.dart'; |
|
|
import 'package:haptic_feedback/haptic_feedback.dart'; |
|
|
import 'package:haptic_feedback/haptic_feedback.dart'; |
|
|
import 'package:intl/intl.dart'; |
|
|
import 'package:intl/intl.dart'; |
|
|
|
|
|
|
|
|
import '../../../core/theme/app_colors.dart'; |
|
|
import '../../../core/theme/app_colors.dart'; |
|
|
import '../../../routes/app_routes.dart'; |
|
|
import '../../../routes/app_routes.dart'; |
|
|
import '../controllers/translation_list_controller.dart'; |
|
|
import '../controllers/translation_list_controller.dart'; |
|
|
@ -39,7 +37,7 @@ class TranslationListView extends GetView<TranslationListController> { |
|
|
onPressed: () => Get.back(), |
|
|
onPressed: () => Get.back(), |
|
|
), |
|
|
), |
|
|
title: Text( |
|
|
title: Text( |
|
|
'conferenceAssistant'.tr, // 商务会议助手 |
|
|
"翻译录音文件", // |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 17.sp, |
|
|
fontSize: 17.sp, |
|
|
fontWeight: FontWeight.w600, |
|
|
fontWeight: FontWeight.w600, |
|
|
@ -52,7 +50,8 @@ class TranslationListView extends GetView<TranslationListController> { |
|
|
|
|
|
|
|
|
Widget _buildAudioList(BuildContext context, bool isDarkMode) { |
|
|
Widget _buildAudioList(BuildContext context, bool isDarkMode) { |
|
|
return Obx(() { |
|
|
return Obx(() { |
|
|
if (controller.files.isEmpty) { |
|
|
final fileList = controller.files; // 不要 toList() |
|
|
|
|
|
if (fileList.isEmpty) { |
|
|
return Center(child: Text('暂无音频文件')); |
|
|
return Center(child: Text('暂无音频文件')); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -72,115 +71,168 @@ class TranslationListView extends GetView<TranslationListController> { |
|
|
final fileName = file.path.split('/').last; |
|
|
final fileName = file.path.split('/').last; |
|
|
final fileStat = file.statSync(); // 获取文件信息 |
|
|
final fileStat = file.statSync(); // 获取文件信息 |
|
|
final modifiedTime = fileStat.modified; |
|
|
final modifiedTime = fileStat.modified; |
|
|
|
|
|
// 添加 FutureBuilder 来异步获取音频时长 |
|
|
return GestureDetector( |
|
|
return FutureBuilder<Duration>( |
|
|
onTap: () { |
|
|
future: controller.getAudioDuration(file.path), |
|
|
// TODO: 播放音频 |
|
|
builder: (context, snapshot) { |
|
|
print("播放音频: $fileName"); |
|
|
String durationText = "计算中..."; |
|
|
}, |
|
|
if (snapshot.hasData) { |
|
|
onLongPressStart: (details) { |
|
|
final duration = snapshot.data!; |
|
|
_onLongPressAudioItem(context, isDarkMode, details, file); |
|
|
if (duration.inSeconds > 0) { |
|
|
print("长按操作: $fileName"); |
|
|
durationText = |
|
|
}, |
|
|
"${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}"; |
|
|
child: Container( |
|
|
} else { |
|
|
padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 10.w), |
|
|
durationText = "未知"; |
|
|
margin: EdgeInsets.symmetric(vertical: 5.w), |
|
|
} |
|
|
decoration: BoxDecoration( |
|
|
} else if (snapshot.hasError) { |
|
|
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white, |
|
|
durationText = "错误"; |
|
|
borderRadius: BorderRadius.circular(12.w), |
|
|
} |
|
|
boxShadow: [ |
|
|
return GestureDetector( |
|
|
BoxShadow( |
|
|
onLongPressStart: (details) { |
|
|
color: isDarkMode |
|
|
_onLongPressAudioItem(context, isDarkMode, details, file); |
|
|
? Colors.black.withOpacity(0.2) |
|
|
print("长按操作: $fileName"); |
|
|
: Colors.black.withOpacity(0.05), |
|
|
}, |
|
|
blurRadius: 10, |
|
|
onTap: () { |
|
|
offset: const Offset(0, 2), |
|
|
// 添加点击播放功能 |
|
|
), |
|
|
controller.togglePlay(file); |
|
|
], |
|
|
}, |
|
|
), |
|
|
child: Container( |
|
|
child: Column( |
|
|
padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 10.w), |
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
margin: EdgeInsets.symmetric(vertical: 5.w), |
|
|
children: [ |
|
|
decoration: BoxDecoration( |
|
|
/// 文件名 |
|
|
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white, |
|
|
Text( |
|
|
borderRadius: BorderRadius.circular(12.w), |
|
|
fileName, |
|
|
boxShadow: [ |
|
|
style: TextStyle( |
|
|
BoxShadow( |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
color: isDarkMode |
|
|
fontSize: 18.sp, |
|
|
? Colors.black.withOpacity(0.2) |
|
|
), |
|
|
: Colors.black.withOpacity(0.05), |
|
|
overflow: TextOverflow.ellipsis, |
|
|
blurRadius: 10, |
|
|
), |
|
|
offset: const Offset(0, 2), |
|
|
|
|
|
), |
|
|
/// 修改时间 & 大小 |
|
|
], |
|
|
Padding( |
|
|
|
|
|
padding: EdgeInsets.symmetric(vertical: 5.w), |
|
|
|
|
|
child: Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
Icon( |
|
|
|
|
|
Icons.access_time, |
|
|
|
|
|
size: 14.w, |
|
|
|
|
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], |
|
|
|
|
|
), |
|
|
|
|
|
4.horizontalSpace, |
|
|
|
|
|
Text( |
|
|
|
|
|
DateFormat('yyyy-MM-dd HH:mm').format(modifiedTime), |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], |
|
|
|
|
|
fontSize: 12.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
20.horizontalSpace, |
|
|
|
|
|
Icon( |
|
|
|
|
|
Icons.sd_storage, |
|
|
|
|
|
size: 14.w, |
|
|
|
|
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], |
|
|
|
|
|
), |
|
|
|
|
|
4.horizontalSpace, |
|
|
|
|
|
Text( |
|
|
|
|
|
'${(fileStat.size / 1024).toStringAsFixed(1)} KB', |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], |
|
|
|
|
|
fontSize: 12.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
child: Column( |
|
|
/// 文件类型标签 |
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
Row( |
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
|
|
|
|
children: [ |
|
|
children: [ |
|
|
Container( |
|
|
/// 文件名 |
|
|
padding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 2.w), |
|
|
Text( |
|
|
margin: EdgeInsets.only(top: 5.w), |
|
|
fileName, |
|
|
decoration: BoxDecoration( |
|
|
style: TextStyle( |
|
|
color: isDarkMode ? Colors.grey[900] : Colors.grey[100], |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
borderRadius: BorderRadius.circular(4.w), |
|
|
fontSize: 18.sp, |
|
|
), |
|
|
|
|
|
child: Text( |
|
|
|
|
|
file.path.split('.').last.toUpperCase(), |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
|
|
|
|
|
fontSize: 10.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
|
|
|
overflow: TextOverflow.ellipsis, |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
/// 修改时间 & 大小 |
|
|
Padding( |
|
|
Padding( |
|
|
padding: EdgeInsets.only(top: 5.w), |
|
|
padding: EdgeInsets.symmetric(vertical: 5.w), |
|
|
child: Text( |
|
|
child: Row( |
|
|
'点击播放', |
|
|
children: [ |
|
|
style: TextStyle( |
|
|
Icon( |
|
|
color: Colors.blue, |
|
|
Icons.access_time, |
|
|
fontSize: 10.sp, |
|
|
size: 14.w, |
|
|
), |
|
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], |
|
|
|
|
|
), |
|
|
|
|
|
4.horizontalSpace, |
|
|
|
|
|
Text( |
|
|
|
|
|
DateFormat('yyyy-MM-dd HH:mm').format(modifiedTime), |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: |
|
|
|
|
|
isDarkMode ? Colors.grey[400] : Colors.grey[500], |
|
|
|
|
|
fontSize: 12.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
20.horizontalSpace, |
|
|
|
|
|
Icon( |
|
|
|
|
|
Icons.sd_storage, |
|
|
|
|
|
size: 14.w, |
|
|
|
|
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[500], |
|
|
|
|
|
), |
|
|
|
|
|
4.horizontalSpace, |
|
|
|
|
|
Text( |
|
|
|
|
|
'${(fileStat.size / 1024).toStringAsFixed(1)} KB', |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: |
|
|
|
|
|
isDarkMode ? Colors.grey[400] : Colors.grey[500], |
|
|
|
|
|
fontSize: 12.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
20.horizontalSpace, |
|
|
|
|
|
Icon(Icons.music_note, |
|
|
|
|
|
size: 14.w, |
|
|
|
|
|
color: |
|
|
|
|
|
isDarkMode ? Colors.grey[400] : Colors.grey[500]), |
|
|
|
|
|
4.horizontalSpace, |
|
|
|
|
|
Text( |
|
|
|
|
|
durationText, // 使用计算出的时长文本 |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: |
|
|
|
|
|
isDarkMode ? Colors.grey[400] : Colors.grey[500], |
|
|
|
|
|
fontSize: 12.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
/// 文件类型标签 |
|
|
|
|
|
Row( |
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
|
|
|
|
children: [ |
|
|
|
|
|
Container( |
|
|
|
|
|
padding: |
|
|
|
|
|
EdgeInsets.symmetric(horizontal: 5.w, vertical: 2.w), |
|
|
|
|
|
margin: EdgeInsets.only(top: 5.w), |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
color: isDarkMode ? Colors.grey[900] : Colors.grey[100], |
|
|
|
|
|
borderRadius: BorderRadius.circular(4.w), |
|
|
|
|
|
), |
|
|
|
|
|
child: Text( |
|
|
|
|
|
file.path.split('.').last.toUpperCase(), |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: |
|
|
|
|
|
isDarkMode ? Colors.grey[400] : Colors.grey[600], |
|
|
|
|
|
fontSize: 10.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
Obx(() { |
|
|
|
|
|
final isCurrentFile = |
|
|
|
|
|
controller.currentPlayingPath.value == file.path; |
|
|
|
|
|
final isPlaying = controller.isPlaying.value; |
|
|
|
|
|
|
|
|
|
|
|
return Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
// 播放/暂停图标 |
|
|
|
|
|
if (isCurrentFile) |
|
|
|
|
|
Icon( |
|
|
|
|
|
isPlaying ? Icons.pause : Icons.play_arrow, |
|
|
|
|
|
size: 20.w, |
|
|
|
|
|
color: Colors.blue, |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
// 播放状态文本 |
|
|
|
|
|
Text( |
|
|
|
|
|
isCurrentFile |
|
|
|
|
|
? (isPlaying ? '播放中...' : '已暂停') |
|
|
|
|
|
: '点击播放', |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
color: Colors.blue, |
|
|
|
|
|
fontSize: 10.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
); |
|
|
|
|
|
}), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
], |
|
|
), |
|
|
), |
|
|
); |
|
|
), |
|
|
}, |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -237,6 +289,20 @@ class TranslationListView extends GetView<TranslationListController> { |
|
|
controller.loadTranslatAudio(); // 刷新列表 |
|
|
controller.loadTranslatAudio(); // 刷新列表 |
|
|
}, |
|
|
}, |
|
|
), |
|
|
), |
|
|
|
|
|
_popupMenuEntry( |
|
|
|
|
|
Icon( |
|
|
|
|
|
Icons.delete_outline, |
|
|
|
|
|
size: 20.w, |
|
|
|
|
|
color: isDarkMode ? Colors.red[700] : Colors.red, |
|
|
|
|
|
), |
|
|
|
|
|
'导入', |
|
|
|
|
|
isDarkMode ? Colors.red[700]! : Colors.red, |
|
|
|
|
|
() { |
|
|
|
|
|
Get.toNamed(Routes.meeting, arguments: { |
|
|
|
|
|
'filePath': file.path, |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
], |
|
|
], |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|