|
|
@ -11,6 +11,7 @@ import 'package:get/get.dart'; |
|
|
import 'package:intl/intl.dart'; |
|
|
import 'package:intl/intl.dart'; |
|
|
import 'package:path_provider/path_provider.dart'; |
|
|
import 'package:path_provider/path_provider.dart'; |
|
|
import 'package:permission_handler/permission_handler.dart'; |
|
|
import 'package:permission_handler/permission_handler.dart'; |
|
|
|
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; |
|
|
import '../../../data/services/asr_service.dart'; |
|
|
import '../../../data/services/asr_service.dart'; |
|
|
import '../../../data/services/ble_manager.dart'; |
|
|
import '../../../data/services/ble_manager.dart'; |
|
|
|
|
|
|
|
|
@ -25,6 +26,66 @@ enum TimerStatus { |
|
|
/// 负责会议记录的状态管理、音频处理、语音识别和UI交互 |
|
|
/// 负责会议记录的状态管理、音频处理、语音识别和UI交互 |
|
|
class MeetingRecordController extends GetxController |
|
|
class MeetingRecordController extends GetxController |
|
|
with GetTickerProviderStateMixin { |
|
|
with GetTickerProviderStateMixin { |
|
|
|
|
|
static const int _backgroundRecordingNotificationId = 91001; |
|
|
|
|
|
|
|
|
|
|
|
static FlutterLocalNotificationsPlugin? _localNotificationsPlugin; |
|
|
|
|
|
|
|
|
|
|
|
Future<FlutterLocalNotificationsPlugin> |
|
|
|
|
|
_ensureLocalNotificationsPlugin() async { |
|
|
|
|
|
final existing = _localNotificationsPlugin; |
|
|
|
|
|
if (existing != null) return existing; |
|
|
|
|
|
|
|
|
|
|
|
final plugin = FlutterLocalNotificationsPlugin(); |
|
|
|
|
|
const androidSettings = |
|
|
|
|
|
AndroidInitializationSettings('@mipmap/ic_launcher'); |
|
|
|
|
|
const iosSettings = DarwinInitializationSettings(); |
|
|
|
|
|
const settings = InitializationSettings( |
|
|
|
|
|
android: androidSettings, |
|
|
|
|
|
iOS: iosSettings, |
|
|
|
|
|
); |
|
|
|
|
|
await plugin.initialize(settings); |
|
|
|
|
|
_localNotificationsPlugin = plugin; |
|
|
|
|
|
return plugin; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Future<void> _requestNotificationPermissionIfNeeded() async { |
|
|
|
|
|
await PermissionUtil.instance.requestPermission( |
|
|
|
|
|
permissionType: Permission.notification, |
|
|
|
|
|
permissionName: 'notificationPermission'.tr, |
|
|
|
|
|
explanationText: 'notificationPermissionExplanation'.tr, |
|
|
|
|
|
permanentDenialText: 'notificationPermissionPermanentDenial'.tr, |
|
|
|
|
|
settingsButtonText: 'goToSettings'.tr, |
|
|
|
|
|
cancelButtonText: 'cancel'.tr, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Future<void> showBackgroundRecordingIndicator() async { |
|
|
|
|
|
await _requestNotificationPermissionIfNeeded(); |
|
|
|
|
|
if (!Platform.isIOS) return; |
|
|
|
|
|
|
|
|
|
|
|
final plugin = await _ensureLocalNotificationsPlugin(); |
|
|
|
|
|
final details = NotificationDetails( |
|
|
|
|
|
iOS: DarwinNotificationDetails( |
|
|
|
|
|
presentAlert: true, |
|
|
|
|
|
presentBadge: false, |
|
|
|
|
|
presentSound: false, |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
await plugin.show( |
|
|
|
|
|
_backgroundRecordingNotificationId, |
|
|
|
|
|
'meetingRecordRecordingNotificationTitle'.tr, |
|
|
|
|
|
'meetingRecordRecordingNotificationBody'.tr, |
|
|
|
|
|
details, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Future<void> clearBackgroundRecordingIndicator() async { |
|
|
|
|
|
if (!Platform.isIOS) return; |
|
|
|
|
|
final plugin = await _ensureLocalNotificationsPlugin(); |
|
|
|
|
|
await plugin.cancel(_backgroundRecordingNotificationId); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 服务 |
|
|
// 服务 |
|
|
final AsrService _asrService = Get.find<AsrService>(); |
|
|
final AsrService _asrService = Get.find<AsrService>(); |
|
|
final BleManager _bleManager = Get.find<BleManager>(); |
|
|
final BleManager _bleManager = Get.find<BleManager>(); |
|
|
@ -225,6 +286,8 @@ class MeetingRecordController extends GetxController |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
await _requestNotificationPermissionIfNeeded(); |
|
|
|
|
|
|
|
|
// 根据当前计时器状态执行相应操作 |
|
|
// 根据当前计时器状态执行相应操作 |
|
|
switch (timerStatus.value) { |
|
|
switch (timerStatus.value) { |
|
|
case TimerStatus.stopped: |
|
|
case TimerStatus.stopped: |
|
|
@ -389,6 +452,7 @@ class MeetingRecordController extends GetxController |
|
|
} |
|
|
} |
|
|
if (!isRecording.value) return; |
|
|
if (!isRecording.value) return; |
|
|
await _asrService.stopRecord(true); |
|
|
await _asrService.stopRecord(true); |
|
|
|
|
|
await clearBackgroundRecordingIndicator(); |
|
|
|
|
|
|
|
|
// 如果标题被修改则重命名文件 |
|
|
// 如果标题被修改则重命名文件 |
|
|
if (fileName.value != newName.value) { |
|
|
if (fileName.value != newName.value) { |
|
|
@ -427,6 +491,7 @@ class MeetingRecordController extends GetxController |
|
|
if (isRecording.value) { |
|
|
if (isRecording.value) { |
|
|
await _asrService.stopRecord(false); |
|
|
await _asrService.stopRecord(false); |
|
|
} |
|
|
} |
|
|
|
|
|
await clearBackgroundRecordingIndicator(); |
|
|
_resetToDefaultState(); |
|
|
_resetToDefaultState(); |
|
|
isRecording.value = false; |
|
|
isRecording.value = false; |
|
|
rms.value = 0.0; |
|
|
rms.value = 0.0; |
|
|
|