优化录制页性能
This commit is contained in:
@@ -8,6 +8,7 @@ import 'package:recording_tool/features/recording/model/model_recording.dart';
|
||||
import 'package:recording_tool/features/recording/model/model_recording_context.dart';
|
||||
import 'package:recording_tool/features/recording/model/model_recording_session.dart';
|
||||
import 'package:recording_tool/features/recording/platform/recording_platform.dart';
|
||||
import 'package:recording_tool/features/recording/utils/recording_performance.dart';
|
||||
|
||||
/// 录制页状态 Provider。
|
||||
final recordingViewModelProvider =
|
||||
@@ -32,6 +33,8 @@ class RecordingRequiredPermissions {
|
||||
class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
Timer? _elapsedTimer;
|
||||
DateTime? _recordingStartedAt;
|
||||
RecordingRequiredPermissions? _cachedRequiredPermissions;
|
||||
var _sessionGeneration = 0;
|
||||
|
||||
/// 初始化状态并注册销毁回调。
|
||||
@override
|
||||
@@ -52,55 +55,88 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
state = state.copyWith(recordingContext: recordingContext);
|
||||
}
|
||||
|
||||
/// 申请权限并检查系统设置。
|
||||
Future<void> prepareSession() async {
|
||||
/// 准备相机和麦克风权限;已授权时复用当前会话结果。
|
||||
Future<RecordingRequiredPermissions> prepareRequiredPermissions({
|
||||
bool forceRefresh = false,
|
||||
}) async {
|
||||
final generation = _sessionGeneration;
|
||||
if (!RecordingPlatform.isSupported) {
|
||||
_updateSession((s) => s.copyWith(errorMessage: '当前设备不支持录制'));
|
||||
return;
|
||||
return const RecordingRequiredPermissions(
|
||||
cameraGranted: false,
|
||||
microphoneGranted: false,
|
||||
);
|
||||
}
|
||||
|
||||
final permissions = await PermissionService.requestMissing([
|
||||
Permission.camera,
|
||||
Permission.microphone,
|
||||
if (Platform.isAndroid) Permission.notification,
|
||||
]);
|
||||
|
||||
final cameraGranted = permissions[Permission.camera]?.isGranted ?? false;
|
||||
if (!cameraGranted) {
|
||||
_updateSession((s) => s.copyWith(errorMessage: '需要相机权限才能录制'));
|
||||
return;
|
||||
final cached = _cachedRequiredPermissions;
|
||||
if (!forceRefresh && cached?.allGranted == true) {
|
||||
return cached!;
|
||||
}
|
||||
|
||||
final microphoneGranted =
|
||||
permissions[Permission.microphone]?.isGranted ?? false;
|
||||
final permissions = await measureRecordingOperation(
|
||||
'required permissions',
|
||||
() => PermissionService.requestMissing([
|
||||
Permission.camera,
|
||||
Permission.microphone,
|
||||
]),
|
||||
);
|
||||
final result = RecordingRequiredPermissions(
|
||||
cameraGranted: _isPermissionGranted(permissions[Permission.camera]),
|
||||
microphoneGranted: _isPermissionGranted(
|
||||
permissions[Permission.microphone],
|
||||
),
|
||||
);
|
||||
if (generation != _sessionGeneration) return result;
|
||||
_cachedRequiredPermissions = result;
|
||||
final errorMessage = !result.cameraGranted
|
||||
? '需要相机权限才能录制'
|
||||
: (!result.microphoneGranted ? '需要录音权限才能录制' : null);
|
||||
|
||||
_updateSession(
|
||||
(s) => s.copyWith(
|
||||
isMicrophoneGranted: result.microphoneGranted,
|
||||
errorMessage: errorMessage,
|
||||
),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 加载不影响相机首帧的通知、勿扰和电池状态。
|
||||
Future<void> loadSystemAdvisories() async {
|
||||
final generation = _sessionGeneration;
|
||||
final notificationFuture = Platform.isAndroid
|
||||
? PermissionService.requestMissing([Permission.notification])
|
||||
: Future.value(<Permission, PermissionStatus>{});
|
||||
final results = await measureRecordingOperation(
|
||||
'system advisories',
|
||||
() => Future.wait<dynamic>([
|
||||
notificationFuture,
|
||||
RecordingPlatform.hasNotificationPolicyAccess(),
|
||||
RecordingPlatform.isIgnoringBatteryOptimizations(),
|
||||
]),
|
||||
);
|
||||
final notificationPermissions =
|
||||
results[0] as Map<Permission, PermissionStatus>;
|
||||
final notificationsGranted = Platform.isAndroid
|
||||
? (permissions[Permission.notification]?.isGranted ?? false)
|
||||
? _isPermissionGranted(notificationPermissions[Permission.notification])
|
||||
: true;
|
||||
|
||||
final hasDnd = results[1] as bool;
|
||||
final batteryIgnored = results[2] as bool;
|
||||
if (generation != _sessionGeneration) return;
|
||||
final warnings = <String>[];
|
||||
if (Platform.isAndroid && !notificationsGranted) {
|
||||
warnings.add('未授予通知权限,录制时可能看不到前台服务通知,系统更容易结束后台录制');
|
||||
}
|
||||
if (!microphoneGranted) {
|
||||
warnings.add('未授予麦克风权限,当前将以静音模式录制');
|
||||
}
|
||||
final hasDnd = await RecordingPlatform.hasNotificationPolicyAccess();
|
||||
final batteryIgnored =
|
||||
await RecordingPlatform.isIgnoringBatteryOptimizations();
|
||||
|
||||
_updateSession(
|
||||
(s) => s.copyWith(
|
||||
hasDndAccess: hasDnd,
|
||||
isBatteryOptimizedIgnored: batteryIgnored,
|
||||
isMicrophoneGranted: microphoneGranted,
|
||||
notificationsGranted: notificationsGranted,
|
||||
permissionWarning: warnings.isEmpty ? null : warnings.join('\n'),
|
||||
errorMessage: null,
|
||||
clearPermissionWarning: warnings.isEmpty,
|
||||
),
|
||||
);
|
||||
|
||||
_updateSession((s) => s.copyWith(errorMessage: null));
|
||||
}
|
||||
|
||||
void setPreviewReady({required bool ready, String? errorMessage}) {
|
||||
@@ -112,27 +148,8 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
/// 检测并尝试申请相机、麦克风权限,同步更新 session 中的 isMicrophoneGranted。
|
||||
Future<RecordingRequiredPermissions>
|
||||
ensureCameraAndMicrophonePermissions() async {
|
||||
final permissions = await PermissionService.requestMissing([
|
||||
Permission.camera,
|
||||
Permission.microphone,
|
||||
]);
|
||||
|
||||
final cameraGranted = _isPermissionGranted(permissions[Permission.camera]);
|
||||
final microphoneGranted = _isPermissionGranted(
|
||||
permissions[Permission.microphone],
|
||||
);
|
||||
|
||||
_updateSession((s) => s.copyWith(isMicrophoneGranted: microphoneGranted));
|
||||
|
||||
if (cameraGranted && !state.session.isPreviewReady) {
|
||||
_updateSession((s) => s.copyWith(errorMessage: null));
|
||||
_updateSession((s) => s.copyWith(isPreviewReady: true));
|
||||
}
|
||||
|
||||
return RecordingRequiredPermissions(
|
||||
cameraGranted: cameraGranted,
|
||||
microphoneGranted: microphoneGranted,
|
||||
);
|
||||
final cached = _cachedRequiredPermissions;
|
||||
return prepareRequiredPermissions(forceRefresh: cached?.allGranted != true);
|
||||
}
|
||||
|
||||
bool _isPermissionGranted(PermissionStatus? status) {
|
||||
@@ -282,11 +299,13 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
|
||||
/// 退出录制页时释放勿扰和会话状态(沉浸式由页面统一恢复)。
|
||||
Future<void> teardown() async {
|
||||
await RecordingPlatform.disableDoNotDisturb();
|
||||
_sessionGeneration++;
|
||||
_cachedRequiredPermissions = null;
|
||||
_recordingStartedAt = null;
|
||||
_elapsedTimer?.cancel();
|
||||
_elapsedTimer = null;
|
||||
state = state.copyWith(session: const RecordingSessionState());
|
||||
await RecordingPlatform.disableDoNotDisturb();
|
||||
}
|
||||
|
||||
/// Provider 销毁时取消状态流订阅。
|
||||
|
||||
Reference in New Issue
Block a user