Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add cancel token for darwin #1234

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ To know more about breaking changes, see the [Migration Guide][].

## Unreleased

*None.*
### Features

## 3.6.4
- Add `cancelToken` parameter to `AssetEntity.loadFile`.
- Add `cancelAllRequest` method to `PhotoManager`.
- The `getFile` and `getOriginBytes` methods are public.

### Fixes

Expand Down
19 changes: 19 additions & 0 deletions README-ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,25 @@ iCloud 文件只能在设备上的 Apple ID 正常登录时获取。
当账号要求重新输入密码验证时,未缓存在本地的 iCloud 文件将无法访问,
此时相关方法会抛出 `CloudPhotoLibraryErrorDomain` 错误。

**取消加载** (Since 3.7.0)

上述的 `AssetEntity` 方法均添加了 `cancelToken` 参数,
可以用于取消加载过程。

其他方法如果也添加了 `cancelToken` 参数,同样可以用于取消加载过程。

```dart
final PMCancelToken cancelToken = PMCancelToken();
final File? file = await yourAssetEntity.loadFile(cancelToken: cancelToken);
await cancelToken.cancel();
```

`PhotoManager` 也有一个方法可以取消所有加载:

```dart
await PhotoManager.cancelAllRequest();
```

#### 展示资源

从 v3.0.0 开始,插件不再提供任何 UI 组件。
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,23 @@ When the account requires to re-enter the password to verify, iCloud files that
locally available are not allowed to be fetched. The photo library will throws
`CloudPhotoLibraryErrorDomain` in this circumstance.

**Cancel loading** (Since 3.7.0)

The methods in `AssetEntity` to add `cancelToken` parameter,
which can be used to cancel the loading process.

```dart
final PMCancelToken cancelToken = PMCancelToken();
final File? file = await yourAssetEntity.loadFile(cancelToken: cancelToken);
await cancelToken.cancel();
```

The `PhotoManager` also has a method to cancel all loading:

```dart
await PhotoManager.cancelAllRequest();
```

#### Display assets

> Starts from v3.0.0, `AssetEntityImage` and `AssetEntityImageProvider`
Expand Down
2 changes: 1 addition & 1 deletion ios/Classes/PMPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@class PMManager;
@class PMNotificationManager;

@interface PMPlugin : NSObject
@interface PMPlugin : NSObject<FlutterPlugin>
@property(nonatomic, strong) PMManager *manager;
@property(nonatomic, strong) PMNotificationManager *notificationManager;
- (void)registerPlugin:(NSObject <FlutterPluginRegistrar> *)registrar;
Expand Down
61 changes: 41 additions & 20 deletions ios/Classes/PMPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#import "PMLogUtils.h"
#import "PMManager.h"
#import "PMNotificationManager.h"
#import "ResultHandler.h"
#import "PMResultHandler.h"
#import "PMThumbLoadOption.h"
#import "PMProgressHandler.h"
#import "PMConverter.h"
Expand All @@ -19,6 +19,12 @@ @implementation PMPlugin {
BOOL isDetach;
}


+ (void)registerWithRegistrar:(nonnull NSObject<FlutterPluginRegistrar> *)registrar {
PMPlugin *plugin = [PMPlugin new];
[plugin registerPlugin:registrar];
}

- (void)registerPlugin:(NSObject <FlutterPluginRegistrar> *)registrar {
privateRegistrar = registrar;
[self initNotificationManager:registrar];
Expand All @@ -29,8 +35,9 @@ - (void)registerPlugin:(NSObject <FlutterPluginRegistrar> *)registrar {
manager.converter = [PMConverter new];
[self setManager:manager];

__block PMPlugin *weakSelf = self; // avoid retain cycle
[channel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
[self onMethodCall:call result:result];
[weakSelf onMethodCall:call result:result];
}];
}

Expand Down Expand Up @@ -119,7 +126,7 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
return;
}

ResultHandler *handler = [ResultHandler handlerWithCall:call result:result];
PMResultHandler *handler = [PMResultHandler handlerWithCall:call result:result];

if ([self isNotNeedPermissionMethod:call.method]) {
[self handleNotNeedPermissionMethod:handler];
Expand All @@ -130,7 +137,7 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
}
}

