diff --git a/AUTHORS b/AUTHORS index b27c156188f8..17ede94e79ba 100644 --- a/AUTHORS +++ b/AUTHORS @@ -56,4 +56,5 @@ Giancarlo Rocha Ryo Miyake Théo Champion Kazuki Yamaguchi -Eitan Schwartz \ No newline at end of file +Eitan Schwartz +Chris Rutkowski diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index e3856c266464..6b85f26daf33 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.7+2 + +* iOS: Fixes unpresentable album/image picker if window's root view controller is already presenting other view controller. + ## 0.6.7+1 * Add web support to the example app. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h index 38e5b56600f3..b6d8687a32e3 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h @@ -7,7 +7,7 @@ @interface FLTImagePickerPlugin : NSObject // For testing only. -- (instancetype)initWithViewController:(UIViewController *)viewController; - (UIImagePickerController *)getImagePickerController; +- (UIViewController *)viewControllerWithWindow:(UIWindow *)window; @end diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 449157565e7f..00fdec245aaf 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -25,7 +25,6 @@ @interface FLTImagePickerPlugin () *)registrar { FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/image_picker" binaryMessenger:[registrar messenger]]; - UIViewController *viewController = - [UIApplication sharedApplication].delegate.window.rootViewController; - FLTImagePickerPlugin *instance = - [[FLTImagePickerPlugin alloc] initWithViewController:viewController]; + FLTImagePickerPlugin *instance = [FLTImagePickerPlugin new]; [registrar addMethodCallDelegate:instance channel:channel]; } -- (instancetype)initWithViewController:(UIViewController *)viewController { - self = [super init]; - if (self) { - _viewController = viewController; - } - return self; -} - - (UIImagePickerController *)getImagePickerController { return _imagePickerController; } +- (UIViewController *)viewControllerWithWindow:(UIWindow *)window { + UIWindow *windowToUse = window; + if (windowToUse == nil) { + for (UIWindow *window in [UIApplication sharedApplication].windows) { + if (window.isKeyWindow) { + windowToUse = window; + break; + } + } + } + + UIViewController *topController = windowToUse.rootViewController; + while (topController.presentedViewController) { + topController = topController.presentedViewController; + } + return topController; +} + - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { if (self.result) { self.result([FlutterError errorWithCode:@"multiple_request" @@ -136,7 +142,9 @@ - (void)showCamera { [UIImagePickerController isCameraDeviceAvailable:_device]) { _imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; _imagePickerController.cameraDevice = _device; - [_viewController presentViewController:_imagePickerController animated:YES completion:nil]; + [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController + animated:YES + completion:nil]; } else { [[[UIAlertView alloc] initWithTitle:@"Error" message:@"Camera not available." @@ -241,7 +249,9 @@ - (void)errorNoPhotoAccess:(PHAuthorizationStatus)status { - (void)showPhotoLibrary { // No need to check if SourceType is available. It always is. _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; - [_viewController presentViewController:_imagePickerController animated:YES completion:nil]; + [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController + animated:YES + completion:nil]; } - (void)imagePickerController:(UIImagePickerController *)picker diff --git a/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m b/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m index e5c681e7d956..c8d5a2bb5368 100644 --- a/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m +++ b/packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m @@ -7,6 +7,19 @@ @import image_picker; @import XCTest; +@interface MockViewController : UIViewController +@property(nonatomic, retain) UIViewController *mockPresented; +@end + +@implementation MockViewController +@synthesize mockPresented; + +- (UIViewController *)presentedViewController { + return mockPresented; +} + +@end + @interface FLTImagePickerPlugin (Test) @property(copy, nonatomic) FlutterResult result; - (void)handleSavedPath:(NSString *)path; @@ -23,8 +36,7 @@ - (void)testPluginPickImageDeviceBack { if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}]; @@ -39,8 +51,7 @@ - (void)testPluginPickImageDeviceFront { if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}]; @@ -55,8 +66,7 @@ - (void)testPluginPickVideoDeviceBack { if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickVideo" arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}]; @@ -71,8 +81,7 @@ - (void)testPluginPickImageDeviceCancelClickMultipleTimes { if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}]; @@ -90,8 +99,7 @@ - (void)testPluginPickVideoDeviceFront { if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { return; } - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickVideo" arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}]; @@ -104,8 +112,7 @@ - (void)testPluginPickVideoDeviceFront { #pragma mark - Test video duration - (void)testPickingVideoWithDuration { - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickVideo" arguments:@{@"source" : @(0), @"cameraDevice" : @(0), @"maxDuration" : @95}]; @@ -116,8 +123,7 @@ - (void)testPickingVideoWithDuration { } - (void)testPluginPickImageSelectMultipleTimes { - FLTImagePickerPlugin *plugin = - [[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]]; + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}]; @@ -131,4 +137,16 @@ - (void)testPluginPickImageSelectMultipleTimes { [plugin handleSavedPath:@"test"]; } +- (void)testViewController { + UIWindow *window = [UIWindow new]; + MockViewController *vc1 = [MockViewController new]; + window.rootViewController = vc1; + + UIViewController *vc2 = [UIViewController new]; + vc1.mockPresented = vc2; + + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; + XCTAssertEqual([plugin viewControllerWithWindow:window], vc2); +} + @end diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 9086028952ce..4f52b19c2659 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.6.7+1 +version: 0.6.7+2 flutter: plugin: