diff --git a/React/Modules/RCTAlertManager.m b/React/Modules/RCTAlertManager.m index bb1f3ceaa42e10..59f175befb7f88 100644 --- a/React/Modules/RCTAlertManager.m +++ b/React/Modules/RCTAlertManager.m @@ -30,6 +30,7 @@ @interface RCTAlertManager() @implementation RCTAlertManager { NSHashTable *_alertControllers; + UIWindow *_window; } RCT_EXPORT_MODULE() @@ -90,11 +91,16 @@ - (void)invalidate } } - UIViewController *presentingController = RCTPresentedViewController(); - if (presentingController == nil) { - RCTLogError(@"Tried to display alert view but there is no application window. args: %@", args); - return; - } + CGSize screenSize = [UIScreen mainScreen].bounds.size; + self->_window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, screenSize.height)]; +#if TARGET_OS_TV + self->_window.windowLevel = UIWindowLevelNormal + 1; +#else + self->_window.windowLevel = UIWindowLevelStatusBar + 1; +#endif + UIViewController *presentingController = [UIViewController new]; + self->_window.rootViewController = presentingController; + self->_window.hidden = NO; UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title @@ -152,6 +158,7 @@ - (void)invalidate [alertController addAction:[UIAlertAction actionWithTitle:buttonTitle style:buttonStyle handler:^(__unused UIAlertAction *action) { + self->_window = nil; switch (type) { case RCTAlertViewStylePlainTextInput: case RCTAlertViewStyleSecureTextInput: diff --git a/React/Views/RCTModalHostView.m b/React/Views/RCTModalHostView.m index bc0cac18b3ec94..c9962fb185e113 100644 --- a/React/Views/RCTModalHostView.m +++ b/React/Views/RCTModalHostView.m @@ -159,7 +159,9 @@ - (void)didUpdateReactSubviews - (void)dismissModalViewController { if (_isPresented) { - [_delegate dismissModalHostView:self withViewController:_modalViewController animated:[self hasAnimationType]]; + [_delegate dismissModalHostView:self + withViewController:_modalViewController + animated:[self hasAnimationType]]; _isPresented = NO; } } diff --git a/React/Views/RCTModalHostViewManager.m b/React/Views/RCTModalHostViewManager.m index 28c1c5e9423060..ec09cfb0e14d83 100644 --- a/React/Views/RCTModalHostViewManager.m +++ b/React/Views/RCTModalHostViewManager.m @@ -75,7 +75,19 @@ - (void)presentModalHostView:(RCTModalHostView *)modalHostView withViewControlle if (_presentationBlock) { _presentationBlock([modalHostView reactViewController], viewController, animated, completionBlock); } else { - [[modalHostView reactViewController] presentViewController:viewController animated:animated completion:completionBlock]; + UIViewController *topViewController = [modalHostView reactViewController]; + while (topViewController.presentedViewController != nil) { + if ([topViewController.presentedViewController isKindOfClass:UIAlertController.class]) { + // Don't present on top of UIAlertController, this will mess it up: + // https://stackoverflow.com/questions/27028983/uialertcontroller-is-moved-to-buggy-position-at-top-of-screen-when-it-calls-pre + [topViewController dismissViewControllerAnimated:animated completion:^{ + [topViewController presentViewController:viewController animated:animated completion:completionBlock]; + }]; + return; + } + topViewController = topViewController.presentedViewController; + } + [topViewController presentViewController:viewController animated:animated completion:completionBlock]; } } @@ -89,7 +101,13 @@ - (void)dismissModalHostView:(RCTModalHostView *)modalHostView withViewControlle if (_dismissalBlock) { _dismissalBlock([modalHostView reactViewController], viewController, animated, completionBlock); } else { - [viewController.presentingViewController dismissViewControllerAnimated:animated completion:completionBlock]; + if (viewController.presentedViewController && viewController.presentingViewController) { + // Ask the presenting view controller to dismiss any view controllers presented on top of the modal host + // together with the host itself. + [viewController.presentingViewController dismissViewControllerAnimated:animated completion:completionBlock]; + } else { + [viewController dismissViewControllerAnimated:animated completion:completionBlock]; + } } }