- (void)handleNotNeedPermissionMethod:(ResultHandler *)handler {
- (void)handleNotNeedPermissionMethod:(PMResultHandler *)handler {
FlutterMethodCall *call = handler.call;
NSString *method = call.method;
PMManager *manager = self.manager;
Expand All @@ -154,9 +161,9 @@ - (void)handleNotNeedPermissionMethod:(ResultHandler *)handler {
}
}

- (void)getPermissionState:(ResultHandler *)handler {
- (void)getPermissionState:(PMResultHandler *)handler {
int requestAccessLevel = [handler.call.arguments[@"iosAccessLevel"] intValue];
#if __IPHONE_14_0
#if TARGET_OS_IOS
if (@available(iOS 14, *)) {
PHAuthorizationStatus result = [PHPhotoLibrary authorizationStatusForAccessLevel: requestAccessLevel];
[handler reply: @(result)];
Expand All @@ -165,12 +172,17 @@ - (void)getPermissionState:(ResultHandler *)handler {
[handler reply:@(status)];
}
#else
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
[handler reply:@(status)];
if (@available(macOS 11.0, *)) {
PHAuthorizationStatus result = [PHPhotoLibrary authorizationStatusForAccessLevel: requestAccessLevel];
[handler reply: @(result)];
} else {
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
[handler reply:@(status)];
}
#endif
}

- (void)handleAboutPermissionMethod:(ResultHandler *)handler {
- (void)handleAboutPermissionMethod:(PMResultHandler *)handler {
FlutterMethodCall *call = handler.call;
PMManager *manager = self.manager;

Expand All @@ -182,7 +194,7 @@ - (void)handleAboutPermissionMethod:(ResultHandler *)handler {
}
}

- (void)replyPermssionResult:(ResultHandler *)handler status:(PHAuthorizationStatus)status isOnlyAdd:(BOOL)isOnlyAdd {
- (void)replyPermssionResult:(PMResultHandler *)handler status:(PHAuthorizationStatus)status isOnlyAdd:(BOOL)isOnlyAdd {
[handler reply:@(status)];
}

Expand All @@ -207,7 +219,7 @@ - (UIViewController *)getCurrentViewController {
#endif

- (void)handlePermission:(PMManager *)manager
handler:(ResultHandler *)handler
handler:(PMResultHandler *)handler
requestAccessLevel:(int)requestAccessLevel {
#if __IPHONE_14_0
if (@available(iOS 14, *)) {
Expand Down Expand Up @@ -245,7 +257,7 @@ - (void)requestPermissionStatus:(int)requestAccessLevel
#endif
}

- (void)presentLimited:(ResultHandler *)handler {
- (void)presentLimited:(PMResultHandler *)handler {
#if __IPHONE_14_0
if (@available(iOS 14, *)) {
UIViewController *controller = [self getCurrentViewController];
Expand Down Expand Up @@ -282,7 +294,7 @@ - (void)presentLimited:(ResultHandler *)handler {

#if TARGET_OS_OSX
- (void)handlePermission:(PMManager *)manager
handler:(ResultHandler*)handler
handler:(PMResultHandler*)handler
requestAccessLevel:(int)requestAccessLevel {
#if __MAC_11_0
if (@available(macOS 11.0, *)) {
Expand Down Expand Up @@ -320,21 +332,23 @@ - (void)requestPermissionStatus:(int)requestAccessLevel
#endif
}

- (void)presentLimited:(ResultHandler*)handler {
- (void)presentLimited:(PMResultHandler*)handler {
[handler replyError:@"Not supported on macOS."];
}

#endif

- (void)runInBackground:(dispatch_block_t)block withHandler:(ResultHandler *)handler {
- (void)runInBackground:(dispatch_block_t)block withHandler:(PMResultHandler *)handler {
dispatch_qos_class_t priority = [self getQosPriorityForMethod:handler.call.method];
dispatch_async(dispatch_get_global_queue(priority, 0), block);
}

- (dispatch_qos_class_t)getQosPriorityForMethod:(NSString *)method {
if ([method isEqualToString:@"getThumb"] ||
[method isEqualToString:@"assetExists"] ||
[method isEqualToString:@"isLocallyAvailable"]) {
[method isEqualToString:@"isLocallyAvailable"] ||
[method isEqualToString:@"cancelRequestWithCancelToken"] ||
[method isEqualToString:@"cancelAllRequest"]) {
return QOS_CLASS_USER_INTERACTIVE;
}

Expand Down Expand Up @@ -367,7 +381,7 @@ - (dispatch_qos_class_t)getQosPriorityForMethod:(NSString *)method {
return QOS_CLASS_DEFAULT;
}

- (void)onAuth:(ResultHandler *)handler {
- (void)onAuth:(PMResultHandler *)handler {
PMManager *manager = self.manager;
__block PMNotificationManager *notificationManager = self.notificationManager;

Expand All @@ -381,7 +395,7 @@ - (void)onAuth:(ResultHandler *)handler {
} withHandler:handler];
}

- (void)handleMethodResultHandler:(ResultHandler *)handler manager:(PMManager *)manager notificationManager:(PMNotificationManager *)notificationManager {
- (void)handleMethodResultHandler:(PMResultHandler *)handler manager:(PMManager *)manager notificationManager:(PMNotificationManager *)notificationManager {
FlutterMethodCall *call = handler.call;

if ([call.method isEqualToString:@"getAssetPathList"]) {
Expand Down Expand Up @@ -669,6 +683,13 @@ - (void)handleMethodResultHandler:(ResultHandler *)handler manager:(PMManager *)
} else if ([@"cancelCacheRequests" isEqualToString:call.method]) {
[manager cancelCacheRequests];
[handler reply:@YES];
} else if ([@"cancelRequestWithCancelToken" isEqualToString:call.method]) {
NSString *cancelToken = call.arguments[@"cancelToken"];
[manager cancelRequestWithCancelToken:cancelToken];
[handler reply:@YES];
} else if ([@"cancelAllRequest" isEqualToString:call.method]) {
[manager cancelAllRequest];
[handler reply:@YES];
} else {
[handler notImplemented];
}
Expand All @@ -692,7 +713,7 @@ - (PMProgressHandler *)getProgressHandlerFromDict:(NSDictionary *)dict {
return handler;
}

- (void)createFolder:(FlutterMethodCall *)call manager:(PMManager *)manager handler:(ResultHandler *)handler {
- (void)createFolder:(FlutterMethodCall *)call manager:(PMManager *)manager handler:(PMResultHandler *)handler {
NSString *name = call.arguments[@"name"];
BOOL isRoot = [call.arguments[@"isRoot"] boolValue];
NSString *parentId = call.arguments[@"folderId"];
Expand All @@ -709,7 +730,7 @@ - (void)createFolder:(FlutterMethodCall *)call manager:(PMManager *)manager hand
}];
}

- (void)createAlbum:(FlutterMethodCall *)call manager:(PMManager *)manager handler:(ResultHandler *)handler {
- (void)createAlbum:(FlutterMethodCall *)call manager:(PMManager *)manager handler:(PMResultHandler *)handler {
NSString *name = call.arguments[@"name"];
BOOL isRoot = [call.arguments[@"isRoot"] boolValue];
NSString *parentId = call.arguments[@"folderId"];
Expand Down
14 changes: 11 additions & 3 deletions ios/Classes/ResultHandler.h → ios/Classes/PMResultHandler.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#import <Foundation/Foundation.h>
#import "PMImport.h"
#import "PMResultHandler.h"

@interface ResultHandler : NSObject <PMResultHandler>
@interface PMResultHandler : NSObject

@property (nonatomic, strong) FlutterMethodCall* call;
@property(nonatomic, strong) FlutterMethodCall* call;
@property(nonatomic, strong) FlutterResult result;

- (instancetype)initWithResult:(FlutterResult)result;
Expand All @@ -13,5 +12,14 @@

+ (instancetype)handlerWithCall:(FlutterMethodCall *)call result:(FlutterResult)result;

- (void)replyError:(NSObject *)value;

- (void)reply:(id)obj;

- (void)notImplemented;

- (BOOL)isReplied;

- (NSString *)getCancelToken;

@end
13 changes: 9 additions & 4 deletions ios/Classes/ResultHandler.m → ios/Classes/PMResultHandler.m
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#import "ResultHandler.h"
#import "PMResultHandler.h"

@implementation ResultHandler {
@implementation PMResultHandler {
BOOL isReply;
}

- (instancetype)initWithResult:(FlutterResult)result {
self = [super init];
if (self) {
Expand All @@ -27,7 +28,6 @@ + (instancetype)handlerWithCall:(FlutterMethodCall *)call result:(FlutterResult)
return [[self alloc] initWithCall:call result:result];
}


- (void)reply:(id)obj {
if (isReply) {
return;
Expand Down Expand Up @@ -63,6 +63,7 @@ - (void)replyError:(NSObject *)value {
NSString *message = [NSString stringWithFormat:@"%@", [value description]];
flutterError = [FlutterError errorWithCode:code message:message details:nil];
}

if ([NSThread isMainThread]) {
self.result(flutterError);
} else {
Expand All @@ -80,10 +81,14 @@ - (void)notImplemented {
dispatch_async(dispatch_get_main_queue(), ^{
self.result(FlutterMethodNotImplemented);
});

}

- (BOOL)isReplied {
return isReply;
}

- (NSString *)getCancelToken {
return self.call.arguments[@"cancelToken"];
}

@end
6 changes: 5 additions & 1 deletion ios/Classes/core/PHAssetResource+PM_COMMON.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,14 @@ - (bool)isImageOrVideo {
- (bool)isValid {
bool isResource = self.type != PHAssetResourceTypeAdjustmentData;

#if __IPHONE_17_0
#if TARGET_OS_IOS
if (@available(iOS 17.0, *)) {
isResource = isResource && self.type != PHAssetResourceTypePhotoProxy;
}
#elif TARGET_OS_OSX
if (@available(macOS 14.0, *)) {
isResource = isResource && self.type != PHAssetResourceTypePhotoProxy;
}
#endif
return isResource;
}
Expand Down
Loading
Loading