兼容 IOS
This commit is contained in:
@@ -7,6 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:recording_tool/core/logging/app_logger.dart';
|
||||
import 'package:recording_tool/core/permission/permission_service.dart';
|
||||
import 'package:recording_tool/core/platform/app_platform_info.dart';
|
||||
import 'package:recording_tool/features/recording/model/model_clipboard.dart';
|
||||
import 'package:recording_tool/features/recording/model/model_recording.dart';
|
||||
import 'package:recording_tool/features/recording/model/model_recording_session.dart';
|
||||
@@ -31,15 +32,19 @@ enum ClipboardReadResult {
|
||||
invalid,
|
||||
}
|
||||
|
||||
List<Permission> recordingGalleryPermissionsForHost({
|
||||
List<Permission> recordingFileSavePermissionsForHost({
|
||||
required bool isIOS,
|
||||
required bool isAndroid,
|
||||
int? androidSdkInt,
|
||||
}) {
|
||||
if (isIOS) {
|
||||
return [Permission.photosAddOnly];
|
||||
return const [];
|
||||
}
|
||||
if (isAndroid) {
|
||||
return [Permission.videos, Permission.storage];
|
||||
if (androidSdkInt != null && androidSdkInt >= 29) {
|
||||
return const [];
|
||||
}
|
||||
return [Permission.storage];
|
||||
}
|
||||
return const [];
|
||||
}
|
||||
@@ -144,11 +149,12 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
return;
|
||||
}
|
||||
|
||||
final fileSavePermissions = await _fileSavePermissions();
|
||||
final permissions = await PermissionService.requestMissing([
|
||||
Permission.camera,
|
||||
Permission.microphone,
|
||||
if (Platform.isAndroid) Permission.notification,
|
||||
..._galleryPermissions(),
|
||||
...fileSavePermissions,
|
||||
]);
|
||||
|
||||
final cameraGranted = permissions[Permission.camera]?.isGranted ?? false;
|
||||
@@ -170,8 +176,8 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
if (!microphoneGranted) {
|
||||
warnings.add('未授予麦克风权限,当前将以静音模式录制');
|
||||
}
|
||||
if (!_isGalleryPermissionGranted(permissions)) {
|
||||
warnings.add('未授予相册权限,录制结束后可能无法保存到相册');
|
||||
if (!_isFileSavePermissionGranted(permissions, fileSavePermissions)) {
|
||||
warnings.add('未授予文件保存权限,录制结束后可能无法保存到文件夹');
|
||||
}
|
||||
|
||||
final hasDnd = await RecordingPlatform.hasNotificationPolicyAccess();
|
||||
@@ -258,24 +264,36 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 当前平台所需的相册/视频保存权限列表。
|
||||
List<Permission> _galleryPermissions() {
|
||||
return recordingGalleryPermissionsForHost(
|
||||
/// 当前平台所需的视频文件保存权限列表。
|
||||
Future<List<Permission>> _fileSavePermissions() async {
|
||||
int? androidSdkInt;
|
||||
if (Platform.isAndroid) {
|
||||
try {
|
||||
androidSdkInt = int.tryParse(
|
||||
(await AppPlatformInfo.deviceInfo()).values['sdkInt'] ?? '',
|
||||
);
|
||||
} on PlatformException {
|
||||
androidSdkInt = null;
|
||||
}
|
||||
}
|
||||
return recordingFileSavePermissionsForHost(
|
||||
isIOS: Platform.isIOS,
|
||||
isAndroid: Platform.isAndroid,
|
||||
androidSdkInt: androidSdkInt,
|
||||
);
|
||||
}
|
||||
|
||||
/// 判断相册相关权限是否至少有一项已授予。
|
||||
bool _isGalleryPermissionGranted(
|
||||
/// 判断文件保存相关权限是否至少有一项已授予。
|
||||
bool _isFileSavePermissionGranted(
|
||||
Map<Permission, PermissionStatus> permissions,
|
||||
List<Permission> fileSavePermissions,
|
||||
) {
|
||||
for (final permission in _galleryPermissions()) {
|
||||
for (final permission in fileSavePermissions) {
|
||||
if (permissions[permission]?.isGranted ?? false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return _galleryPermissions().isEmpty;
|
||||
return fileSavePermissions.isEmpty;
|
||||
}
|
||||
|
||||
/// 检测并尝试申请相机、麦克风权限,同步更新 session 中的 isMicrophoneGranted。
|
||||
@@ -338,7 +356,7 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
lastOutputPath: result.outputPath,
|
||||
isTouchLocked: true,
|
||||
errorMessage: null,
|
||||
gallerySaveFailed: false,
|
||||
fileSaveFailed: false,
|
||||
clearLastSaved: true,
|
||||
),
|
||||
);
|
||||
@@ -351,13 +369,13 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 停止录制、保存到相册,并恢复相机预览。
|
||||
/// 停止录制、保存到文件夹,并恢复相机预览。
|
||||
Future<void> stopRecording() async {
|
||||
if (!state.session.isRecording) return;
|
||||
|
||||
try {
|
||||
final result = await RecordingPlatform.stopRecording();
|
||||
final galleryFailed = !result.gallerySaved;
|
||||
final fileFailed = !result.fileSaved;
|
||||
final savedName = recordingFileNameForPlatform(
|
||||
state.clipboardRecordingModel.filename,
|
||||
);
|
||||
@@ -365,11 +383,11 @@ class RecordingViewModel extends Notifier<RecordingModel> {
|
||||
(s) => s.copyWith(
|
||||
status: result.status,
|
||||
lastOutputPath: result.outputPath ?? s.lastOutputPath,
|
||||
lastSavedDisplayName: galleryFailed ? null : savedName,
|
||||
errorMessage: galleryFailed
|
||||
? (result.galleryErrorMessage ?? '保存到相册失败,请开启相册权限')
|
||||
lastSavedDisplayName: fileFailed ? null : savedName,
|
||||
errorMessage: fileFailed
|
||||
? (result.fileErrorMessage ?? '保存到文件夹失败,请检查文件保存权限')
|
||||
: null,
|
||||
gallerySaveFailed: galleryFailed,
|
||||
fileSaveFailed: fileFailed,
|
||||
),
|
||||
);
|
||||
} on PlatformException catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user