Skip to content

Commit

Permalink
[image_picker] fixes for iOS which doesn't present camera/albums with…
Browse files Browse the repository at this point in the history
… more complex navigation (flutter#2755)
  • Loading branch information
chris-rutkowski authored Jun 15, 2020
1 parent 90462df commit ff53b70
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 32 deletions.
3 changes: 2 additions & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,5 @@ Giancarlo Rocha <[email protected]>
Ryo Miyake <[email protected]>
Théo Champion <[email protected]>
Kazuki Yamaguchi <[email protected]>
Eitan Schwartz <[email protected]>
Eitan Schwartz <[email protected]>
Chris Rutkowski <[email protected]>
4 changes: 4 additions & 0 deletions packages/image_picker/image_picker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@interface FLTImagePickerPlugin : NSObject <FlutterPlugin>

// For testing only.
- (instancetype)initWithViewController:(UIViewController *)viewController;
- (UIImagePickerController *)getImagePickerController;
- (UIViewController *)viewControllerWithWindow:(UIWindow *)window;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,39 @@ @interface FLTImagePickerPlugin () <UINavigationControllerDelegate, UIImagePicke
@implementation FLTImagePickerPlugin {
NSDictionary *_arguments;
UIImagePickerController *_imagePickerController;
UIViewController *_viewController;
UIImagePickerControllerCameraDevice _device;
}

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)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"
Expand Down Expand Up @@ -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."
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)}];
Expand All @@ -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)}];
Expand All @@ -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)}];
Expand All @@ -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)}];
Expand All @@ -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)}];
Expand All @@ -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}];
Expand All @@ -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)}];
Expand All @@ -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
2 changes: 1 addition & 1 deletion packages/image_picker/image_picker/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit ff53b70

Please sign in to comment.