状态管理 函数增加注释
This commit is contained in:
@@ -13,6 +13,7 @@ import 'package:recording_tool/features/recording/model/model_recording_session.
|
|||||||
import 'package:recording_tool/features/recording/platform/recording_platform.dart';
|
import 'package:recording_tool/features/recording/platform/recording_platform.dart';
|
||||||
import 'package:recording_tool/features/recording/utils/recording_display_name.dart';
|
import 'package:recording_tool/features/recording/utils/recording_display_name.dart';
|
||||||
|
|
||||||
|
/// 录制页状态 Provider。
|
||||||
final recordingViewModelProvider =
|
final recordingViewModelProvider =
|
||||||
NotifierProvider<RecordingViewModel, RecordingModel>(
|
NotifierProvider<RecordingViewModel, RecordingModel>(
|
||||||
RecordingViewModel.new,
|
RecordingViewModel.new,
|
||||||
@@ -30,6 +31,7 @@ enum ClipboardReadResult {
|
|||||||
invalid,
|
invalid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 录制页 ViewModel:剪贴板、权限、相机预览与录制流程。
|
||||||
class RecordingViewModel extends Notifier<RecordingModel> {
|
class RecordingViewModel extends Notifier<RecordingModel> {
|
||||||
static final _defaultClipboard = ClipboardRecordingModel(
|
static final _defaultClipboard = ClipboardRecordingModel(
|
||||||
title: '',
|
title: '',
|
||||||
@@ -38,19 +40,21 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
|
|
||||||
StreamSubscription<RecordingStatus>? _statusSubscription;
|
StreamSubscription<RecordingStatus>? _statusSubscription;
|
||||||
|
|
||||||
|
/// 初始化状态并注册销毁回调。
|
||||||
@override
|
@override
|
||||||
RecordingModel build() {
|
RecordingModel build() {
|
||||||
ref.onDispose(_dispose);
|
ref.onDispose(_dispose);
|
||||||
return RecordingModel(clipboardRecordingModel: _defaultClipboard);
|
return RecordingModel(clipboardRecordingModel: _defaultClipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 局部更新 session 子状态。
|
||||||
void _updateSession(
|
void _updateSession(
|
||||||
RecordingSessionState Function(RecordingSessionState session) update,
|
RecordingSessionState Function(RecordingSessionState session) update,
|
||||||
) {
|
) {
|
||||||
state = state.copyWith(session: update(state.session));
|
state = state.copyWith(session: update(state.session));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 从剪切板获取小程序复制的录制信息。
|
/// 读取并解析剪贴板中的小程序录制信息。
|
||||||
Future<ClipboardReadResult> getClipboardContent() async {
|
Future<ClipboardReadResult> getClipboardContent() async {
|
||||||
try {
|
try {
|
||||||
final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);
|
final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);
|
||||||
@@ -94,10 +98,12 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 清空剪贴板赛事信息(供 UI 调用)。
|
||||||
void resetClipboardInfo() {
|
void resetClipboardInfo() {
|
||||||
_resetClipboardInfo();
|
_resetClipboardInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 重置剪贴板赛事信息为默认空值。
|
||||||
void _resetClipboardInfo() {
|
void _resetClipboardInfo() {
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
clipboardRecordingModel: _defaultClipboard,
|
clipboardRecordingModel: _defaultClipboard,
|
||||||
@@ -105,6 +111,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 申请权限、检查系统设置并初始化相机预览。
|
||||||
Future<void> prepareSession() async {
|
Future<void> prepareSession() async {
|
||||||
if (!RecordingPlatform.isSupported) {
|
if (!RecordingPlatform.isSupported) {
|
||||||
_updateSession((s) => s.copyWith(errorMessage: '当前设备不支持录制'));
|
_updateSession((s) => s.copyWith(errorMessage: '当前设备不支持录制'));
|
||||||
@@ -179,6 +186,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 初始化相机预览,PlatformView 未就绪时自动重试。
|
||||||
Future<RecordingStatus> _initializePreviewWithRetry() async {
|
Future<RecordingStatus> _initializePreviewWithRetry() async {
|
||||||
const maxAttempts = 8;
|
const maxAttempts = 8;
|
||||||
for (var attempt = 0; attempt < maxAttempts; attempt++) {
|
for (var attempt = 0; attempt < maxAttempts; attempt++) {
|
||||||
@@ -196,7 +204,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
throw StateError('initializePreview retry exhausted');
|
throw StateError('initializePreview retry exhausted');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 停止录制后重新绑定相机预览(重置 isPreviewReady 以显示加载遮罩)。
|
/// 停止录制后重新绑定相机预览,并显示加载遮罩。
|
||||||
Future<void> restorePreview() async {
|
Future<void> restorePreview() async {
|
||||||
if (!RecordingPlatform.isSupported) return;
|
if (!RecordingPlatform.isSupported) return;
|
||||||
|
|
||||||
@@ -222,6 +230,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 当前平台所需的相册/视频保存权限列表。
|
||||||
List<Permission> _galleryPermissions() {
|
List<Permission> _galleryPermissions() {
|
||||||
if (Platform.isIOS) {
|
if (Platform.isIOS) {
|
||||||
return [Permission.photosAddOnly, Permission.photos];
|
return [Permission.photosAddOnly, Permission.photos];
|
||||||
@@ -232,6 +241,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
return const [];
|
return const [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 判断相册相关权限是否至少有一项已授予。
|
||||||
bool _isGalleryPermissionGranted(
|
bool _isGalleryPermissionGranted(
|
||||||
Map<Permission, PermissionStatus> permissions,
|
Map<Permission, PermissionStatus> permissions,
|
||||||
) {
|
) {
|
||||||
@@ -243,6 +253,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
return _galleryPermissions().isEmpty;
|
return _galleryPermissions().isEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 开始录制,可选开启勿扰模式。
|
||||||
Future<void> startRecording({bool enableDoNotDisturb = true}) async {
|
Future<void> startRecording({bool enableDoNotDisturb = true}) async {
|
||||||
final session = state.session;
|
final session = state.session;
|
||||||
if (!session.isPreviewReady ||
|
if (!session.isPreviewReady ||
|
||||||
@@ -282,6 +293,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 停止录制、保存到相册,并恢复相机预览。
|
||||||
Future<void> stopRecording() async {
|
Future<void> stopRecording() async {
|
||||||
if (!state.session.isRecording) return;
|
if (!state.session.isRecording) return;
|
||||||
|
|
||||||
@@ -311,30 +323,37 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 切换录制中触屏锁定状态。
|
||||||
void setTouchLocked(bool locked) {
|
void setTouchLocked(bool locked) {
|
||||||
_updateSession((s) => s.copyWith(isTouchLocked: locked));
|
_updateSession((s) => s.copyWith(isTouchLocked: locked));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 清除上次保存成功的录制结果标记。
|
||||||
void clearSavedRecordingResult() {
|
void clearSavedRecordingResult() {
|
||||||
_updateSession((s) => s.copyWith(clearLastSaved: true));
|
_updateSession((s) => s.copyWith(clearLastSaved: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 跳转系统勿扰/通知策略设置页。
|
||||||
Future<void> openDndSettings() =>
|
Future<void> openDndSettings() =>
|
||||||
RecordingPlatform.openNotificationPolicySettings();
|
RecordingPlatform.openNotificationPolicySettings();
|
||||||
|
|
||||||
|
/// 重新检测勿扰模式权限并更新状态。
|
||||||
Future<void> refreshDndAccess() async {
|
Future<void> refreshDndAccess() async {
|
||||||
final hasDnd = await RecordingPlatform.hasNotificationPolicyAccess();
|
final hasDnd = await RecordingPlatform.hasNotificationPolicyAccess();
|
||||||
_updateSession((s) => s.copyWith(hasDndAccess: hasDnd));
|
_updateSession((s) => s.copyWith(hasDndAccess: hasDnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 跳转电池优化白名单设置页。
|
||||||
Future<void> openBatterySettings() =>
|
Future<void> openBatterySettings() =>
|
||||||
RecordingPlatform.openBatteryOptimizationSettings();
|
RecordingPlatform.openBatteryOptimizationSettings();
|
||||||
|
|
||||||
|
/// 重新检测是否已忽略电池优化并更新状态。
|
||||||
Future<void> refreshBatteryOptimization() async {
|
Future<void> refreshBatteryOptimization() async {
|
||||||
final ignored = await RecordingPlatform.isIgnoringBatteryOptimizations();
|
final ignored = await RecordingPlatform.isIgnoringBatteryOptimizations();
|
||||||
_updateSession((s) => s.copyWith(isBatteryOptimizedIgnored: ignored));
|
_updateSession((s) => s.copyWith(isBatteryOptimizedIgnored: ignored));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 退出录制页时释放相机、勿扰和状态订阅。
|
||||||
Future<void> teardown() async {
|
Future<void> teardown() async {
|
||||||
await RecordingPlatform.setImmersiveMode(enabled: false);
|
await RecordingPlatform.setImmersiveMode(enabled: false);
|
||||||
await RecordingPlatform.disableDoNotDisturb();
|
await RecordingPlatform.disableDoNotDisturb();
|
||||||
@@ -344,6 +363,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
state = state.copyWith(session: const RecordingSessionState());
|
state = state.copyWith(session: const RecordingSessionState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 订阅原生层录制状态流并同步到 session。
|
||||||
Future<void> _listenStatus() async {
|
Future<void> _listenStatus() async {
|
||||||
await _statusSubscription?.cancel();
|
await _statusSubscription?.cancel();
|
||||||
_statusSubscription = RecordingPlatform.statusStream().listen((status) {
|
_statusSubscription = RecordingPlatform.statusStream().listen((status) {
|
||||||
@@ -351,6 +371,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provider 销毁时取消状态流订阅。
|
||||||
Future<void> _dispose() async {
|
Future<void> _dispose() async {
|
||||||
await _statusSubscription?.cancel();
|
await _statusSubscription?.cancel();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user