diff --git a/lib/data/services/meeting/meeting_upload_service.dart b/lib/data/services/meeting/meeting_upload_service.dart index ab67a255a..13a98ef2d 100644 --- a/lib/data/services/meeting/meeting_upload_service.dart +++ b/lib/data/services/meeting/meeting_upload_service.dart @@ -29,6 +29,7 @@ class MeetingUploadService extends GetxService { executeUpload(); } + /// 添加待上传的音频文件 void addUpload( int id, String filePath, diff --git a/lib/modules/meeting/controllers/meeting_details_controller.dart b/lib/modules/meeting/controllers/meeting_details_controller.dart index aaf4eb6f7..aa679d154 100644 --- a/lib/modules/meeting/controllers/meeting_details_controller.dart +++ b/lib/modules/meeting/controllers/meeting_details_controller.dart @@ -18,6 +18,7 @@ import '../../../data/services/meeting/meeting_upload_service.dart'; import '../model/meeting_details_model.dart'; import '../model/meeting_model.dart'; +/// 会议详情控制器 class MeetingDetailsController extends GetxController with GetTickerProviderStateMixin { late TabController tabController; diff --git a/lib/modules/meeting/controllers/meeting_home_controller.dart b/lib/modules/meeting/controllers/meeting_home_controller.dart index df04c4d80..cd8c1f98a 100644 --- a/lib/modules/meeting/controllers/meeting_home_controller.dart +++ b/lib/modules/meeting/controllers/meeting_home_controller.dart @@ -41,7 +41,7 @@ class MeetingHomeController extends GetxController { RxList originalDataList = [].obs; RxList dataList = [].obs; RxString filtrateType = ''.obs; - bool isAsc = false; + bool isAsc = false; // 是否升序排序 TextEditingController filtrateController = TextEditingController(); // 蓝牙服务 @@ -178,15 +178,16 @@ class MeetingHomeController extends GetxController { } } +// 核心方法:导入本地录音文件到统一目录 void addMeetingAudio() async { EasyLoading.show(status: 'importingLocalRecordings'.tr); // 对应中文:正在导入本地录音... try { - int addUp = 0; - final appDir = await appDocDir; + int addUp = 0; // 新增计数 + final appDir = await appDocDir; // 获取应用文档目录 final sourceDirs = [ - Directory("${appDir.path}/MeetingAudio/"), - Directory("${appDir.path}/DestAudio/"), + Directory("${appDir.path}/MeetingAudio/"), // 会议录音目录 + Directory("${appDir.path}/DestAudio/"), // 目标录音目录 ]; // 目标目录:LocalAudio @@ -200,31 +201,33 @@ class MeetingHomeController extends GetxController { for (final dir in sourceDirs) { if (await dir.exists()) { + //遍历每个源目录,筛选出文件实体(仅包含文件,不包含子目录) final files = await dir.list().where((entity) => entity is File).toList(); - allFiles.addAll(files); + allFiles.addAll(files); //合并到总文件列表 } } + // 遍历所有文件实体 for (final fileEntity in allFiles) { try { - final file = File(fileEntity.path); + final file = File(fileEntity.path); //将文件实体转换为具体文件操作对象 final filePath = file.path; - // 设置音频源获取时长 - + // 使用just_audio库加载音频文件以获取时长 await _audioPlayer.setAudioSource(AudioSource.file(filePath)); - int seconds = _audioPlayer.duration?.inSeconds ?? 0; + int seconds = + _audioPlayer.duration?.inSeconds ?? 0; //获取音频时长(秒),若为空则设为0 // 获取文件修改时间 - final fileStat = await file.stat(); + final fileStat = await file.stat(); //获取文件状态信息,包含修改时间等 final creationTime = fileStat.changed.millisecondsSinceEpoch; // 准备新路径 - final fileName = filePath.split('/').last; - final newPath = "${destDir.path}/$fileName"; + final fileName = filePath.split('/').last; //获取文件名(包含扩展名) + final newPath = "${destDir.path}/$fileName"; //构建新路径,保持原文件名 - // 构建数据 + // 构建要存入数据库的音频文件抽象对象 Map data = { 'title': fileName, 'type': 'LOCAL', @@ -238,7 +241,7 @@ class MeetingHomeController extends GetxController { // 插入数据库 final meetingId = await SqfliteApi.insertMeeting(data); if (meetingId != null) { - // 上传OSS + // 安排后台上传任务 meetingUploadService.addUpload(meetingId, newPath, 'LocalAudio'); originalDataList.insert(0, { @@ -259,8 +262,8 @@ class MeetingHomeController extends GetxController { } // 移动文件 - await file.copy(newPath); - await file.delete(); + await file.copy(newPath); // 复制到新路径 + await file.delete(); // 删除原文件 addUp++; } @@ -272,10 +275,11 @@ class MeetingHomeController extends GetxController { e.toString())); // 对应中文:文件处理失败: {filePath}, 错误: {error} } } - if (addUp > 0) + if (addUp > 0) { EasyLoading.showSuccess('importSuccess' .tr .replaceAll('{count}', '$addUp')); // 对应中文:成功导入本地 {count} 条录音 + } } catch (e) { EasyLoading.showError('importError' .tr @@ -285,50 +289,88 @@ class MeetingHomeController extends GetxController { } } - void addTranslatAudio() async { + // 新增:将翻译音频归档到 LocalAudio 并返回新路径(优先 rename,失败再 copy+delete) + Future _archiveTranslatToLocal(String srcPath) async { + // 中文注释:获取应用文档目录并确保 LocalAudio 目录存在 + final appDir = await appDocDir; + final destDir = Directory(path.join(appDir.path, 'LocalAudio')); + if (!await destDir.exists()) { + await destDir.create(recursive: true); + } + + // 中文注释:目标文件名与路径,处理重名冲突 + final fileName = path.basename(srcPath); + final baseName = path.basenameWithoutExtension(fileName); + final ext = path.extension(fileName); + String destPath = path.join(destDir.path, fileName); + + if (await File(destPath).exists()) { + final ts = DateTime.now().millisecondsSinceEpoch; + destPath = path.join(destDir.path, '$baseName\_$ts$ext'); + } + + // 中文注释:尝试 rename(更快),失败则 copy + delete + final srcFile = File(srcPath); + try { + await srcFile.rename(destPath); + return destPath; + } catch (_) { + await srcFile.copy(destPath); + await srcFile.delete(); + return destPath; + } + } + + // 修改:翻译音频导入支持归档到 LocalAudio(智能转写默认归档以隐藏原翻译目录) + void addTranslatAudio({bool archiveToLocal = true}) async { EasyLoading.show(status: 'batchImporting'.tr); // 对应中文:正在批量导入... - for (final filePath in selected) { + for (final originalPath in selected) { try { - await _audioPlayer.setAudioSource(AudioSource.file(filePath)); - final fileStat = await File(filePath).stat(); - final creationTime = fileStat.changed.millisecondsSinceEpoch; // 时间戳 - int seconds = _audioPlayer.duration?.inSeconds ?? 0; - final fileName = filePath.split('/').last; - Map data = { + // 中文注释:根据开关决定是否将翻译音频迁移到 LocalAudio + final usePath = + archiveToLocal ? await _archiveTranslatToLocal(originalPath) : originalPath; + + // 中文注释:计算音频时长与创建时间 + await _audioPlayer.setAudioSource(AudioSource.file(usePath)); + final fileStat = await File(usePath).stat(); + final creationTime = fileStat.changed.millisecondsSinceEpoch; + final seconds = _audioPlayer.duration?.inSeconds ?? 0; + final fileName = path.basename(usePath); + + // 中文注释:归档则统一标记为 LOCAL,未归档则保留 TRANSLAT + final String recordType = archiveToLocal ? 'LOCAL' : 'TRANSLAT'; + + // 中文注释:写入数据库 + final Map data = { 'title': fileName, - 'type': 'TRANSLAT', + 'type': recordType, 'seconds': seconds, - 'filepath': filePath, + 'filepath': usePath, 'audiourl': '', 'tasktype': 0, 'creationtime': creationTime, }; + final meetingId = await SqfliteApi.insertMeeting(data); if (meetingId != null) { - meetingUploadService.addUpload(meetingId, filePath, 'TranslatAudio'); + // 中文注释:上传分类按目录区分 + final uploadBucket = archiveToLocal ? 'LocalAudio' : 'TranslatAudio'; + meetingUploadService.addUpload(meetingId, usePath, uploadBucket); - originalDataList.insert(0, { - 'id': meetingId, - ...data, - }); + // 中文注释:更新列表(保持现有排序逻辑) + final record = {'id': meetingId, ...data}; + originalDataList.insert(0, record); if (isAsc) { - dataList.add({ - 'id': meetingId, - ...data, - }); + dataList.add(record); } else { - dataList.insert(0, { - 'id': meetingId, - ...data, - }); + dataList.insert(0, record); } } } catch (e) { Logger.error('importFailed' .tr - .replaceAll('{filePath}', filePath) - .replaceAll('{error}', - e.toString())); // 对应中文:导入文件失败: {filePath}, error: {error} + .replaceAll('{filePath}', originalPath) + .replaceAll('{error}', e.toString())); // 对应中文:导入文件失败: {filePath}, error: {error} } } EasyLoading.dismiss(); diff --git a/lib/modules/meeting/controllers/mind_map_controller.dart b/lib/modules/meeting/controllers/mind_map_controller.dart index 45786ff99..997ec75bb 100644 --- a/lib/modules/meeting/controllers/mind_map_controller.dart +++ b/lib/modules/meeting/controllers/mind_map_controller.dart @@ -12,6 +12,7 @@ import 'package:webview_flutter/webview_flutter.dart'; import 'meeting_details_controller.dart'; +/// 思维导图控制器 class MindMapController extends GetxController { late final WebViewController webViewController; final _meetingDetailsController = Get.find(); diff --git a/lib/modules/translation/controllers/translation_list_controller.dart b/lib/modules/translation/controllers/translation_list_controller.dart index a908bf6c4..4a3954b55 100644 --- a/lib/modules/translation/controllers/translation_list_controller.dart +++ b/lib/modules/translation/controllers/translation_list_controller.dart @@ -86,7 +86,7 @@ class TranslationListController extends GetxController { await audioPlayer.setFilePath(filePath); await audioPlayer.play(); } catch (e) { - print("播放失败: $e"); + Logger.e("AudioPlayer", "播放失败: $e"); currentPlayingPath.value = ''; } } @@ -146,7 +146,7 @@ class TranslationListController extends GetxController { audioDurations[filePath] = duration; return duration; } catch (e) { - print("获取音频时长失败: $e"); + Logger.e("AudioPlayer", "获取音频时长失败: $e"); return Duration.zero; } } @@ -156,7 +156,7 @@ class TranslationListController extends GetxController { final appDir = await appDocDir; // 先 await 获取目录 final dir = Directory("${appDir.path}/TranslatAudio"); - print("appDocDir=${dir?.path}"); + Logger.d("AudioPlayer", "appDocDir=${dir?.path}"); // Create directory if it doesn't exist if (!await dir.exists()) { await dir.create(recursive: true); // Create directory tree if needed @@ -186,7 +186,7 @@ class TranslationListController extends GetxController { files.value = audioFiles; } catch (e) { - print("Error loading files: $e"); + Logger.e("AudioPlayer", "Error loading files: $e"); files.value = []; // Return empty list on error } }