|
|
@ -41,6 +41,9 @@ class MeetingRecordController extends GetxController |
|
|
Timer? _routeMonitorTimer; |
|
|
Timer? _routeMonitorTimer; |
|
|
StreamSubscription<String>? _recordingFloatingActionSubscription; |
|
|
StreamSubscription<String>? _recordingFloatingActionSubscription; |
|
|
bool _floatingBarManuallyClosed = false; |
|
|
bool _floatingBarManuallyClosed = false; |
|
|
|
|
|
bool _overlayPermissionPromptedThisSession = false; |
|
|
|
|
|
bool _overlayPermissionSnackShownThisSession = false; |
|
|
|
|
|
bool _overlayPermissionRequesting = false; |
|
|
AppLifecycleState _appLifecycleState = AppLifecycleState.resumed; |
|
|
AppLifecycleState _appLifecycleState = AppLifecycleState.resumed; |
|
|
String _lastKnownRoute = ''; |
|
|
String _lastKnownRoute = ''; |
|
|
|
|
|
|
|
|
@ -152,13 +155,8 @@ class MeetingRecordController extends GetxController |
|
|
if (!isRecording.value) return; |
|
|
if (!isRecording.value) return; |
|
|
if (_floatingBarManuallyClosed) return; |
|
|
if (_floatingBarManuallyClosed) return; |
|
|
|
|
|
|
|
|
final hasPermission = await OverlayPermissionUtil.hasOverlayPermission(); |
|
|
final granted = await _ensureAndroidOverlayPermissionForFloatingBar(); |
|
|
if (!hasPermission) { |
|
|
|
|
|
final granted = await OverlayPermissionUtil.requestOverlayPermission( |
|
|
|
|
|
scene: OverlayPermissionScene.recordingFloatingBar, |
|
|
|
|
|
); |
|
|
|
|
|
if (!granted) return; |
|
|
if (!granted) return; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
final typeText = _getRecordingTypeText(); |
|
|
final typeText = _getRecordingTypeText(); |
|
|
final durationText = _formatTimeForFloatingBar(milliseconds.value); |
|
|
final durationText = _formatTimeForFloatingBar(milliseconds.value); |
|
|
@ -191,6 +189,54 @@ class MeetingRecordController extends GetxController |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _showOverlayPermissionSnackOnce() { |
|
|
|
|
|
if (_overlayPermissionSnackShownThisSession) return; |
|
|
|
|
|
_overlayPermissionSnackShownThisSession = true; |
|
|
|
|
|
Get.snackbar( |
|
|
|
|
|
'overlayPermissionTitle'.tr, |
|
|
|
|
|
'overlayPermissionRecordingDesc'.tr, |
|
|
|
|
|
snackPosition: SnackPosition.BOTTOM, |
|
|
|
|
|
duration: const Duration(seconds: 4), |
|
|
|
|
|
mainButton: TextButton( |
|
|
|
|
|
onPressed: () { |
|
|
|
|
|
unawaited(OverlayPermissionUtil.openOverlayPermissionSettings()); |
|
|
|
|
|
}, |
|
|
|
|
|
child: Text('goToSettings'.tr), |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Future<bool> _ensureAndroidOverlayPermissionForFloatingBar() async { |
|
|
|
|
|
if (!Platform.isAndroid) return true; |
|
|
|
|
|
if (!isRecording.value) return false; |
|
|
|
|
|
|
|
|
|
|
|
final hasPermission = await OverlayPermissionUtil.hasOverlayPermission(); |
|
|
|
|
|
if (hasPermission) return true; |
|
|
|
|
|
|
|
|
|
|
|
if (_appLifecycleState != AppLifecycleState.resumed) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (_overlayPermissionPromptedThisSession || _overlayPermissionRequesting) { |
|
|
|
|
|
_showOverlayPermissionSnackOnce(); |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_overlayPermissionPromptedThisSession = true; |
|
|
|
|
|
_overlayPermissionRequesting = true; |
|
|
|
|
|
try { |
|
|
|
|
|
final granted = await OverlayPermissionUtil.requestOverlayPermission( |
|
|
|
|
|
scene: OverlayPermissionScene.recordingFloatingBar, |
|
|
|
|
|
); |
|
|
|
|
|
if (!granted) { |
|
|
|
|
|
_showOverlayPermissionSnackOnce(); |
|
|
|
|
|
} |
|
|
|
|
|
return granted; |
|
|
|
|
|
} finally { |
|
|
|
|
|
_overlayPermissionRequesting = false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
Future<void> _stopAndroidRecordingFloatingBar() async { |
|
|
Future<void> _stopAndroidRecordingFloatingBar() async { |
|
|
if (!Platform.isAndroid) return; |
|
|
if (!Platform.isAndroid) return; |
|
|
_recordingFloatingBarTimer?.cancel(); |
|
|
_recordingFloatingBarTimer?.cancel(); |
|
|
@ -513,6 +559,9 @@ class MeetingRecordController extends GetxController |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
isRecording.value = true; |
|
|
isRecording.value = true; |
|
|
|
|
|
_overlayPermissionPromptedThisSession = false; |
|
|
|
|
|
_overlayPermissionSnackShownThisSession = false; |
|
|
|
|
|
_overlayPermissionRequesting = false; |
|
|
// 更新录音状态 |
|
|
// 更新录音状态 |
|
|
fileName.value = fullFileName; |
|
|
fileName.value = fullFileName; |
|
|
newName.value = fullFileName; |
|
|
newName.value = fullFileName; |
|
|
|