diff --git a/lib/modules/opus_test/controllers/opus_test_controller.dart b/lib/modules/opus_test/controllers/opus_test_controller.dart index 75b60b3ad..4fad692e9 100644 --- a/lib/modules/opus_test/controllers/opus_test_controller.dart +++ b/lib/modules/opus_test/controllers/opus_test_controller.dart @@ -9,6 +9,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:just_audio/just_audio.dart'; import 'package:jl_opus/jl_opus.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:share_plus/share_plus.dart'; // 添加分享插件导入 class OpusTestController extends GetxController { // 选中的文件 @@ -346,6 +347,166 @@ class OpusTestController extends GetxController { // 数据大小 data.setUint32(40, pcmLength, Endian.little); } + + /// 删除外部文件 + Future deleteExternalFile(PlatformFile file) async { + try { + final fileToDelete = File(file.path!); + if (await fileToDelete.exists()) { + await fileToDelete.delete(); + externalFiles.removeWhere((f) => f.path == file.path); + + // 如果删除的是当前选中的文件,清空选择 + if (selectedFiles.isNotEmpty && selectedFiles.first.path == file.path) { + selectedFiles.clear(); + } + + statusMessage.value = '文件已删除: ${file.name}'; + } else { + statusMessage.value = '文件不存在: ${file.name}'; + } + } catch (e) { + statusMessage.value = '删除文件失败: $e'; + } + } + + /// 分享外部文件 + Future shareExternalFile(PlatformFile file) async { + try { + if (file.path != null) { + final fileToShare = File(file.path!); + if (await fileToShare.exists()) { + await Share.shareXFiles( + [XFile(file.path!)], + text: '分享Opus音频文件: ${file.name}', + ); + statusMessage.value = '正在分享文件: ${file.name}'; + } else { + statusMessage.value = '文件不存在: ${file.name}'; + } + } + } catch (e) { + statusMessage.value = '分享文件失败: $e'; + } + } + + /// 显示文件操作底部弹窗 + void showFileActionSheet(BuildContext context, PlatformFile file) { + showModalBottomSheet( + context: context, + backgroundColor: Get.isDarkMode ? Colors.grey[900] : Colors.white, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (context) => Container( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 文件信息 + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: [ + Icon( + Icons.audiotrack, + color: Get.isDarkMode ? Colors.white70 : Colors.black87, + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + file.name, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Get.isDarkMode ? Colors.white : Colors.black, + ), + overflow: TextOverflow.ellipsis, + ), + Text( + '${(file.size / 1024).toStringAsFixed(2)} KB', + style: TextStyle( + fontSize: 14, + color: Get.isDarkMode + ? Colors.white60 + : Colors.black54, + ), + ), + ], + ), + ), + ], + ), + ), + const Divider(), + // 分享选项 + ListTile( + leading: const Icon(Icons.share, color: Colors.blue), + title: const Text('分享文件'), + onTap: () { + Navigator.pop(context); + shareExternalFile(file); + }, + ), + // 删除选项 + ListTile( + leading: const Icon(Icons.delete, color: Colors.red), + title: const Text('删除文件', style: TextStyle(color: Colors.red)), + onTap: () { + Navigator.pop(context); + _showDeleteConfirmDialog(context, file); + }, + ), + // 取消选项 + ListTile( + leading: const Icon(Icons.cancel), + title: const Text('取消'), + onTap: () => Navigator.pop(context), + ), + ], + ), + ), + ); + } + + /// 显示删除确认对话框 + void _showDeleteConfirmDialog(BuildContext context, PlatformFile file) { + showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: Get.isDarkMode ? Colors.grey[900] : Colors.white, + title: Text( + '确认删除', + style: TextStyle( + color: Get.isDarkMode ? Colors.white : Colors.black, + ), + ), + content: Text( + '确定要删除文件 "${file.name}" 吗?\n此操作不可撤销。', + style: TextStyle( + color: Get.isDarkMode ? Colors.white70 : Colors.black87, + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('取消'), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + deleteExternalFile(file); + }, + style: TextButton.styleFrom(foregroundColor: Colors.red), + child: const Text('删除'), + ), + ], + ), + ); + } } // PCM音频源 diff --git a/lib/modules/opus_test/views/opus_test_view.dart b/lib/modules/opus_test/views/opus_test_view.dart index adecc15b6..de02e5138 100644 --- a/lib/modules/opus_test/views/opus_test_view.dart +++ b/lib/modules/opus_test/views/opus_test_view.dart @@ -170,6 +170,10 @@ class OpusTestView extends GetView { onTap: () { controller.selectExternalFile(file); }, + onLongPress: () { + // 长按显示操作菜单 + controller.showFileActionSheet(context, file); + }, trailing: Icon( Icons.arrow_forward, color: diff --git a/lib/modules/settings/views/settings_view.dart b/lib/modules/settings/views/settings_view.dart index 58d527fdb..f6c2e7892 100644 --- a/lib/modules/settings/views/settings_view.dart +++ b/lib/modules/settings/views/settings_view.dart @@ -407,8 +407,6 @@ class SettingsView extends GetView { ? Colors.white.withOpacity(0.1) : Colors.grey[200]), - - // 用户反馈 _buildSimpleNavigationSetting( title: 'feedback'.tr, // 用户反馈 @@ -520,23 +518,23 @@ class SettingsView extends GetView { // color: isDarkMode // ? Colors.white.withOpacity(0.1) // : Colors.grey[200]), - // BLE测试 - // _buildSimpleNavigationSetting( - // title: 'opus解码测试', - // subtitle: '测试opus解码', - // icon: Icons.bluetooth_searching, - // iconBgColor: isDarkMode - // ? Colors.green[900]!.withOpacity(0.3) - // : Colors.green[100]!, - // iconColor: - // isDarkMode ? Colors.green[300]! : Colors.green[600]!, - // titleColor: isDarkMode ? Colors.white : null, - // subtitleColor: isDarkMode ? Colors.white70 : null, - // onTap: () { - // Get.toNamed(Routes.opusTest); - // }, - // isDarkMode: isDarkMode, - // ), + //BLE测试 + _buildSimpleNavigationSetting( + title: 'opus解码测试', + subtitle: '测试opus解码', + icon: Icons.bluetooth_searching, + iconBgColor: isDarkMode + ? Colors.green[900]!.withOpacity(0.3) + : Colors.green[100]!, + iconColor: + isDarkMode ? Colors.green[300]! : Colors.green[600]!, + titleColor: isDarkMode ? Colors.white : null, + subtitleColor: isDarkMode ? Colors.white70 : null, + onTap: () { + Get.toNamed(Routes.opusTest); + }, + isDarkMode: isDarkMode, + ), // Divider( // height: 1, // color: isDarkMode