diff --git a/CHANGELOG.md b/CHANGELOG.md index b4825d69..ae2a6975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,11 @@ To know more about breaking changes, see the [Migration Guide][]. ### Breaking changes -`saveImage` now requires `title` rather than `filename`. +`saveLivePhoto` now requires `title` rather than `filename`. + +### Featuers + +- Add `getPermissionState` method to `PhotoManager`. ### Improvements diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/constant/Methods.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/constant/Methods.kt index ada5b7b6..c30d5cb1 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/constant/Methods.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/constant/Methods.kt @@ -1,5 +1,6 @@ package com.fluttercandies.photo_manager.constant +@Suppress("MemberVisibilityCanBePrivate", "ConstPropertyName") class Methods { companion object { // Not need permission methods @@ -10,6 +11,7 @@ class Methods { const val clearFileCache = "clearFileCache" const val releaseMemoryCache = "releaseMemoryCache" const val ignorePermissionCheck = "ignorePermissionCheck" + const val getPermissionState = "getPermissionState" fun isNotNeedPermissionMethod(method: String): Boolean { return method in arrayOf( @@ -20,6 +22,7 @@ class Methods { clearFileCache, releaseMemoryCache, ignorePermissionCheck, + getPermissionState, ) } // Not need permission methods end diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt index a9e1ff56..158e7df3 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt @@ -61,6 +61,7 @@ class PhotoManagerPlugin( fun bindActivity(activity: Activity?) { this.activity = activity + permissionsUtils.withActivity(activity) deleteManager.bindActivity(activity) } @@ -322,6 +323,15 @@ class PhotoManagerPlugin( ignorePermissionCheck = ignore resultHandler.reply(ignore) } + + Methods.getPermissionState -> { + val androidPermission = call.argument>("androidPermission")!! + val requestType = androidPermission["type"] as Int + val mediaLocation = androidPermission["mediaLocation"] as Boolean + permissionsUtils.getAuthValue(requestType, mediaLocation).let { + resultHandler.reply(it.value) + } + } } } diff --git a/example/lib/page/developer/develop_index_page.dart b/example/lib/page/developer/develop_index_page.dart index bd32ba1c..62fe1c20 100644 --- a/example/lib/page/developer/develop_index_page.dart +++ b/example/lib/page/developer/develop_index_page.dart @@ -18,6 +18,7 @@ import 'dev_title_page.dart'; import 'ios/create_folder_example.dart'; import 'ios/edit_asset.dart'; import 'issues_page/issue_index_page.dart'; +import 'permission_state_page.dart'; import 'remove_all_android_not_exists_example.dart'; import 'verbose_log_page.dart'; @@ -78,6 +79,10 @@ class _DeveloperIndexPageState extends State { onPressed: () => navToWidget(const ColumnNamesPage()), child: const Text('Android: column names'), ), + ElevatedButton( + onPressed: () => navToWidget(const PermissionStatePage()), + child: const Text('Show permission state page'), + ), ElevatedButton( child: const Text('Show iOS create folder example.'), onPressed: () => navToWidget(const CreateFolderExample()), diff --git a/example/lib/page/developer/permission_state_page.dart b/example/lib/page/developer/permission_state_page.dart new file mode 100644 index 00000000..72a88a81 --- /dev/null +++ b/example/lib/page/developer/permission_state_page.dart @@ -0,0 +1,121 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:photo_manager/photo_manager.dart'; + +extension on List { + List paddingAll(double padding) { + return map((e) => Padding(padding: EdgeInsets.all(padding), child: e)) + .toList(); + } +} + +class PermissionStatePage extends StatefulWidget { + const PermissionStatePage({super.key}); + + @override + State createState() => _PermissionStatePageState(); +} + +class _PermissionStatePageState extends State { + List types = [ + RequestType.image.value, + RequestType.video.value, + ]; + + RequestType get _selectedType { + return RequestType.fromTypes(types.map((e) => RequestType(e)).toList()); + } + + PermissionState? _permissionState; + + IosAccessLevel _iosAccessLevel = IosAccessLevel.readWrite; // 添加这一行 + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Permission State'), + ), + body: ListView( + children: [ + if (Platform.isAndroid) + Column( + children: RequestType.values.map((RequestType type) { + return CheckboxListTile( + title: Text(type.toString().split('.').last), + value: types.contains(type.value), + onChanged: (bool? value) { + setState(() { + if (value == true) { + types.add(type.value); + } else { + types.remove(type.value); + } + }); + }, + ); + }).toList(), + ), + if (Platform.isIOS) + Column( + children: [ + Text('iOS Access Level: $_iosAccessLevel'), + DropdownButton( + value: _iosAccessLevel, + onChanged: (IosAccessLevel? value) { + setState(() { + _iosAccessLevel = value!; + }); + }, + items: IosAccessLevel.values.map((IosAccessLevel value) { + return DropdownMenuItem( + value: value, + child: Text(value.toString()), + ); + }).toList(), + ), + ], + ), + ElevatedButton( + onPressed: _requestPermission, + child: const Text('Request Permission'), + ), + ElevatedButton( + onPressed: _getPermissionState, + child: const Text('Get Permission State'), + ), + if (_permissionState != null) + Text('Current Permission State: $_permissionState'), + ].paddingAll(16), + ), + ); + } + + Future _requestPermission() async { + final PermissionRequestOption option = _option(); + final result = + await PhotoManager.requestPermissionExtend(requestOption: option); + setState(() { + _permissionState = result; + }); + } + + PermissionRequestOption _option() { + final type = _selectedType; + final PermissionRequestOption option = PermissionRequestOption( + androidPermission: AndroidPermission(type: type, mediaLocation: false), + iosAccessLevel: IosAccessLevel.readWrite, + ohosPermissions: const [], + ); + return option; + } + + Future _getPermissionState() async { + final PermissionRequestOption option = _option(); + final state = await PhotoManager.getPermissionState(requestOption: option); + setState(() { + _permissionState = state; + }); + } +} diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 39161552..11afc4a9 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -202,7 +202,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 77e492c1..1562d56a 100644 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ getPermissionState( + PermissionRequestOption requestOption, + ) async { + final int result = await _channel.invokeMethod( + PMConstants.mGetPermissionState, + requestOption.toMap(), + ); + return PermissionState.values[result]; + } } mixin IosPlugin on BasePlugin { diff --git a/lib/src/managers/photo_manager.dart b/lib/src/managers/photo_manager.dart index d1a2316b..640e196d 100644 --- a/lib/src/managers/photo_manager.dart +++ b/lib/src/managers/photo_manager.dart @@ -57,6 +57,34 @@ class PhotoManager { return plugin.requestPermissionExtend(requestOption); } + /// Get the current [PermissionState] of the photo library + /// with the given [requestOption]. + /// + /// Example: + /// ```dart + /// final PermissionState state = await PhotoManager.getPermissionState( + /// requestOption: const PermissionRequestOption( + /// androidPermission: AndroidPermission( + // type: RequestType.image, + // mediaLocation: false, + // ), + /// ), + /// ); + /// if (state == PermissionState.authorized) { + /// print('The application has full access permission'); + /// } else { + /// print('The application does not have full access permission'); + /// } + /// ``` + /// + /// Note: On Android, this method may require an `Activity` context. + /// Call [setIgnorePermissionCheck] if the call is from background service. + static Future getPermissionState({ + required PermissionRequestOption requestOption, + }) { + return plugin.getPermissionState(requestOption); + } + /// Prompts the limited assets selection modal on iOS. /// /// This method only supports from iOS 14.0, and will behave differently on diff --git a/lib/src/types/types.dart b/lib/src/types/types.dart index d5c62a53..05165253 100644 --- a/lib/src/types/types.dart +++ b/lib/src/types/types.dart @@ -82,7 +82,19 @@ class RequestType { int get hashCode => value; @override - String toString() => '$runtimeType($value)'; + String toString() { + final values = []; + if (containsImage()) { + values.add('image'); + } + if (containsVideo()) { + values.add('video'); + } + if (containsAudio()) { + values.add('audio'); + } + return 'RequestType(${values.join(', ')})'; + } } /// See [PermissionState].