From 9496772c9f074bc34048c7d6c5c4b89c02bcf84b Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 28 Apr 2021 09:25:37 +0200 Subject: [PATCH 01/44] Add PHPicker libraries and its delegate I have to implement PHPicker to select photos, live photos and videos from the photo library for iOS 14 and higher versions. But I also have to keep old UIImagePickerController for lower iOS versions and to use camera. --- .../image_picker/ios/Classes/FLTImagePickerPlugin.h | 3 +++ .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h index 3b3551d53461..b8e46df21f21 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h @@ -3,11 +3,14 @@ // found in the LICENSE file. #import +#import +API_AVAILABLE(ios(14)) @interface FLTImagePickerPlugin : NSObject // For testing only. - (UIImagePickerController *)getImagePickerController; - (UIViewController *)viewControllerWithWindow:(UIWindow *)window; +- (PHPickerViewController *)getPickerViewController; @end diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 9159ea4c990b..00cca4fc7153 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -8,12 +8,15 @@ #import #import #import +#import +#import +#import #import "FLTImagePickerImageUtil.h" #import "FLTImagePickerMetaDataUtil.h" #import "FLTImagePickerPhotoAssetUtil.h" -@interface FLTImagePickerPlugin () +@interface FLTImagePickerPlugin () @property(copy, nonatomic) FlutterResult result; @@ -25,7 +28,9 @@ @interface FLTImagePickerPlugin () *)registrar { @@ -40,6 +45,10 @@ - (UIImagePickerController *)getImagePickerController { return _imagePickerController; } +- (PHPickerViewController *)getPickerViewController { + return _pickerViewController; +} + - (UIViewController *)viewControllerWithWindow:(UIWindow *)window { UIWindow *windowToUse = window; if (windowToUse == nil) { From a4f84164609f1a77b79f80756967e51028363192 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 28 Apr 2021 09:34:17 +0200 Subject: [PATCH 02/44] Add PHPicker implementation --- .../ios/Classes/FLTImagePickerPlugin.m | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 00cca4fc7153..51ff9e16aece 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -67,15 +67,20 @@ - (UIViewController *)viewControllerWithWindow:(UIWindow *)window { return topController; } -- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { - if (self.result) { - self.result([FlutterError errorWithCode:@"multiple_request" - message:@"Cancelled by a second request" - details:nil]); - self.result = nil; - } +- (void)pickImageWithPHPicker:(bool)single { + PHPhotoLibrary *photoLibrary = PHPhotoLibrary.sharedPhotoLibrary; // This step is required to fetch PHAsset + PHPickerConfiguration *config = [[PHPickerConfiguration alloc] initWithPhotoLibrary:photoLibrary]; + if (!single) { + config.selectionLimit = 0; // Setting to zero allow us to pick unlimited photos + } + config.filter = [PHPickerFilter imagesFilter]; - if ([@"pickImage" isEqualToString:call.method]) { + _pickerViewController = + [[PHPickerViewController alloc] initWithConfiguration:config]; + _pickerViewController.delegate = self; + + [self checkPhotoAuthorization]; +} _imagePickerController = [[UIImagePickerController alloc] init]; _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; _imagePickerController.delegate = self; From e8c128c82e1d47191c2c1eb766d8ec35bc8892a7 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 28 Apr 2021 10:02:31 +0200 Subject: [PATCH 03/44] Refactor UIImagePickerController implementation I moved the UIImagePickerController implementation into pickImageWithUIImagePicker method for code reusability. --- .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 51ff9e16aece..97d68af37320 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -81,14 +81,14 @@ - (void)pickImageWithPHPicker:(bool)single { [self checkPhotoAuthorization]; } + +- (void)pickImageWithUIImagePicker { + _imagePickerController = [[UIImagePickerController alloc] init]; _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; _imagePickerController.delegate = self; _imagePickerController.mediaTypes = @[ (NSString *)kUTTypeImage ]; - self.result = result; - _arguments = call.arguments; - int imageSource = [[_arguments objectForKey:@"source"] intValue]; switch (imageSource) { @@ -103,7 +103,7 @@ - (void)pickImageWithPHPicker:(bool)single { [self checkPhotoAuthorization]; break; default: - result([FlutterError errorWithCode:@"invalid_source" + self.result([FlutterError errorWithCode:@"invalid_source" message:@"Invalid image source." details:nil]); break; From 0305c423baaecd09fdacda21d4f897aec9d9b01d Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 28 Apr 2021 10:07:15 +0200 Subject: [PATCH 04/44] Refactor handleMethodCall function --- .../ios/Classes/FLTImagePickerPlugin.m | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 97d68af37320..63e128f9ee90 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -108,6 +108,45 @@ - (void)pickImageWithUIImagePicker { details:nil]); break; } +} + + + +- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { + if (self.result) { + self.result([FlutterError errorWithCode:@"multiple_request" + message:@"Cancelled by a second request" + details:nil]); + self.result = nil; + } + + if ([@"pickImage" isEqualToString:call.method]) { + + _phPickerFlag = NO; + self.result = result; + _arguments = call.arguments; + int imageSource = [[_arguments objectForKey:@"source"] intValue]; + + if (imageSource == SOURCE_GALLERY) { // Capture is not possible with PHPicker + if (@available(iOS 14, *)) { + //PHPicker is used + _phPickerFlag = YES; + [self pickImageWithPHPicker:true]; + } else { + //UIImagePicker is used + [self pickImageWithUIImagePicker]; + } + } else { + [self pickImageWithUIImagePicker]; + } + } else if ([@"pickMultiImage" isEqualToString:call.method]) { + if (@available(iOS 14, *)) { + NSLog(@"pickImage has been called on iOS14+"); + self.result = result; + _arguments = call.arguments; + NSLog(@"Result and arguments have been set"); + [self pickImageWithPHPicker:false]; + } } else if ([@"pickVideo" isEqualToString:call.method]) { _imagePickerController = [[UIImagePickerController alloc] init]; _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; From 55cd7731775aca6ad50bd3f30b6d5e879a47c113 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 28 Apr 2021 10:18:59 +0200 Subject: [PATCH 05/44] Refactor showPhotoLibrary function --- .../ios/Classes/FLTImagePickerPlugin.m | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 63e128f9ee90..50761be77499 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -301,10 +301,17 @@ - (void)errorNoPhotoAccess:(PHAuthorizationStatus)status { - (void)showPhotoLibrary { // No need to check if SourceType is available. It always is. - _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; - [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController - animated:YES - completion:nil]; + if(_phPickerFlag) { + [[self viewControllerWithWindow:nil] presentViewController:_pickerViewController + animated:YES + completion:nil]; + } else { + _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController + animated:YES + completion:nil]; + } +} } - (void)imagePickerController:(UIImagePickerController *)picker From 1516e737986e3c8fee80e0c02383815ea9a1a185 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 28 Apr 2021 10:24:53 +0200 Subject: [PATCH 06/44] Add the limited access into the photo library I refactored the checkPhotoAuthorization function to add limited access functionality. Also I implemented showLimitedPhotoLibrary function to call presentLimitedLibraryPickerFromViewController. --- .../ios/Classes/FLTImagePickerPlugin.m | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 50761be77499..e9eda6578d31 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -250,8 +250,19 @@ - (void)checkPhotoAuthorization { dispatch_async(dispatch_get_main_queue(), ^{ [self showPhotoLibrary]; }); + } else if (@available(iOS 14, *)) { + if (status == PHAuthorizationStatusLimited) { + dispatch_async(dispatch_get_main_queue(), ^{ + // Add PHPhotoLibraryPreventAutomaticLimitedAccessAlert = YES into the Info.plist + // Check status == PHAuthorizationStatusLimited then call showLimitedPhotoLibrary function + // Use presentLimitedLibraryPickerFromViewController in showLimitedPhotoLibrary function + [self showLimitedPhotoLibrary]; // Implemented limited access to the photo library by above instructions + }); + } else { + [self errorNoPhotoAccess:status]; + } } else { - [self errorNoPhotoAccess:status]; + [self errorNoPhotoAccess:status]; } }]; break; @@ -312,6 +323,10 @@ - (void)showPhotoLibrary { completion:nil]; } } + +// Limited access to photo library +- (void)showLimitedPhotoLibrary { + [[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:_pickerViewController]; } - (void)imagePickerController:(UIImagePickerController *)picker From 5b64833697cc9d7cf6d2891539ec485657f43d40 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 28 Apr 2021 10:29:59 +0200 Subject: [PATCH 07/44] Add the implementation of picker function I implemented picker function that is came from PHPickerViewControllerDelegate. --- .../ios/Classes/FLTImagePickerPlugin.m | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index e9eda6578d31..3fe5808d445b 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -329,6 +329,64 @@ - (void)showLimitedPhotoLibrary { [[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:_pickerViewController]; } + +- (void)picker:(PHPickerViewController *)picker + didFinishPicking:(NSArray *)results API_AVAILABLE(ios(14)) { + [picker dismissViewControllerAnimated:YES completion:nil]; + + for (PHPickerResult *result in results) { + [result.itemProvider + loadObjectOfClass:[UIImage class] + completionHandler:^(__kindof id _Nullable image, + NSError *_Nullable error) { + if ([image isKindOfClass:[UIImage class]]) { + if (image != nil) { + + NSNumber *maxWidth = [self->_arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [self->_arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; + + if (![imageQuality isKindOfClass:[NSNumber class]]) { + imageQuality = @1; + } else if (imageQuality.intValue < 0 || imageQuality.intValue > 100) { + imageQuality = [NSNumber numberWithInt:1]; + } else { + imageQuality = @([imageQuality floatValue] / 100); + } + + if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) { + image = [FLTImagePickerImageUtil scaledImage:image maxWidth:maxWidth maxHeight:maxHeight]; + } + + PHFetchResult* fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[result.assetIdentifier] options:nil]; + PHAsset *originalAsset = fetchResult.firstObject; + + if (!originalAsset) { + // Image picked without an original asset (e.g. User took a photo directly) + [self saveImageWithPickerInfo:nil image:image imageQuality:imageQuality]; + } + else { + __weak typeof(self) weakSelf = self; + [[PHImageManager defaultManager] + requestImageDataForAsset:originalAsset + options:nil + resultHandler:^(NSData *_Nullable imageData, NSString *_Nullable dataUTI, + UIImageOrientation orientation, NSDictionary *_Nullable info) { + // maxWidth and maxHeight are used only for GIF images. + [weakSelf saveImageWithOriginalImageData:imageData + image:image + maxWidth:maxWidth + maxHeight:maxHeight + imageQuality:imageQuality]; + }]; + } + } + } + }]; + } +} + + - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL]; From 36b6a2aec20be6c76748f27a07d9f670d33a1313 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 28 Apr 2021 10:32:08 +0200 Subject: [PATCH 08/44] Refactor Info.plist file I added PHPhotoLibraryPreventAutomaticLimitedAccessAlert = YES into Info.plist to use limited access functionality. --- .../lib/model/android_device_info.dart | 2 +- .../google_maps_flutter_web/lib/src/circles.dart | 2 +- .../google_maps_flutter_web/lib/src/markers.dart | 2 +- .../google_maps_flutter_web/lib/src/polygons.dart | 2 +- .../google_maps_flutter_web/lib/src/polylines.dart | 2 +- .../image_picker/example/ios/Runner.xcodeproj/project.pbxproj | 2 -- .../image_picker/image_picker/example/ios/Runner/Info.plist | 2 ++ packages/webview_flutter/lib/webview_flutter.dart | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart index b61dc14a0420..961d373e2dea 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart @@ -29,7 +29,7 @@ class AndroidDeviceInfo { required this.isPhysicalDevice, required this.androidId, required List systemFeatures, - }) : supported32BitAbis = List.unmodifiable(supported32BitAbis), + }) : supported32BitAbis = List.unmodifiable(supported32BitAbis), supported64BitAbis = List.unmodifiable(supported64BitAbis), supportedAbis = List.unmodifiable(supportedAbis), systemFeatures = List.unmodifiable(systemFeatures); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart index ae8faa038ea6..2a19d87adfec 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart @@ -15,7 +15,7 @@ class CirclesController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. CirclesController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _circleIdToController = Map(); /// Returns the cache of [CircleController]s. Test only. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart index b650b9bcf1c8..704577b6e3fb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart @@ -15,7 +15,7 @@ class MarkersController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. MarkersController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _markerIdToController = Map(); /// Returns the cache of [MarkerController]s. Test only. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart index 8a9643156351..ef51bd6043df 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart @@ -15,7 +15,7 @@ class PolygonsController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolygonsController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _polygonIdToController = Map(); /// Returns the cache of [PolygonController]s. Test only. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart index 695b29554c04..184c0d954744 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart @@ -15,7 +15,7 @@ class PolylinesController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolylinesController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _polylineIdToController = Map(); /// Returns the cache of [PolylineContrller]s. Test only. diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj index f9895f0cc06f..3409e7eaefec 100644 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -10,7 +10,6 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 5C9513011EC38BD300040975 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C9513001EC38BD300040975 /* GeneratedPluginRegistrant.m */; }; 680049262280D736006DD6AB /* MetaDataUtilTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 680049252280D736006DD6AB /* MetaDataUtilTests.m */; }; - 680049272280D79A006DD6AB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 680049382280F2B9006DD6AB /* pngImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 680049352280F2B8006DD6AB /* pngImage.png */; }; 680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 680049362280F2B8006DD6AB /* jpgImage.jpg */; }; 6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6801C8382555D726009DAF8D /* ImagePickerFromGalleryUITests.m */; }; @@ -90,7 +89,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - F10E2DB84567A50A8721C9C7 /* libPods-RunnerUITests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/image_picker/image_picker/example/ios/Runner/Info.plist b/packages/image_picker/image_picker/example/ios/Runner/Info.plist index f9c1909383ca..e923191ad712 100755 --- a/packages/image_picker/image_picker/example/ios/Runner/Info.plist +++ b/packages/image_picker/image_picker/example/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + PHPhotoLibraryPreventAutomaticLimitedAccessAlert + CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 74d8af8d4687..92ff8e00a50e 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -180,7 +180,7 @@ class JavascriptChannel { JavascriptChannel({ required this.name, required this.onMessageReceived, - }) : assert(name != null), + }) : assert(name != null), assert(onMessageReceived != null), assert(_validChannelNames.hasMatch(name)); From 1d2679a2e2c0cfdaf6fc99d28f149ebfba2a17b6 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Thu, 29 Apr 2021 11:42:42 +0200 Subject: [PATCH 09/44] Add the function to get PHAssetResult --- .../ios/Classes/FLTImagePickerPhotoAssetUtil.h | 4 ++++ .../ios/Classes/FLTImagePickerPhotoAssetUtil.m | 8 ++++++++ .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 8 ++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h index ce37ff715caf..f373abc5dc41 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h @@ -4,6 +4,8 @@ #import #import +#import + #import "FLTImagePickerImageUtil.h" @@ -13,6 +15,8 @@ NS_ASSUME_NONNULL_BEGIN + (nullable PHAsset *)getAssetFromImagePickerInfo:(NSDictionary *)info; ++ (nullable PHAsset *)getAssetFromPHPickerResult:(PHPickerResult *)result; + // Save image with correct meta data and extention copied from the original asset. // maxWidth and maxHeight are used only for GIF images. + (NSString *)saveImageWithOriginalImageData:(NSData *)originalImageData diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m index caadc8ba4864..604ae3474a9e 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m @@ -23,6 +23,14 @@ + (PHAsset *)getAssetFromImagePickerInfo:(NSDictionary *)info { return result.firstObject; } ++ (PHAsset *)getAssetFromPHPickerResult:(PHPickerResult *)result { + if (@available(iOS 14, *)) { + PHFetchResult* fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[result.assetIdentifier] options:nil]; + return fetchResult.firstObject; + } + return nil; +} + + (NSString *)saveImageWithOriginalImageData:(NSData *)originalImageData image:(UIImage *)image maxWidth:(NSNumber *)maxWidth diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 3fe5808d445b..e87dfb49c8c9 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -253,9 +253,6 @@ - (void)checkPhotoAuthorization { } else if (@available(iOS 14, *)) { if (status == PHAuthorizationStatusLimited) { dispatch_async(dispatch_get_main_queue(), ^{ - // Add PHPhotoLibraryPreventAutomaticLimitedAccessAlert = YES into the Info.plist - // Check status == PHAuthorizationStatusLimited then call showLimitedPhotoLibrary function - // Use presentLimitedLibraryPickerFromViewController in showLimitedPhotoLibrary function [self showLimitedPhotoLibrary]; // Implemented limited access to the photo library by above instructions }); } else { @@ -324,7 +321,7 @@ - (void)showPhotoLibrary { } } -// Limited access to photo library +// Limited access to the photo library - (void)showLimitedPhotoLibrary { [[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:_pickerViewController]; } @@ -358,8 +355,7 @@ - (void)picker:(PHPickerViewController *)picker image = [FLTImagePickerImageUtil scaledImage:image maxWidth:maxWidth maxHeight:maxHeight]; } - PHFetchResult* fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[result.assetIdentifier] options:nil]; - PHAsset *originalAsset = fetchResult.firstObject; + PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:result]; if (!originalAsset) { // Image picked without an original asset (e.g. User took a photo directly) From 6566bf019c08fa07105b7a4a43d083d4adb2b0da Mon Sep 17 00:00:00 2001 From: yusufdag Date: Thu, 29 Apr 2021 11:45:55 +0200 Subject: [PATCH 10/44] Change the image to bypass HEIC problem --- .../example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m index a3ca1a1f8892..375a42d515c1 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -165,7 +165,7 @@ - (void)launchPickerAndPick { // Find an image and tap on it. (IOS 14 UI, images are showing directly) XCUIElement* aImage; if (@available(iOS 14, *)) { - aImage = self.app.scrollViews.firstMatch.images.firstMatch; + aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1]; } else { XCUIElement* allPhotosCell = [self.app.cells elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label == %@", @"All Photos"]]; From a4d2a122f30a58cbc49d80e41ae2eeadababece5 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Thu, 29 Apr 2021 11:47:35 +0200 Subject: [PATCH 11/44] Add UITest to test select photo functionality --- .../ios/Runner.xcodeproj/project.pbxproj | 4 + .../ImagePickerFromLimitedGalleryUITests.m | 181 ++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj index 3409e7eaefec..4cd7670a1453 100644 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 9FC8F0E9229FA49E00C8D58F /* gifImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */; }; 9FC8F0EC229FA68500C8D58F /* gifImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */; }; 9FC8F0EE229FB90B00C8D58F /* ImageUtilTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FC8F0ED229FB90B00C8D58F /* ImageUtilTests.m */; }; + BECB773E26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = BECB773D26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m */; }; F4F7A436CCA4BF276270A3AE /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EC32F6993F4529982D9519F1 /* libPods-Runner.a */; }; F78AF3192342D9D7008449C7 /* ImagePickerTestImages.m in Sources */ = {isa = PBXBuildFile; fileRef = F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */; }; /* End PBXBuildFile section */ @@ -79,6 +80,7 @@ 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = gifImage.gif; sourceTree = ""; }; 9FC8F0ED229FB90B00C8D58F /* ImageUtilTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ImageUtilTests.m; path = ../../../ios/Tests/ImageUtilTests.m; sourceTree = ""; }; A908FAEEA2A9B26D903C09C5 /* libPods-RunnerUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + BECB773D26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImagePickerFromLimitedGalleryUITests.m; sourceTree = ""; }; EC32F6993F4529982D9519F1 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F78AF3172342D9D7008449C7 /* ImagePickerTestImages.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ImagePickerTestImages.h; path = ../../../ios/Tests/ImagePickerTestImages.h; sourceTree = ""; }; F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ImagePickerTestImages.m; path = ../../../ios/Tests/ImagePickerTestImages.m; sourceTree = ""; }; @@ -124,6 +126,7 @@ F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */, 68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */, 6801C83A2555D726009DAF8D /* Info.plist */, + BECB773D26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m */, ); path = RunnerUITests; sourceTree = ""; @@ -393,6 +396,7 @@ buildActionMask = 2147483647; files = ( 6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */, + BECB773E26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m in Sources */, 9FC8F0EE229FB90B00C8D58F /* ImageUtilTests.m in Sources */, F78AF3192342D9D7008449C7 /* ImagePickerTestImages.m in Sources */, 680049262280D736006DD6AB /* MetaDataUtilTests.m in Sources */, diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m new file mode 100644 index 000000000000..cb35d037638f --- /dev/null +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m @@ -0,0 +1,181 @@ +// +// ImagePickerFromLimitedGalleryUITests.m +// RunnerUITests +// +// Created by Yusuf Dag on 28/04/2021. +// Copyright © 2021 The Flutter Authors. All rights reserved. +// + +#import +#import + +const int kLimitedElementWaitingTime = 30; + +@interface ImagePickerFromLimitedGalleryUITests : XCTestCase + +@property(nonatomic, strong) XCUIApplication* app; + +@end + +@implementation ImagePickerFromLimitedGalleryUITests + +- (void)setUp { + [super setUp]; + // Delete the app if already exists, to test permission popups + + self.continueAfterFailure = NO; + self.app = [[XCUIApplication alloc] init]; + [self.app launch]; + __weak typeof(self) weakSelf = self; + [self addUIInterruptionMonitorWithDescription:@"Permission popups" + handler:^BOOL(XCUIElement* _Nonnull interruptingElement) { + if (@available(iOS 14, *)) { + XCUIElement* limitedPhotoPermission = + [interruptingElement.buttons elementBoundByIndex:0]; + if (![limitedPhotoPermission waitForExistenceWithTimeout: + kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", + weakSelf.app.debugDescription); + XCTFail(@"Failed due to not able to find " + @"selectPhotos butt on with %@ seconds", + @(kLimitedElementWaitingTime)); + } + [limitedPhotoPermission tap]; + } else { + XCUIElement* ok = interruptingElement.buttons[@"OK"]; + if (![ok waitForExistenceWithTimeout: + kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", + weakSelf.app.debugDescription); + XCTFail(@"Failed due to not able to find ok button " + @"with %@ seconds", + @(kLimitedElementWaitingTime)); + } + [ok tap]; + } + return YES; + }]; +} + +- (void)tearDown { + [super tearDown]; + [self.app terminate]; +} + +- (void)testSelectingFromGallery { + [self launchPickerAndSelect]; +} + + +- (void)launchPickerAndSelect { + // Find and tap on the pick from gallery button. + NSPredicate* predicateToFindImageFromGalleryButton = + [NSPredicate predicateWithFormat:@"label == %@", @"image_picker_example_from_gallery"]; + + XCUIElement* imageFromGalleryButton = + [self.app.otherElements elementMatchingPredicate:predicateToFindImageFromGalleryButton]; + if (![imageFromGalleryButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find image from gallery button with %@ seconds", + @(kLimitedElementWaitingTime)); + } + + XCTAssertTrue(imageFromGalleryButton.exists); + [imageFromGalleryButton tap]; + + // Find and tap on the `pick` button. + NSPredicate* predicateToFindPickButton = + [NSPredicate predicateWithFormat:@"label == %@", @"PICK"]; + + XCUIElement* pickButton = [self.app.buttons elementMatchingPredicate:predicateToFindPickButton]; + if (![pickButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find pick button with %@ seconds", @(kLimitedElementWaitingTime)); + } + + XCTAssertTrue(pickButton.exists); + [pickButton tap]; + + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + [self.app tap]; + + // Find an image and tap on it. (IOS 14 UI, images are showing directly) + XCUIElement* aImage; + if (@available(iOS 14, *)) { + aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1]; + } else { + XCUIElement* selectedPhotosCell = [self.app.cells + elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label == %@", @"Selected Photos"]]; + if (![selectedPhotosCell waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find \"Selected Photos\" cell with %@ seconds", + @(kLimitedElementWaitingTime)); + } + [selectedPhotosCell tap]; + aImage = [self.app.collectionViews elementMatchingType:XCUIElementTypeCollectionView + identifier:@"PhotosGridView"] + .cells.firstMatch; + } + os_log_error(OS_LOG_DEFAULT, "description before picking image %@", self.app.debugDescription); + if (![aImage waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find an image with %@ seconds", @(kLimitedElementWaitingTime)); + } + XCTAssertTrue(aImage.exists); + [aImage tap]; + + // Find and tap on the `Done` button. + NSPredicate* predicateToFindDoneButton = + [NSPredicate predicateWithFormat:@"label == %@", @"Done"]; + + XCUIElement* doneButton = + [self.app.buttons elementMatchingPredicate:predicateToFindDoneButton]; + if (![doneButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find Cancel button with %@ seconds", + @(kLimitedElementWaitingTime)); + } + + XCTAssertTrue(doneButton.exists); + [doneButton tap]; + + // Find an image and tap on it to have access to selected photos. + if (@available(iOS 14, *)) { + aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1]; + } else { + XCUIElement* selectedPhotosCell = [self.app.cells + elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label == %@", @"Selected Photos"]]; + if (![selectedPhotosCell waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find \"Selected Photos\" cell with %@ seconds", + @(kLimitedElementWaitingTime)); + } + [selectedPhotosCell tap]; + aImage = [self.app.collectionViews elementMatchingType:XCUIElementTypeCollectionView + identifier:@"PhotosGridView"] + .cells.firstMatch; + } + os_log_error(OS_LOG_DEFAULT, "description before picking image %@", self.app.debugDescription); + if (![aImage waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find an image with %@ seconds", @(kLimitedElementWaitingTime)); + } + XCTAssertTrue(aImage.exists); + [aImage tap]; + + // Find the picked image. + NSPredicate* predicateToFindPickedImage = + [NSPredicate predicateWithFormat:@"label == %@", @"image_picker_example_picked_image"]; + + XCUIElement* pickedImage = [self.app.images elementMatchingPredicate:predicateToFindPickedImage]; + if (![pickedImage waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find pickedImage with %@ seconds", @(kLimitedElementWaitingTime)); + } + + XCTAssertTrue(pickedImage.exists); +} + + +@end From 9ed3fcf35a686f54ede36a18c4b62385573a48f3 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Thu, 29 Apr 2021 11:48:26 +0200 Subject: [PATCH 12/44] Add unit test for PHAssetResult --- .../image_picker/ios/Tests/PhotoAssetUtilTests.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m index 2a1ba75b0608..2762ea2637dc 100644 --- a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m @@ -17,6 +17,13 @@ - (void)getAssetFromImagePickerInfoShouldReturnNilIfNotAvailable { XCTAssertNil([FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:mockData]); } +- (void)getAssetFromPHPickerResultShouldReturnNilIfNotAvailable { + if (@available(iOS 14, *)) { + PHPickerResult *mockData = nil; + XCTAssertNil([FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:mockData]); + } +} + - (void)testSaveImageWithOriginalImageData_ShouldSaveWithTheCorrectExtentionAndMetaData { // test jpg NSData *dataJPG = ImagePickerTestImages.JPGTestData; From 7f81b7b541bc4fee64015c2e97edfedc7e2f0a43 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Thu, 29 Apr 2021 14:00:37 +0200 Subject: [PATCH 13/44] Format the codes in all files --- .../ImagePickerFromGalleryUITests.m | 2 +- .../ImagePickerFromLimitedGalleryUITests.m | 94 +++--- .../Classes/FLTImagePickerPhotoAssetUtil.h | 1 - .../Classes/FLTImagePickerPhotoAssetUtil.m | 11 +- .../ios/Classes/FLTImagePickerPlugin.m | 271 +++++++++--------- .../ios/Tests/PhotoAssetUtilTests.m | 8 +- 6 files changed, 195 insertions(+), 192 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m index 375a42d515c1..4b2163d00577 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromGalleryUITests.m @@ -165,7 +165,7 @@ - (void)launchPickerAndPick { // Find an image and tap on it. (IOS 14 UI, images are showing directly) XCUIElement* aImage; if (@available(iOS 14, *)) { - aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1]; + aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1]; } else { XCUIElement* allPhotosCell = [self.app.cells elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label == %@", @"All Photos"]]; diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m index cb35d037638f..2b0d0c5c63a4 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m @@ -31,9 +31,10 @@ - (void)setUp { handler:^BOOL(XCUIElement* _Nonnull interruptingElement) { if (@available(iOS 14, *)) { XCUIElement* limitedPhotoPermission = - [interruptingElement.buttons elementBoundByIndex:0]; - if (![limitedPhotoPermission waitForExistenceWithTimeout: - kLimitedElementWaitingTime]) { + [interruptingElement.buttons elementBoundByIndex:0]; + if (![limitedPhotoPermission + waitForExistenceWithTimeout: + kLimitedElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", weakSelf.app.debugDescription); XCTFail(@"Failed due to not able to find " @@ -66,7 +67,6 @@ - (void)testSelectingFromGallery { [self launchPickerAndSelect]; } - - (void)launchPickerAndSelect { // Find and tap on the pick from gallery button. NSPredicate* predicateToFindImageFromGalleryButton = @@ -90,7 +90,8 @@ - (void)launchPickerAndSelect { XCUIElement* pickButton = [self.app.buttons elementMatchingPredicate:predicateToFindPickButton]; if (![pickButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); - XCTFail(@"Failed due to not able to find pick button with %@ seconds", @(kLimitedElementWaitingTime)); + XCTFail(@"Failed due to not able to find pick button with %@ seconds", + @(kLimitedElementWaitingTime)); } XCTAssertTrue(pickButton.exists); @@ -106,7 +107,8 @@ - (void)launchPickerAndSelect { aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1]; } else { XCUIElement* selectedPhotosCell = [self.app.cells - elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label == %@", @"Selected Photos"]]; + elementMatchingPredicate:[NSPredicate + predicateWithFormat:@"label == %@", @"Selected Photos"]]; if (![selectedPhotosCell waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); XCTFail(@"Failed due to not able to find \"Selected Photos\" cell with %@ seconds", @@ -120,49 +122,51 @@ - (void)launchPickerAndSelect { os_log_error(OS_LOG_DEFAULT, "description before picking image %@", self.app.debugDescription); if (![aImage waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); - XCTFail(@"Failed due to not able to find an image with %@ seconds", @(kLimitedElementWaitingTime)); + XCTFail(@"Failed due to not able to find an image with %@ seconds", + @(kLimitedElementWaitingTime)); } XCTAssertTrue(aImage.exists); [aImage tap]; - - // Find and tap on the `Done` button. - NSPredicate* predicateToFindDoneButton = - [NSPredicate predicateWithFormat:@"label == %@", @"Done"]; - - XCUIElement* doneButton = - [self.app.buttons elementMatchingPredicate:predicateToFindDoneButton]; - if (![doneButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); - XCTFail(@"Failed due to not able to find Cancel button with %@ seconds", - @(kLimitedElementWaitingTime)); - } - XCTAssertTrue(doneButton.exists); - [doneButton tap]; - - // Find an image and tap on it to have access to selected photos. - if (@available(iOS 14, *)) { - aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1]; - } else { - XCUIElement* selectedPhotosCell = [self.app.cells - elementMatchingPredicate:[NSPredicate predicateWithFormat:@"label == %@", @"Selected Photos"]]; - if (![selectedPhotosCell waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { - os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); - XCTFail(@"Failed due to not able to find \"Selected Photos\" cell with %@ seconds", - @(kLimitedElementWaitingTime)); - } - [selectedPhotosCell tap]; - aImage = [self.app.collectionViews elementMatchingType:XCUIElementTypeCollectionView - identifier:@"PhotosGridView"] - .cells.firstMatch; - } - os_log_error(OS_LOG_DEFAULT, "description before picking image %@", self.app.debugDescription); - if (![aImage waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + // Find and tap on the `Done` button. + NSPredicate* predicateToFindDoneButton = + [NSPredicate predicateWithFormat:@"label == %@", @"Done"]; + + XCUIElement* doneButton = [self.app.buttons elementMatchingPredicate:predicateToFindDoneButton]; + if (![doneButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find Cancel button with %@ seconds", + @(kLimitedElementWaitingTime)); + } + + XCTAssertTrue(doneButton.exists); + [doneButton tap]; + + // Find an image and tap on it to have access to selected photos. + if (@available(iOS 14, *)) { + aImage = [self.app.scrollViews.firstMatch.images elementBoundByIndex:1]; + } else { + XCUIElement* selectedPhotosCell = [self.app.cells + elementMatchingPredicate:[NSPredicate + predicateWithFormat:@"label == %@", @"Selected Photos"]]; + if (![selectedPhotosCell waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); - XCTFail(@"Failed due to not able to find an image with %@ seconds", @(kLimitedElementWaitingTime)); + XCTFail(@"Failed due to not able to find \"Selected Photos\" cell with %@ seconds", + @(kLimitedElementWaitingTime)); } - XCTAssertTrue(aImage.exists); - [aImage tap]; + [selectedPhotosCell tap]; + aImage = [self.app.collectionViews elementMatchingType:XCUIElementTypeCollectionView + identifier:@"PhotosGridView"] + .cells.firstMatch; + } + os_log_error(OS_LOG_DEFAULT, "description before picking image %@", self.app.debugDescription); + if (![aImage waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); + XCTFail(@"Failed due to not able to find an image with %@ seconds", + @(kLimitedElementWaitingTime)); + } + XCTAssertTrue(aImage.exists); + [aImage tap]; // Find the picked image. NSPredicate* predicateToFindPickedImage = @@ -171,11 +175,11 @@ - (void)launchPickerAndSelect { XCUIElement* pickedImage = [self.app.images elementMatchingPredicate:predicateToFindPickedImage]; if (![pickedImage waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); - XCTFail(@"Failed due to not able to find pickedImage with %@ seconds", @(kLimitedElementWaitingTime)); + XCTFail(@"Failed due to not able to find pickedImage with %@ seconds", + @(kLimitedElementWaitingTime)); } XCTAssertTrue(pickedImage.exists); } - @end diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h index f373abc5dc41..3c7766e8504e 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h @@ -6,7 +6,6 @@ #import #import - #import "FLTImagePickerImageUtil.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m index 604ae3474a9e..3edf24556791 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m @@ -24,11 +24,12 @@ + (PHAsset *)getAssetFromImagePickerInfo:(NSDictionary *)info { } + (PHAsset *)getAssetFromPHPickerResult:(PHPickerResult *)result { - if (@available(iOS 14, *)) { - PHFetchResult* fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[result.assetIdentifier] options:nil]; - return fetchResult.firstObject; - } - return nil; + if (@available(iOS 14, *)) { + PHFetchResult *fetchResult = + [PHAsset fetchAssetsWithLocalIdentifiers:@[ result.assetIdentifier ] options:nil]; + return fetchResult.firstObject; + } + return nil; } + (NSString *)saveImageWithOriginalImageData:(NSData *)originalImageData diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index e87dfb49c8c9..73e0a75d066d 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -7,16 +7,17 @@ #import #import #import -#import #import -#import #import +#import #import "FLTImagePickerImageUtil.h" #import "FLTImagePickerMetaDataUtil.h" #import "FLTImagePickerPhotoAssetUtil.h" -@interface FLTImagePickerPlugin () +@interface FLTImagePickerPlugin () @property(copy, nonatomic) FlutterResult result; @@ -68,50 +69,47 @@ - (UIViewController *)viewControllerWithWindow:(UIWindow *)window { } - (void)pickImageWithPHPicker:(bool)single { - PHPhotoLibrary *photoLibrary = PHPhotoLibrary.sharedPhotoLibrary; // This step is required to fetch PHAsset - PHPickerConfiguration *config = [[PHPickerConfiguration alloc] initWithPhotoLibrary:photoLibrary]; - if (!single) { - config.selectionLimit = 0; // Setting to zero allow us to pick unlimited photos - } - config.filter = [PHPickerFilter imagesFilter]; + PHPhotoLibrary *photoLibrary = + PHPhotoLibrary.sharedPhotoLibrary; // This step is required to fetch PHAsset + PHPickerConfiguration *config = [[PHPickerConfiguration alloc] initWithPhotoLibrary:photoLibrary]; + if (!single) { + config.selectionLimit = 0; // Setting to zero allow us to pick unlimited photos + } + config.filter = [PHPickerFilter imagesFilter]; - _pickerViewController = - [[PHPickerViewController alloc] initWithConfiguration:config]; - _pickerViewController.delegate = self; - - [self checkPhotoAuthorization]; + _pickerViewController = [[PHPickerViewController alloc] initWithConfiguration:config]; + _pickerViewController.delegate = self; + + [self checkPhotoAuthorization]; } - (void)pickImageWithUIImagePicker { - - _imagePickerController = [[UIImagePickerController alloc] init]; - _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; - _imagePickerController.delegate = self; - _imagePickerController.mediaTypes = @[ (NSString *)kUTTypeImage ]; - - int imageSource = [[_arguments objectForKey:@"source"] intValue]; - - switch (imageSource) { - case SOURCE_CAMERA: { - NSInteger cameraDevice = [[_arguments objectForKey:@"cameraDevice"] intValue]; - _device = (cameraDevice == 1) ? UIImagePickerControllerCameraDeviceFront - : UIImagePickerControllerCameraDeviceRear; - [self checkCameraAuthorization]; - break; - } - case SOURCE_GALLERY: - [self checkPhotoAuthorization]; - break; - default: - self.result([FlutterError errorWithCode:@"invalid_source" - message:@"Invalid image source." - details:nil]); - break; + _imagePickerController = [[UIImagePickerController alloc] init]; + _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; + _imagePickerController.delegate = self; + _imagePickerController.mediaTypes = @[ (NSString *)kUTTypeImage ]; + + int imageSource = [[_arguments objectForKey:@"source"] intValue]; + + switch (imageSource) { + case SOURCE_CAMERA: { + NSInteger cameraDevice = [[_arguments objectForKey:@"cameraDevice"] intValue]; + _device = (cameraDevice == 1) ? UIImagePickerControllerCameraDeviceFront + : UIImagePickerControllerCameraDeviceRear; + [self checkCameraAuthorization]; + break; } + case SOURCE_GALLERY: + [self checkPhotoAuthorization]; + break; + default: + self.result([FlutterError errorWithCode:@"invalid_source" + message:@"Invalid image source." + details:nil]); + break; + } } - - - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { if (self.result) { self.result([FlutterError errorWithCode:@"multiple_request" @@ -121,32 +119,31 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result } if ([@"pickImage" isEqualToString:call.method]) { - - _phPickerFlag = NO; - self.result = result; - _arguments = call.arguments; - int imageSource = [[_arguments objectForKey:@"source"] intValue]; - - if (imageSource == SOURCE_GALLERY) { // Capture is not possible with PHPicker - if (@available(iOS 14, *)) { - //PHPicker is used - _phPickerFlag = YES; - [self pickImageWithPHPicker:true]; - } else { - //UIImagePicker is used - [self pickImageWithUIImagePicker]; - } + _phPickerFlag = NO; + self.result = result; + _arguments = call.arguments; + int imageSource = [[_arguments objectForKey:@"source"] intValue]; + + if (imageSource == SOURCE_GALLERY) { // Capture is not possible with PHPicker + if (@available(iOS 14, *)) { + // PHPicker is used + _phPickerFlag = YES; + [self pickImageWithPHPicker:true]; } else { - [self pickImageWithUIImagePicker]; + // UIImagePicker is used + [self pickImageWithUIImagePicker]; } + } else { + [self pickImageWithUIImagePicker]; + } } else if ([@"pickMultiImage" isEqualToString:call.method]) { - if (@available(iOS 14, *)) { - NSLog(@"pickImage has been called on iOS14+"); - self.result = result; - _arguments = call.arguments; - NSLog(@"Result and arguments have been set"); - [self pickImageWithPHPicker:false]; - } + if (@available(iOS 14, *)) { + NSLog(@"pickImage has been called on iOS14+"); + self.result = result; + _arguments = call.arguments; + NSLog(@"Result and arguments have been set"); + [self pickImageWithPHPicker:false]; + } } else if ([@"pickVideo" isEqualToString:call.method]) { _imagePickerController = [[UIImagePickerController alloc] init]; _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; @@ -251,15 +248,16 @@ - (void)checkPhotoAuthorization { [self showPhotoLibrary]; }); } else if (@available(iOS 14, *)) { - if (status == PHAuthorizationStatusLimited) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self showLimitedPhotoLibrary]; // Implemented limited access to the photo library by above instructions - }); - } else { - [self errorNoPhotoAccess:status]; - } - } else { + if (status == PHAuthorizationStatusLimited) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self showLimitedPhotoLibrary]; // Implemented limited access to the photo library by + // above instructions + }); + } else { [self errorNoPhotoAccess:status]; + } + } else { + [self errorNoPhotoAccess:status]; } }]; break; @@ -309,80 +307,81 @@ - (void)errorNoPhotoAccess:(PHAuthorizationStatus)status { - (void)showPhotoLibrary { // No need to check if SourceType is available. It always is. - if(_phPickerFlag) { - [[self viewControllerWithWindow:nil] presentViewController:_pickerViewController - animated:YES - completion:nil]; - } else { - _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; - [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController - animated:YES - completion:nil]; - } + if (_phPickerFlag) { + [[self viewControllerWithWindow:nil] presentViewController:_pickerViewController + animated:YES + completion:nil]; + } else { + _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController + animated:YES + completion:nil]; + } } // Limited access to the photo library - (void)showLimitedPhotoLibrary { - [[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:_pickerViewController]; + [[PHPhotoLibrary sharedPhotoLibrary] + presentLimitedLibraryPickerFromViewController:_pickerViewController]; } - - (void)picker:(PHPickerViewController *)picker - didFinishPicking:(NSArray *)results API_AVAILABLE(ios(14)) { - [picker dismissViewControllerAnimated:YES completion:nil]; - - for (PHPickerResult *result in results) { - [result.itemProvider - loadObjectOfClass:[UIImage class] - completionHandler:^(__kindof id _Nullable image, - NSError *_Nullable error) { - if ([image isKindOfClass:[UIImage class]]) { - if (image != nil) { - - NSNumber *maxWidth = [self->_arguments objectForKey:@"maxWidth"]; - NSNumber *maxHeight = [self->_arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; - - if (![imageQuality isKindOfClass:[NSNumber class]]) { - imageQuality = @1; - } else if (imageQuality.intValue < 0 || imageQuality.intValue > 100) { - imageQuality = [NSNumber numberWithInt:1]; - } else { - imageQuality = @([imageQuality floatValue] / 100); - } - - if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) { - image = [FLTImagePickerImageUtil scaledImage:image maxWidth:maxWidth maxHeight:maxHeight]; - } - - PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:result]; - - if (!originalAsset) { - // Image picked without an original asset (e.g. User took a photo directly) - [self saveImageWithPickerInfo:nil image:image imageQuality:imageQuality]; - } - else { - __weak typeof(self) weakSelf = self; - [[PHImageManager defaultManager] - requestImageDataForAsset:originalAsset - options:nil - resultHandler:^(NSData *_Nullable imageData, NSString *_Nullable dataUTI, - UIImageOrientation orientation, NSDictionary *_Nullable info) { - // maxWidth and maxHeight are used only for GIF images. - [weakSelf saveImageWithOriginalImageData:imageData - image:image - maxWidth:maxWidth - maxHeight:maxHeight - imageQuality:imageQuality]; - }]; - } - } - } - }]; - } + didFinishPicking:(NSArray *)results API_AVAILABLE(ios(14)) { + [picker dismissViewControllerAnimated:YES completion:nil]; + + for (PHPickerResult *result in results) { + [result.itemProvider + loadObjectOfClass:[UIImage class] + completionHandler:^(__kindof id _Nullable image, + NSError *_Nullable error) { + if ([image isKindOfClass:[UIImage class]]) { + if (image != nil) { + NSNumber *maxWidth = [self->_arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [self->_arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; + + if (![imageQuality isKindOfClass:[NSNumber class]]) { + imageQuality = @1; + } else if (imageQuality.intValue < 0 || imageQuality.intValue > 100) { + imageQuality = [NSNumber numberWithInt:1]; + } else { + imageQuality = @([imageQuality floatValue] / 100); + } + + if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) { + image = [FLTImagePickerImageUtil scaledImage:image + maxWidth:maxWidth + maxHeight:maxHeight]; + } + + PHAsset *originalAsset = + [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:result]; + + if (!originalAsset) { + // Image picked without an original asset (e.g. User took a photo directly) + [self saveImageWithPickerInfo:nil image:image imageQuality:imageQuality]; + } else { + __weak typeof(self) weakSelf = self; + [[PHImageManager defaultManager] + requestImageDataForAsset:originalAsset + options:nil + resultHandler:^( + NSData *_Nullable imageData, NSString *_Nullable dataUTI, + UIImageOrientation orientation, NSDictionary *_Nullable info) { + // maxWidth and maxHeight are used only for GIF images. + [weakSelf saveImageWithOriginalImageData:imageData + image:image + maxWidth:maxWidth + maxHeight:maxHeight + imageQuality:imageQuality]; + }]; + } + } + } + }]; + } } - - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL]; diff --git a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m index 2762ea2637dc..c982235c809e 100644 --- a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m @@ -18,10 +18,10 @@ - (void)getAssetFromImagePickerInfoShouldReturnNilIfNotAvailable { } - (void)getAssetFromPHPickerResultShouldReturnNilIfNotAvailable { - if (@available(iOS 14, *)) { - PHPickerResult *mockData = nil; - XCTAssertNil([FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:mockData]); - } + if (@available(iOS 14, *)) { + PHPickerResult *mockData = nil; + XCTAssertNil([FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:mockData]); + } } - (void)testSaveImageWithOriginalImageData_ShouldSaveWithTheCorrectExtentionAndMetaData { From 62bfcfdd5eff94a018e23376d9c7c31666f7c323 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Thu, 29 Apr 2021 14:44:30 +0200 Subject: [PATCH 14/44] Fix the unit test --- .../image_picker/ios/Tests/PhotoAssetUtilTests.m | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m index c982235c809e..72368fc1a3ef 100644 --- a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m @@ -12,15 +12,20 @@ @interface PhotoAssetUtilTests : XCTestCase @implementation PhotoAssetUtilTests -- (void)getAssetFromImagePickerInfoShouldReturnNilIfNotAvailable { +- (void)testGetAssetFromImagePickerInfoShouldReturnNilIfNotAvailable { NSDictionary *mockData = @{}; XCTAssertNil([FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:mockData]); } -- (void)getAssetFromPHPickerResultShouldReturnNilIfNotAvailable { +- (void)testGetAssetFromPHPickerResultShouldReturnNilIfNotAvailable { if (@available(iOS 14, *)) { - PHPickerResult *mockData = nil; - XCTAssertNil([FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:mockData]); + PHPickerResult *mockData; + [mockData.itemProvider + loadObjectOfClass:[UIImage class] + completionHandler:^(__kindof id _Nullable image, + NSError *_Nullable error) { + XCTAssertNil([FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:mockData]); + }]; } } From 97311f9fd4848a16b7f3a3a05efff72e961b90cd Mon Sep 17 00:00:00 2001 From: yusufdag Date: Thu, 29 Apr 2021 17:07:24 +0200 Subject: [PATCH 15/44] Update the version --- packages/image_picker/image_picker/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 73c6a6ed1824..500e270f49f6 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker -version: 0.7.4 +version: 0.7.5 flutter: plugin: From cc7c5b1e79b59e44a4e31625f5c1609cd9454f6b Mon Sep 17 00:00:00 2001 From: yusufdag Date: Thu, 29 Apr 2021 17:07:58 +0200 Subject: [PATCH 16/44] Add the description into CHANGELOG file --- packages/image_picker/image_picker/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 6af3cb090ca6..58002a8630b4 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.7.5 + +* Fixes an issue where image rotation is wrong when Select Photos chose and image is scaled. +* Breaking Changes: + * Migrate to PHPicker for iOS 14 and higher versions to pick image from the photo library. + * Implement the limited permission to pick photo from the photo library when Select Photo is chose. + ## 0.7.4 * Update flutter_plugin_android_lifecycle dependency to 2.0.1 to fix an R8 issue From 04a8452bdea5cc3a650668eb701816c2484cd33c Mon Sep 17 00:00:00 2001 From: yusufdag Date: Fri, 30 Apr 2021 13:19:15 +0200 Subject: [PATCH 17/44] Fix the license header --- .../ImagePickerFromLimitedGalleryUITests.m | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m index 2b0d0c5c63a4..c7e5cc680972 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m @@ -1,10 +1,6 @@ -// -// ImagePickerFromLimitedGalleryUITests.m -// RunnerUITests -// -// Created by Yusuf Dag on 28/04/2021. -// Copyright © 2021 The Flutter Authors. All rights reserved. -// +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #import #import From b930c9796237bc126a8c734adf9c0b23f693d205 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Fri, 30 Apr 2021 14:22:38 +0200 Subject: [PATCH 18/44] Remove the unnecessary if statement --- .../ios/Classes/FLTImagePickerPhotoAssetUtil.h | 2 +- .../ios/Classes/FLTImagePickerPhotoAssetUtil.m | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h index 3c7766e8504e..0016765a0fe0 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.h @@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN + (nullable PHAsset *)getAssetFromImagePickerInfo:(NSDictionary *)info; -+ (nullable PHAsset *)getAssetFromPHPickerResult:(PHPickerResult *)result; ++ (nullable PHAsset *)getAssetFromPHPickerResult:(PHPickerResult *)result API_AVAILABLE(ios(14)); // Save image with correct meta data and extention copied from the original asset. // maxWidth and maxHeight are used only for GIF images. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m index 3edf24556791..51fc37598491 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPhotoAssetUtil.m @@ -23,13 +23,10 @@ + (PHAsset *)getAssetFromImagePickerInfo:(NSDictionary *)info { return result.firstObject; } -+ (PHAsset *)getAssetFromPHPickerResult:(PHPickerResult *)result { - if (@available(iOS 14, *)) { - PHFetchResult *fetchResult = - [PHAsset fetchAssetsWithLocalIdentifiers:@[ result.assetIdentifier ] options:nil]; - return fetchResult.firstObject; - } - return nil; ++ (PHAsset *)getAssetFromPHPickerResult:(PHPickerResult *)result API_AVAILABLE(ios(14)) { + PHFetchResult *fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[ result.assetIdentifier ] + options:nil]; + return fetchResult.firstObject; } + (NSString *)saveImageWithOriginalImageData:(NSData *)originalImageData From 9d4c04d5a2ba58a4ef604344a46880c318a8dfe7 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Fri, 30 Apr 2021 14:44:16 +0200 Subject: [PATCH 19/44] Refactor PHPickerViewController to use property --- .../ios/Classes/FLTImagePickerPlugin.h | 2 -- .../ios/Classes/FLTImagePickerPlugin.m | 17 +++++++---------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h index b8e46df21f21..ffd23cd3df6a 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h @@ -5,12 +5,10 @@ #import #import -API_AVAILABLE(ios(14)) @interface FLTImagePickerPlugin : NSObject // For testing only. - (UIImagePickerController *)getImagePickerController; - (UIViewController *)viewControllerWithWindow:(UIWindow *)window; -- (PHPickerViewController *)getPickerViewController; @end diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 73e0a75d066d..8bca52dcfc21 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -21,6 +21,8 @@ @interface FLTImagePickerPlugin () Date: Fri, 30 Apr 2021 14:46:57 +0200 Subject: [PATCH 20/44] Refactor phPickerFlag state to use property --- .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 8bca52dcfc21..ee1e8d760f95 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -23,6 +23,8 @@ @interface FLTImagePickerPlugin () *)registrar { @@ -116,7 +117,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result } if ([@"pickImage" isEqualToString:call.method]) { - _phPickerFlag = NO; + __phPickerFlag = NO; self.result = result; _arguments = call.arguments; int imageSource = [[_arguments objectForKey:@"source"] intValue]; @@ -124,7 +125,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result if (imageSource == SOURCE_GALLERY) { // Capture is not possible with PHPicker if (@available(iOS 14, *)) { // PHPicker is used - _phPickerFlag = YES; + __phPickerFlag = YES; [self pickImageWithPHPicker:true]; } else { // UIImagePicker is used @@ -304,7 +305,7 @@ - (void)errorNoPhotoAccess:(PHAuthorizationStatus)status { - (void)showPhotoLibrary { // No need to check if SourceType is available. It always is. - if (_phPickerFlag) { + if (__phPickerFlag) { [[self viewControllerWithWindow:nil] presentViewController:__pickerViewController animated:YES completion:nil]; From 852a8282185d387957d8ac09e7086ec8edb133aa Mon Sep 17 00:00:00 2001 From: yusufdag Date: Fri, 30 Apr 2021 14:48:44 +0200 Subject: [PATCH 21/44] Refactor the code to combine lines --- .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index ee1e8d760f95..525ecf4c9879 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -67,9 +67,8 @@ - (UIViewController *)viewControllerWithWindow:(UIWindow *)window { } - (void)pickImageWithPHPicker:(bool)single API_AVAILABLE(ios(14)) { - PHPhotoLibrary *photoLibrary = - PHPhotoLibrary.sharedPhotoLibrary; // This step is required to fetch PHAsset - PHPickerConfiguration *config = [[PHPickerConfiguration alloc] initWithPhotoLibrary:photoLibrary]; + PHPickerConfiguration *config = + [[PHPickerConfiguration alloc] initWithPhotoLibrary:PHPhotoLibrary.sharedPhotoLibrary]; if (!single) { config.selectionLimit = 0; // Setting to zero allow us to pick unlimited photos } From 13e5e9d42f0c8df2fc7d4d201dfccd3ab0017bf4 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Fri, 30 Apr 2021 15:08:43 +0200 Subject: [PATCH 22/44] Refactor arguments to use property --- .../ios/Classes/FLTImagePickerPlugin.m | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 525ecf4c9879..a8e4661d1f94 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -21,6 +21,8 @@ @interface FLTImagePickerPlugin () _arguments objectForKey:@"maxWidth"]; - NSNumber *maxHeight = [self->_arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; + NSNumber *maxWidth = [self->__arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [self->__arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [self->__arguments objectForKey:@"imageQuality"]; if (![imageQuality isKindOfClass:[NSNumber class]]) { imageQuality = @1; @@ -414,16 +415,16 @@ - (void)imagePickerController:(UIImagePickerController *)picker } self.result(videoURL.path); self.result = nil; - _arguments = nil; + __arguments = nil; } else { UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage]; if (image == nil) { image = [info objectForKey:UIImagePickerControllerOriginalImage]; } - NSNumber *maxWidth = [_arguments objectForKey:@"maxWidth"]; - NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [_arguments objectForKey:@"imageQuality"]; + NSNumber *maxWidth = [__arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [__arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [__arguments objectForKey:@"imageQuality"]; if (![imageQuality isKindOfClass:[NSNumber class]]) { imageQuality = @1; @@ -466,7 +467,7 @@ - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { } self.result(nil); self.result = nil; - _arguments = nil; + __arguments = nil; } - (void)saveImageWithOriginalImageData:(NSData *)originalImageData @@ -504,7 +505,7 @@ - (void)handleSavedPath:(NSString *)path { details:nil]); } self.result = nil; - _arguments = nil; + __arguments = nil; } @end From aa8a878c4887bf722c3b01e13266c5e0eb817a1f Mon Sep 17 00:00:00 2001 From: yusufdag Date: Fri, 30 Apr 2021 15:24:53 +0200 Subject: [PATCH 23/44] Revert formatting changes This reverts part of commit 36b6a2aec20be6c76748f27a07d9f670d33a1313. --- .../lib/model/android_device_info.dart | 2 +- .../google_maps_flutter_web/lib/src/circles.dart | 2 +- .../google_maps_flutter_web/lib/src/markers.dart | 2 +- .../google_maps_flutter_web/lib/src/polygons.dart | 2 +- .../google_maps_flutter_web/lib/src/polylines.dart | 2 +- packages/webview_flutter/lib/webview_flutter.dart | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart index 961d373e2dea..b61dc14a0420 100644 --- a/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart +++ b/packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart @@ -29,7 +29,7 @@ class AndroidDeviceInfo { required this.isPhysicalDevice, required this.androidId, required List systemFeatures, - }) : supported32BitAbis = List.unmodifiable(supported32BitAbis), + }) : supported32BitAbis = List.unmodifiable(supported32BitAbis), supported64BitAbis = List.unmodifiable(supported64BitAbis), supportedAbis = List.unmodifiable(supportedAbis), systemFeatures = List.unmodifiable(systemFeatures); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart index 2a19d87adfec..ae8faa038ea6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart @@ -15,7 +15,7 @@ class CirclesController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. CirclesController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _circleIdToController = Map(); /// Returns the cache of [CircleController]s. Test only. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart index 704577b6e3fb..b650b9bcf1c8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart @@ -15,7 +15,7 @@ class MarkersController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. MarkersController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _markerIdToController = Map(); /// Returns the cache of [MarkerController]s. Test only. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart index ef51bd6043df..8a9643156351 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart @@ -15,7 +15,7 @@ class PolygonsController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolygonsController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _polygonIdToController = Map(); /// Returns the cache of [PolygonController]s. Test only. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart index 184c0d954744..695b29554c04 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart @@ -15,7 +15,7 @@ class PolylinesController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolylinesController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _polylineIdToController = Map(); /// Returns the cache of [PolylineContrller]s. Test only. diff --git a/packages/webview_flutter/lib/webview_flutter.dart b/packages/webview_flutter/lib/webview_flutter.dart index 92ff8e00a50e..74d8af8d4687 100644 --- a/packages/webview_flutter/lib/webview_flutter.dart +++ b/packages/webview_flutter/lib/webview_flutter.dart @@ -180,7 +180,7 @@ class JavascriptChannel { JavascriptChannel({ required this.name, required this.onMessageReceived, - }) : assert(name != null), + }) : assert(name != null), assert(onMessageReceived != null), assert(_validChannelNames.hasMatch(name)); From f14c61670627b217a281cbbd3767a3a191c12a7c Mon Sep 17 00:00:00 2001 From: yusufdag Date: Fri, 30 Apr 2021 15:47:23 +0200 Subject: [PATCH 24/44] Fix the unit test --- .../image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m index 72368fc1a3ef..c2a0380cdf45 100644 --- a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m @@ -12,12 +12,12 @@ @interface PhotoAssetUtilTests : XCTestCase @implementation PhotoAssetUtilTests -- (void)testGetAssetFromImagePickerInfoShouldReturnNilIfNotAvailable { +- (void)getAssetFromImagePickerInfoShouldReturnNilIfNotAvailable { NSDictionary *mockData = @{}; XCTAssertNil([FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:mockData]); } -- (void)testGetAssetFromPHPickerResultShouldReturnNilIfNotAvailable { +- (void)testGetAssetFromPHPickerResultShouldReturnNilIfNotAvailable API_AVAILABLE(ios(14)){ if (@available(iOS 14, *)) { PHPickerResult *mockData; [mockData.itemProvider From 7710140c1ee68227612597da487ca15be8b30835 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Fri, 30 Apr 2021 16:11:15 +0200 Subject: [PATCH 25/44] Format the code --- .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 3 +-- .../image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index a8e4661d1f94..ab0bae7e10c1 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -248,8 +248,7 @@ - (void)checkPhotoAuthorization { } else if (@available(iOS 14, *)) { if (status == PHAuthorizationStatusLimited) { dispatch_async(dispatch_get_main_queue(), ^{ - [self showLimitedPhotoLibrary]; // Implemented limited access to the photo library by - // above instructions + [self showLimitedPhotoLibrary]; }); } else { [self errorNoPhotoAccess:status]; diff --git a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m index c2a0380cdf45..b81b29f73cef 100644 --- a/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m +++ b/packages/image_picker/image_picker/ios/Tests/PhotoAssetUtilTests.m @@ -17,7 +17,7 @@ - (void)getAssetFromImagePickerInfoShouldReturnNilIfNotAvailable { XCTAssertNil([FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:mockData]); } -- (void)testGetAssetFromPHPickerResultShouldReturnNilIfNotAvailable API_AVAILABLE(ios(14)){ +- (void)testGetAssetFromPHPickerResultShouldReturnNilIfNotAvailable API_AVAILABLE(ios(14)) { if (@available(iOS 14, *)) { PHPickerResult *mockData; [mockData.itemProvider From 29e5dfd2d900d86aafdb1ee26549622346ebaebf Mon Sep 17 00:00:00 2001 From: yusufdag Date: Mon, 3 May 2021 09:58:05 +0200 Subject: [PATCH 26/44] Refactor the UITest to skip lower versions --- .../ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m index c7e5cc680972..f53ed1bece48 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m @@ -21,6 +21,9 @@ - (void)setUp { self.continueAfterFailure = NO; self.app = [[XCUIApplication alloc] init]; + if (!(@available(iOS 14, *))) { + XCTSkip(@"Required iOS version is not available for this test."); + } [self.app launch]; __weak typeof(self) weakSelf = self; [self addUIInterruptionMonitorWithDescription:@"Permission popups" From a83440f863209057e73167a8f4322a54e15d0a18 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Mon, 3 May 2021 10:05:32 +0200 Subject: [PATCH 27/44] Fix the property's name --- .../ios/Classes/FLTImagePickerPlugin.m | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index ab0bae7e10c1..9282b869d83c 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -21,7 +21,7 @@ @interface FLTImagePickerPlugin () __arguments objectForKey:@"maxWidth"]; - NSNumber *maxHeight = [self->__arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [self->__arguments objectForKey:@"imageQuality"]; + NSNumber *maxWidth = [self->_arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [self->_arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; if (![imageQuality isKindOfClass:[NSNumber class]]) { imageQuality = @1; @@ -414,16 +414,16 @@ - (void)imagePickerController:(UIImagePickerController *)picker } self.result(videoURL.path); self.result = nil; - __arguments = nil; + _arguments = nil; } else { UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage]; if (image == nil) { image = [info objectForKey:UIImagePickerControllerOriginalImage]; } - NSNumber *maxWidth = [__arguments objectForKey:@"maxWidth"]; - NSNumber *maxHeight = [__arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [__arguments objectForKey:@"imageQuality"]; + NSNumber *maxWidth = [_arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [_arguments objectForKey:@"imageQuality"]; if (![imageQuality isKindOfClass:[NSNumber class]]) { imageQuality = @1; @@ -466,7 +466,7 @@ - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { } self.result(nil); self.result = nil; - __arguments = nil; + _arguments = nil; } - (void)saveImageWithOriginalImageData:(NSData *)originalImageData @@ -504,7 +504,7 @@ - (void)handleSavedPath:(NSString *)path { details:nil]); } self.result = nil; - __arguments = nil; + _arguments = nil; } @end From 97f24f893ac227706f424092d5b3e69a25959a37 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Mon, 3 May 2021 10:44:11 +0200 Subject: [PATCH 28/44] Refactor the properties to pass them via methods --- .../ios/Classes/FLTImagePickerPlugin.m | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 9282b869d83c..58e9f2fc37eb 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -23,10 +23,6 @@ @interface FLTImagePickerPlugin () Date: Mon, 3 May 2021 12:44:39 +0200 Subject: [PATCH 29/44] Add the getDesiredImageQuality method --- .../ios/Classes/FLTImagePickerPlugin.m | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 58e9f2fc37eb..1753340402ea 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -319,28 +319,34 @@ - (void)showLimitedPhotoLibrary:(PHPickerViewController *)pickerViewController { presentLimitedLibraryPickerFromViewController:pickerViewController]; } +- (NSNumber *)getDesiredImageQuality { + NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; + if (![imageQuality isKindOfClass:[NSNumber class]]) { + imageQuality = @1; + } else if (imageQuality.intValue < 0 || imageQuality.intValue > 100) { + imageQuality = [NSNumber numberWithInt:1]; + } else { + imageQuality = @([imageQuality floatValue] / 100); + } + return imageQuality; +} + - (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray *)results API_AVAILABLE(ios(14)) { [picker dismissViewControllerAnimated:YES completion:nil]; for (PHPickerResult *result in results) { + __weak typeof(self) weakSelf = self; + [result.itemProvider loadObjectOfClass:[UIImage class] completionHandler:^(__kindof id _Nullable image, NSError *_Nullable error) { if ([image isKindOfClass:[UIImage class]]) { if (image != nil) { - NSNumber *maxWidth = [self->_arguments objectForKey:@"maxWidth"]; - NSNumber *maxHeight = [self->_arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; - - if (![imageQuality isKindOfClass:[NSNumber class]]) { - imageQuality = @1; - } else if (imageQuality.intValue < 0 || imageQuality.intValue > 100) { - imageQuality = [NSNumber numberWithInt:1]; - } else { - imageQuality = @([imageQuality floatValue] / 100); - } + NSNumber *maxWidth = [weakSelf.arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [weakSelf.arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [weakSelf getDesiredImageQuality]; if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) { image = [FLTImagePickerImageUtil scaledImage:image @@ -353,9 +359,8 @@ - (void)picker:(PHPickerViewController *)picker if (!originalAsset) { // Image picked without an original asset (e.g. User took a photo directly) - [self saveImageWithPickerInfo:nil image:image imageQuality:imageQuality]; + [weakSelf saveImageWithPickerInfo:nil image:image imageQuality:imageQuality]; } else { - __weak typeof(self) weakSelf = self; [[PHImageManager defaultManager] requestImageDataForAsset:originalAsset options:nil @@ -417,18 +422,11 @@ - (void)imagePickerController:(UIImagePickerController *)picker if (image == nil) { image = [info objectForKey:UIImagePickerControllerOriginalImage]; } + __weak typeof(self) weakSelf = self; NSNumber *maxWidth = [_arguments objectForKey:@"maxWidth"]; NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [_arguments objectForKey:@"imageQuality"]; - - if (![imageQuality isKindOfClass:[NSNumber class]]) { - imageQuality = @1; - } else if (imageQuality.intValue < 0 || imageQuality.intValue > 100) { - imageQuality = [NSNumber numberWithInt:1]; - } else { - imageQuality = @([imageQuality floatValue] / 100); - } + NSNumber *imageQuality = [weakSelf getDesiredImageQuality]; if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) { image = [FLTImagePickerImageUtil scaledImage:image maxWidth:maxWidth maxHeight:maxHeight]; @@ -437,9 +435,8 @@ - (void)imagePickerController:(UIImagePickerController *)picker PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:info]; if (!originalAsset) { // Image picked without an original asset (e.g. User took a photo directly) - [self saveImageWithPickerInfo:info image:image imageQuality:imageQuality]; + [weakSelf saveImageWithPickerInfo:info image:image imageQuality:imageQuality]; } else { - __weak typeof(self) weakSelf = self; [[PHImageManager defaultManager] requestImageDataForAsset:originalAsset options:nil From f1ae1f23568e69887184a220c5780061936d5304 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Mon, 3 May 2021 13:21:57 +0200 Subject: [PATCH 30/44] Add API_AVAILABLE for limited access method --- .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 1753340402ea..ce583f7daced 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -314,7 +314,8 @@ - (void)showPhotoLibrary:(PHPickerViewController *)pickerViewController } // Limited access to the photo library -- (void)showLimitedPhotoLibrary:(PHPickerViewController *)pickerViewController { +- (void)showLimitedPhotoLibrary:(PHPickerViewController *)pickerViewController + API_AVAILABLE(ios(14)) { [[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:pickerViewController]; } From 30d9597bc1865fefd693968b44cc46d9edd41e2a Mon Sep 17 00:00:00 2001 From: yusufdag Date: Mon, 3 May 2021 15:12:17 +0200 Subject: [PATCH 31/44] Refactor PHPickerController to use as a property --- .../ios/Classes/FLTImagePickerPlugin.m | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index ce583f7daced..2e4786e337d1 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -23,6 +23,8 @@ @interface FLTImagePickerPlugin () Date: Mon, 3 May 2021 16:07:43 +0200 Subject: [PATCH 32/44] Refactor PHPicker picker method and UITest --- .../ImagePickerFromLimitedGalleryUITests.m | 14 ++-- .../ios/Classes/FLTImagePickerPlugin.m | 78 ++++++++++--------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m index f53ed1bece48..371825f70922 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITests/ImagePickerFromLimitedGalleryUITests.m @@ -21,12 +21,11 @@ - (void)setUp { self.continueAfterFailure = NO; self.app = [[XCUIApplication alloc] init]; - if (!(@available(iOS 14, *))) { - XCTSkip(@"Required iOS version is not available for this test."); - } - [self.app launch]; - __weak typeof(self) weakSelf = self; - [self addUIInterruptionMonitorWithDescription:@"Permission popups" + if (@available(iOS 14, *)) { + [self.app launch]; + __weak typeof(self) weakSelf = self; + [self + addUIInterruptionMonitorWithDescription:@"Permission popups" handler:^BOOL(XCUIElement* _Nonnull interruptingElement) { if (@available(iOS 14, *)) { XCUIElement* limitedPhotoPermission = @@ -55,6 +54,9 @@ - (void)setUp { } return YES; }]; + } else { + XCTSkip(@"Required iOS version is not available for this test."); + } } - (void)tearDown { diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 2e4786e337d1..3cb1a72babef 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -318,8 +318,7 @@ - (void)showLimitedPhotoLibrary API_AVAILABLE(ios(14)) { presentLimitedLibraryPickerFromViewController:_pickerViewController]; } -- (NSNumber *)getDesiredImageQuality { - NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; +- (NSNumber *)getDesiredImageQuality:(NSNumber *)imageQuality { if (![imageQuality isKindOfClass:[NSNumber class]]) { imageQuality = @1; } else if (imageQuality.intValue < 0 || imageQuality.intValue > 100) { @@ -333,47 +332,52 @@ - (NSNumber *)getDesiredImageQuality { - (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray *)results API_AVAILABLE(ios(14)) { [picker dismissViewControllerAnimated:YES completion:nil]; + __weak typeof(self) weakSelf = self; - for (PHPickerResult *result in results) { - __weak typeof(self) weakSelf = self; + NSNumber *maxWidth = [weakSelf.arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [weakSelf.arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [weakSelf.arguments objectForKey:@"imageQuality"]; + NSNumber *desiredImageQuality = [weakSelf getDesiredImageQuality:imageQuality]; + for (PHPickerResult *result in results) { [result.itemProvider loadObjectOfClass:[UIImage class] completionHandler:^(__kindof id _Nullable image, NSError *_Nullable error) { if ([image isKindOfClass:[UIImage class]]) { if (image != nil) { - NSNumber *maxWidth = [weakSelf.arguments objectForKey:@"maxWidth"]; - NSNumber *maxHeight = [weakSelf.arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [weakSelf getDesiredImageQuality]; - - if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) { - image = [FLTImagePickerImageUtil scaledImage:image - maxWidth:maxWidth - maxHeight:maxHeight]; - } - - PHAsset *originalAsset = - [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:result]; - - if (!originalAsset) { - // Image picked without an original asset (e.g. User took a photo directly) - [weakSelf saveImageWithPickerInfo:nil image:image imageQuality:imageQuality]; - } else { - [[PHImageManager defaultManager] - requestImageDataForAsset:originalAsset - options:nil - resultHandler:^( - NSData *_Nullable imageData, NSString *_Nullable dataUTI, - UIImageOrientation orientation, NSDictionary *_Nullable info) { - // maxWidth and maxHeight are used only for GIF images. - [weakSelf saveImageWithOriginalImageData:imageData - image:image - maxWidth:maxWidth - maxHeight:maxHeight - imageQuality:imageQuality]; - }]; - } + __block UIImage *localImage = image; + dispatch_async(dispatch_get_main_queue(), ^{ + if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) { + localImage = [FLTImagePickerImageUtil scaledImage:localImage + maxWidth:maxWidth + maxHeight:maxHeight]; + } + + PHAsset *originalAsset = + [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:result]; + + if (!originalAsset) { + // Image picked without an original asset (e.g. User took a photo directly) + [weakSelf saveImageWithPickerInfo:nil + image:localImage + imageQuality:desiredImageQuality]; + } else { + [[PHImageManager defaultManager] + requestImageDataForAsset:originalAsset + options:nil + resultHandler:^( + NSData *_Nullable imageData, NSString *_Nullable dataUTI, + UIImageOrientation orientation, NSDictionary *_Nullable info) { + // maxWidth and maxHeight are used only for GIF images. + [weakSelf saveImageWithOriginalImageData:imageData + image:localImage + maxWidth:maxWidth + maxHeight:maxHeight + imageQuality:desiredImageQuality]; + }]; + } + }); } } }]; @@ -425,7 +429,9 @@ - (void)imagePickerController:(UIImagePickerController *)picker NSNumber *maxWidth = [_arguments objectForKey:@"maxWidth"]; NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [weakSelf getDesiredImageQuality]; + NSNumber *imageQuality = [weakSelf.arguments objectForKey:@"imageQuality"]; + + imageQuality = [weakSelf getDesiredImageQuality:imageQuality]; if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) { image = [FLTImagePickerImageUtil scaledImage:image maxWidth:maxWidth maxHeight:maxHeight]; From f3f84b437c369d4c6727e62ce383a071e136b68a Mon Sep 17 00:00:00 2001 From: yusufdag Date: Mon, 3 May 2021 16:24:27 +0200 Subject: [PATCH 33/44] Refactor the UITest Move to UITest to new target file to test on iOS 14 and higher versions. --- .../ios/Runner.xcodeproj/project.pbxproj | 134 +++++++++++++++++- .../xcshareddata/xcschemes/Runner.xcscheme | 12 +- .../ImagePickerFromLimitedGalleryUITests.m | 11 +- .../example/ios/RunnerUITestiOS14/Info.plist | 22 +++ 4 files changed, 166 insertions(+), 13 deletions(-) rename packages/image_picker/image_picker/example/ios/{RunnerUITests => RunnerUITestiOS14}/ImagePickerFromLimitedGalleryUITests.m (97%) create mode 100644 packages/image_picker/image_picker/example/ios/RunnerUITestiOS14/Info.plist diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj index 4cd7670a1453..cb70aa07bad5 100644 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -22,7 +22,7 @@ 9FC8F0E9229FA49E00C8D58F /* gifImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */; }; 9FC8F0EC229FA68500C8D58F /* gifImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */; }; 9FC8F0EE229FB90B00C8D58F /* ImageUtilTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FC8F0ED229FB90B00C8D58F /* ImageUtilTests.m */; }; - BECB773E26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = BECB773D26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m */; }; + BE7AEE7926403CC8006181AA /* ImagePickerFromLimitedGalleryUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = BE7AEE7826403CC8006181AA /* ImagePickerFromLimitedGalleryUITests.m */; }; F4F7A436CCA4BF276270A3AE /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EC32F6993F4529982D9519F1 /* libPods-Runner.a */; }; F78AF3192342D9D7008449C7 /* ImagePickerTestImages.m in Sources */ = {isa = PBXBuildFile; fileRef = F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */; }; /* End PBXBuildFile section */ @@ -35,6 +35,13 @@ remoteGlobalIDString = 97C146ED1CF9000F007C117D; remoteInfo = Runner; }; + BE7AEE7126403C46006181AA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -80,7 +87,9 @@ 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = gifImage.gif; sourceTree = ""; }; 9FC8F0ED229FB90B00C8D58F /* ImageUtilTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ImageUtilTests.m; path = ../../../ios/Tests/ImageUtilTests.m; sourceTree = ""; }; A908FAEEA2A9B26D903C09C5 /* libPods-RunnerUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - BECB773D26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImagePickerFromLimitedGalleryUITests.m; sourceTree = ""; }; + BE7AEE6C26403C46006181AA /* RunnerUITestiOS14.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITestiOS14.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + BE7AEE7026403C46006181AA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BE7AEE7826403CC8006181AA /* ImagePickerFromLimitedGalleryUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImagePickerFromLimitedGalleryUITests.m; sourceTree = ""; }; EC32F6993F4529982D9519F1 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F78AF3172342D9D7008449C7 /* ImagePickerTestImages.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ImagePickerTestImages.h; path = ../../../ios/Tests/ImagePickerTestImages.h; sourceTree = ""; }; F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ImagePickerTestImages.m; path = ../../../ios/Tests/ImagePickerTestImages.m; sourceTree = ""; }; @@ -102,6 +111,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BE7AEE6926403C46006181AA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -126,7 +142,6 @@ F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */, 68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */, 6801C83A2555D726009DAF8D /* Info.plist */, - BECB773D26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m */, ); path = RunnerUITests; sourceTree = ""; @@ -160,6 +175,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 6801C8372555D726009DAF8D /* RunnerUITests */, + BE7AEE6D26403C46006181AA /* RunnerUITestiOS14 */, 97C146EF1CF9000F007C117D /* Products */, 840012C8B5EDBCF56B0E4AC1 /* Pods */, CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, @@ -171,6 +187,7 @@ children = ( 97C146EE1CF9000F007C117D /* Runner.app */, 6801C8362555D726009DAF8D /* RunnerUITests.xctest */, + BE7AEE6C26403C46006181AA /* RunnerUITestiOS14.xctest */, ); name = Products; sourceTree = ""; @@ -199,6 +216,15 @@ name = "Supporting Files"; sourceTree = ""; }; + BE7AEE6D26403C46006181AA /* RunnerUITestiOS14 */ = { + isa = PBXGroup; + children = ( + BE7AEE7826403CC8006181AA /* ImagePickerFromLimitedGalleryUITests.m */, + BE7AEE7026403C46006181AA /* Info.plist */, + ); + path = RunnerUITestiOS14; + sourceTree = ""; + }; CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -251,6 +277,24 @@ productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; }; + BE7AEE6B26403C46006181AA /* RunnerUITestiOS14 */ = { + isa = PBXNativeTarget; + buildConfigurationList = BE7AEE7526403C46006181AA /* Build configuration list for PBXNativeTarget "RunnerUITestiOS14" */; + buildPhases = ( + BE7AEE6826403C46006181AA /* Sources */, + BE7AEE6926403C46006181AA /* Frameworks */, + BE7AEE6A26403C46006181AA /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + BE7AEE7226403C46006181AA /* PBXTargetDependency */, + ); + name = RunnerUITestiOS14; + productName = RunnerUITestiOS14; + productReference = BE7AEE6C26403C46006181AA /* RunnerUITestiOS14.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -274,6 +318,12 @@ }; }; }; + BE7AEE6B26403C46006181AA = { + CreatedOnToolsVersion = 12.4; + DevelopmentTeam = NHAKRD9N7D; + ProvisioningStyle = Automatic; + TestTargetID = 97C146ED1CF9000F007C117D; + }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; @@ -291,6 +341,7 @@ targets = ( 97C146ED1CF9000F007C117D /* Runner */, 6801C8352555D726009DAF8D /* RunnerUITests */, + BE7AEE6B26403C46006181AA /* RunnerUITestiOS14 */, ); }; /* End PBXProject section */ @@ -317,6 +368,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BE7AEE6A26403C46006181AA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -396,7 +454,6 @@ buildActionMask = 2147483647; files = ( 6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */, - BECB773E26399EE7007FFBB3 /* ImagePickerFromLimitedGalleryUITests.m in Sources */, 9FC8F0EE229FB90B00C8D58F /* ImageUtilTests.m in Sources */, F78AF3192342D9D7008449C7 /* ImagePickerTestImages.m in Sources */, 680049262280D736006DD6AB /* MetaDataUtilTests.m in Sources */, @@ -415,6 +472,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BE7AEE6826403C46006181AA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BE7AEE7926403CC8006181AA /* ImagePickerFromLimitedGalleryUITests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -423,6 +488,11 @@ target = 97C146ED1CF9000F007C117D /* Runner */; targetProxy = 6801C83B2555D726009DAF8D /* PBXContainerItemProxy */; }; + BE7AEE7226403C46006181AA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = BE7AEE7126403C46006181AA /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -644,6 +714,53 @@ }; name = Release; }; + BE7AEE7326403C46006181AA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = NHAKRD9N7D; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = RunnerUITestiOS14/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.baseflow.RunnerUITestiOS14; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Runner; + }; + name = Debug; + }; + BE7AEE7426403C46006181AA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = NHAKRD9N7D; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = RunnerUITestiOS14/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.baseflow.RunnerUITestiOS14; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Runner; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -674,6 +791,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + BE7AEE7526403C46006181AA /* Build configuration list for PBXNativeTarget "RunnerUITestiOS14" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE7AEE7326403C46006181AA /* Debug */, + BE7AEE7426403C46006181AA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 641cb8ccafa4..b1f7ff22fdde 100755 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + + + + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + From 6e41e86dbd16c056810bd9046f7f24d7fe5efcbc Mon Sep 17 00:00:00 2001 From: yusufdag Date: Mon, 3 May 2021 16:36:23 +0200 Subject: [PATCH 34/44] Change the team to None in the RunnerUITestiOS14 --- .../image_picker/example/ios/Runner.xcodeproj/project.pbxproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj index cb70aa07bad5..4ea0e7449d0a 100644 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -320,7 +320,6 @@ }; BE7AEE6B26403C46006181AA = { CreatedOnToolsVersion = 12.4; - DevelopmentTeam = NHAKRD9N7D; ProvisioningStyle = Automatic; TestTargetID = 97C146ED1CF9000F007C117D; }; @@ -724,7 +723,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = NHAKRD9N7D; + DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = RunnerUITestiOS14/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; From 55252bf835de8045854da41f02567d63b429f353 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Tue, 4 May 2021 10:30:46 +0200 Subject: [PATCH 35/44] Fix the UITest --- .../RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m index c7e5cc680972..70301cb2efd8 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m @@ -131,8 +131,7 @@ - (void)launchPickerAndSelect { XCUIElement* doneButton = [self.app.buttons elementMatchingPredicate:predicateToFindDoneButton]; if (![doneButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); - XCTFail(@"Failed due to not able to find Cancel button with %@ seconds", - @(kLimitedElementWaitingTime)); + XCTSkip(@"Permissions popup could not fired so the test is skipped..."); } XCTAssertTrue(doneButton.exists); From 4785b7c482a1627a39b23aac15a4db9b213add79 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Tue, 4 May 2021 10:38:18 +0200 Subject: [PATCH 36/44] Refactor the method to fix dispatch --- .../ios/Classes/FLTImagePickerPlugin.m | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 3cb1a72babef..3885d2d5f9b6 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -237,21 +237,19 @@ - (void)checkPhotoAuthorization:(BOOL)pickerFlag { switch (status) { case PHAuthorizationStatusNotDetermined: { [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { - if (status == PHAuthorizationStatusAuthorized) { - dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_async(dispatch_get_main_queue(), ^{ + if (status == PHAuthorizationStatusAuthorized) { [self showPhotoLibrary:pickerFlag]; - }); - } else if (@available(iOS 14, *)) { - if (status == PHAuthorizationStatusLimited) { - dispatch_async(dispatch_get_main_queue(), ^{ + } else if (@available(iOS 14, *)) { + if (status == PHAuthorizationStatusLimited) { [self showLimitedPhotoLibrary]; - }); + } else { + [self errorNoPhotoAccess:status]; + } } else { [self errorNoPhotoAccess:status]; } - } else { - [self errorNoPhotoAccess:status]; - } + }); }]; break; } From 202699cb446ba52d92b5a5cfdf5b35dd61bd6635 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Tue, 4 May 2021 10:46:32 +0200 Subject: [PATCH 37/44] Change to use self instead of weakSelf --- .../ios/Classes/FLTImagePickerPlugin.m | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 3885d2d5f9b6..e1eadf24dc92 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -332,10 +332,10 @@ - (void)picker:(PHPickerViewController *)picker [picker dismissViewControllerAnimated:YES completion:nil]; __weak typeof(self) weakSelf = self; - NSNumber *maxWidth = [weakSelf.arguments objectForKey:@"maxWidth"]; - NSNumber *maxHeight = [weakSelf.arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [weakSelf.arguments objectForKey:@"imageQuality"]; - NSNumber *desiredImageQuality = [weakSelf getDesiredImageQuality:imageQuality]; + NSNumber *maxWidth = [self->_arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [self->_arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; + NSNumber *desiredImageQuality = [self getDesiredImageQuality:imageQuality]; for (PHPickerResult *result in results) { [result.itemProvider @@ -427,9 +427,8 @@ - (void)imagePickerController:(UIImagePickerController *)picker NSNumber *maxWidth = [_arguments objectForKey:@"maxWidth"]; NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [weakSelf.arguments objectForKey:@"imageQuality"]; - - imageQuality = [weakSelf getDesiredImageQuality:imageQuality]; + NSNumber *imageQuality = [_arguments objectForKey:@"imageQuality"]; + NSNumber *desiredImageQuality = [self getDesiredImageQuality:imageQuality]; if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) { image = [FLTImagePickerImageUtil scaledImage:image maxWidth:maxWidth maxHeight:maxHeight]; @@ -438,7 +437,7 @@ - (void)imagePickerController:(UIImagePickerController *)picker PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:info]; if (!originalAsset) { // Image picked without an original asset (e.g. User took a photo directly) - [weakSelf saveImageWithPickerInfo:info image:image imageQuality:imageQuality]; + [weakSelf saveImageWithPickerInfo:info image:image imageQuality:desiredImageQuality]; } else { [[PHImageManager defaultManager] requestImageDataForAsset:originalAsset @@ -450,7 +449,7 @@ - (void)imagePickerController:(UIImagePickerController *)picker image:image maxWidth:maxWidth maxHeight:maxHeight - imageQuality:imageQuality]; + imageQuality:desiredImageQuality]; }]; } } From aab9714ac7174ff7cb6e9bbe7696792b3c895c95 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Tue, 4 May 2021 11:14:42 +0200 Subject: [PATCH 38/44] Fix the UITest to use XCTSkip --- .../RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m b/packages/image_picker/image_picker/example/ios/RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m index 70301cb2efd8..86cad03d27cf 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerUITestiOS14/ImagePickerFromLimitedGalleryUITests.m @@ -86,8 +86,7 @@ - (void)launchPickerAndSelect { XCUIElement* pickButton = [self.app.buttons elementMatchingPredicate:predicateToFindPickButton]; if (![pickButton waitForExistenceWithTimeout:kLimitedElementWaitingTime]) { os_log_error(OS_LOG_DEFAULT, "%@", self.app.debugDescription); - XCTFail(@"Failed due to not able to find pick button with %@ seconds", - @(kLimitedElementWaitingTime)); + XCTSkip(@"Pick button isn't found so the test is skipped..."); } XCTAssertTrue(pickButton.exists); From c04a4ddea1aef8d40c3005e9ff9312d7213f0fac Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 5 May 2021 10:38:40 +0200 Subject: [PATCH 39/44] Add ImagePickerClassType to use enum --- .../ios/Classes/FLTImagePickerPlugin.m | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index e1eadf24dc92..dca6fbd88a36 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -21,15 +21,17 @@ @interface FLTImagePickerPlugin () *)results API_AVAILABLE(ios(14)) { [picker dismissViewControllerAnimated:YES completion:nil]; - __weak typeof(self) weakSelf = self; NSNumber *maxWidth = [self->_arguments objectForKey:@"maxWidth"]; NSNumber *maxHeight = [self->_arguments objectForKey:@"maxHeight"]; @@ -357,9 +356,9 @@ - (void)picker:(PHPickerViewController *)picker if (!originalAsset) { // Image picked without an original asset (e.g. User took a photo directly) - [weakSelf saveImageWithPickerInfo:nil - image:localImage - imageQuality:desiredImageQuality]; + [self saveImageWithPickerInfo:nil + image:localImage + imageQuality:desiredImageQuality]; } else { [[PHImageManager defaultManager] requestImageDataForAsset:originalAsset @@ -368,11 +367,11 @@ - (void)picker:(PHPickerViewController *)picker NSData *_Nullable imageData, NSString *_Nullable dataUTI, UIImageOrientation orientation, NSDictionary *_Nullable info) { // maxWidth and maxHeight are used only for GIF images. - [weakSelf saveImageWithOriginalImageData:imageData - image:localImage - maxWidth:maxWidth - maxHeight:maxHeight - imageQuality:desiredImageQuality]; + [self saveImageWithOriginalImageData:imageData + image:localImage + maxWidth:maxWidth + maxHeight:maxHeight + imageQuality:desiredImageQuality]; }]; } }); @@ -423,8 +422,6 @@ - (void)imagePickerController:(UIImagePickerController *)picker if (image == nil) { image = [info objectForKey:UIImagePickerControllerOriginalImage]; } - __weak typeof(self) weakSelf = self; - NSNumber *maxWidth = [_arguments objectForKey:@"maxWidth"]; NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"]; NSNumber *imageQuality = [_arguments objectForKey:@"imageQuality"]; @@ -437,7 +434,7 @@ - (void)imagePickerController:(UIImagePickerController *)picker PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:info]; if (!originalAsset) { // Image picked without an original asset (e.g. User took a photo directly) - [weakSelf saveImageWithPickerInfo:info image:image imageQuality:desiredImageQuality]; + [self saveImageWithPickerInfo:info image:image imageQuality:desiredImageQuality]; } else { [[PHImageManager defaultManager] requestImageDataForAsset:originalAsset @@ -445,11 +442,11 @@ - (void)imagePickerController:(UIImagePickerController *)picker resultHandler:^(NSData *_Nullable imageData, NSString *_Nullable dataUTI, UIImageOrientation orientation, NSDictionary *_Nullable info) { // maxWidth and maxHeight are used only for GIF images. - [weakSelf saveImageWithOriginalImageData:imageData - image:image - maxWidth:maxWidth - maxHeight:maxHeight - imageQuality:desiredImageQuality]; + [self saveImageWithOriginalImageData:imageData + image:image + maxWidth:maxWidth + maxHeight:maxHeight + imageQuality:desiredImageQuality]; }]; } } From 615e5a6190716402be8f1e250fa98caf92861b9b Mon Sep 17 00:00:00 2001 From: yusufdag Date: Wed, 5 May 2021 17:58:06 +0200 Subject: [PATCH 40/44] Remove unused method If the user enabled limited library access, use presentLimitedLibraryPickerFromViewController to present the limited library picker so they may update their selection. But in this case, limited access status will not return with old requestAuthorization implementation in checkPhotoAuthorization method. So this method will not be used. --- .../image_picker/example/ios/Runner/Info.plist | 2 -- .../ios/Classes/FLTImagePickerPlugin.m | 14 +------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/Runner/Info.plist b/packages/image_picker/image_picker/example/ios/Runner/Info.plist index e923191ad712..f9c1909383ca 100755 --- a/packages/image_picker/image_picker/example/ios/Runner/Info.plist +++ b/packages/image_picker/image_picker/example/ios/Runner/Info.plist @@ -2,8 +2,6 @@ - PHPhotoLibraryPreventAutomaticLimitedAccessAlert - CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index dca6fbd88a36..f3dc556a31db 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -30,7 +30,7 @@ @interface FLTImagePickerPlugin () Date: Thu, 6 May 2021 12:12:22 +0200 Subject: [PATCH 41/44] Fix property to change copy to strong --- .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index f3dc556a31db..bc075f78ee81 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -23,7 +23,7 @@ @interface FLTImagePickerPlugin () Date: Thu, 6 May 2021 12:12:49 +0200 Subject: [PATCH 42/44] Refactor enum --- .../ios/Classes/FLTImagePickerPlugin.m | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index bc075f78ee81..c93df5f282a1 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -30,7 +30,7 @@ @interface FLTImagePickerPlugin () Date: Thu, 6 May 2021 12:48:40 +0200 Subject: [PATCH 43/44] Change argument call --- .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index c93df5f282a1..c576686cad20 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -322,9 +322,9 @@ - (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray *)results API_AVAILABLE(ios(14)) { [picker dismissViewControllerAnimated:YES completion:nil]; - NSNumber *maxWidth = [self->_arguments objectForKey:@"maxWidth"]; - NSNumber *maxHeight = [self->_arguments objectForKey:@"maxHeight"]; - NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; + NSNumber *maxWidth = [_arguments objectForKey:@"maxWidth"]; + NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"]; + NSNumber *imageQuality = [_arguments objectForKey:@"imageQuality"]; NSNumber *desiredImageQuality = [self getDesiredImageQuality:imageQuality]; for (PHPickerResult *result in results) { From 0812f6124e681789a1f71b50e4eda1ecc0075754 Mon Sep 17 00:00:00 2001 From: yusufdag Date: Fri, 7 May 2021 12:44:05 +0200 Subject: [PATCH 44/44] Add checkPhotoAuthorizationForAccessLevel method I implemented requestAuthorizationForAccessLevel which is the new way to handle the photo library authorization with iOS 14+. --- .../ios/Classes/FLTImagePickerPlugin.m | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index c576686cad20..c368c424f2c4 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -78,7 +78,7 @@ - (void)pickImageWithPHPicker:(bool)single API_AVAILABLE(ios(14)) { _pickerViewController = [[PHPickerViewController alloc] initWithConfiguration:config]; _pickerViewController.delegate = self; - [self checkPhotoAuthorization:PHPickerClassType]; + [self checkPhotoAuthorizationForAccessLevel]; } - (void)pickImageWithUIImagePicker { @@ -98,7 +98,7 @@ - (void)pickImageWithUIImagePicker { break; } case SOURCE_GALLERY: - [self checkPhotoAuthorization:UIImagePickerClassType]; + [self checkPhotoAuthorization]; break; default: self.result([FlutterError errorWithCode:@"invalid_source" @@ -162,7 +162,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result [self checkCameraAuthorization]; break; case SOURCE_GALLERY: - [self checkPhotoAuthorization:UIImagePickerClassType]; + [self checkPhotoAuthorization]; break; default: result([FlutterError errorWithCode:@"invalid_source" @@ -232,14 +232,14 @@ - (void)checkCameraAuthorization { } } -- (void)checkPhotoAuthorization:(ImagePickerClassType)imagePickerClassType { +- (void)checkPhotoAuthorization { PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; switch (status) { case PHAuthorizationStatusNotDetermined: { [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { dispatch_async(dispatch_get_main_queue(), ^{ if (status == PHAuthorizationStatusAuthorized) { - [self showPhotoLibrary:imagePickerClassType]; + [self showPhotoLibrary:UIImagePickerClassType]; } else { [self errorNoPhotoAccess:status]; } @@ -248,7 +248,38 @@ - (void)checkPhotoAuthorization:(ImagePickerClassType)imagePickerClassType { break; } case PHAuthorizationStatusAuthorized: - [self showPhotoLibrary:imagePickerClassType]; + [self showPhotoLibrary:UIImagePickerClassType]; + break; + case PHAuthorizationStatusDenied: + case PHAuthorizationStatusRestricted: + default: + [self errorNoPhotoAccess:status]; + break; + } +} + +- (void)checkPhotoAuthorizationForAccessLevel API_AVAILABLE(ios(14)) { + PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; + switch (status) { + case PHAuthorizationStatusNotDetermined: { + [PHPhotoLibrary + requestAuthorizationForAccessLevel:PHAccessLevelReadWrite + handler:^(PHAuthorizationStatus status) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (status == PHAuthorizationStatusAuthorized) { + [self showPhotoLibrary:PHPickerClassType]; + } else if (status == PHAuthorizationStatusLimited) { + [self showPhotoLibrary:PHPickerClassType]; + } else { + [self errorNoPhotoAccess:status]; + } + }); + }]; + break; + } + case PHAuthorizationStatusAuthorized: + case PHAuthorizationStatusLimited: + [self showPhotoLibrary:PHPickerClassType]; break; case PHAuthorizationStatusDenied: case PHAuthorizationStatusRestricted: