diff --git a/Examples/UIExplorer/AlertIOSExample.js b/Examples/UIExplorer/AlertIOSExample.js index 2d57fd5fe..e09c883c1 100644 --- a/Examples/UIExplorer/AlertIOSExample.js +++ b/Examples/UIExplorer/AlertIOSExample.js @@ -132,7 +132,7 @@ class PromptExample extends React.Component { + onPress={this.prompt.bind(this, this.title, null, null, this.promptResponse)}> @@ -143,7 +143,7 @@ class PromptExample extends React.Component { + onPress={this.prompt.bind(this, this.title, null, this.buttons, null)}> @@ -154,7 +154,7 @@ class PromptExample extends React.Component { + onPress={this.prompt.bind(this, this.title, this.defaultValue, null, this.promptResponse)}> @@ -165,7 +165,7 @@ class PromptExample extends React.Component { + onPress={this.prompt.bind(this, this.title, this.defaultValue, this.buttons, null)}> diff --git a/React/Modules/RCTAlertManager.m b/React/Modules/RCTAlertManager.m index b07dcde54..937bcf5da 100644 --- a/React/Modules/RCTAlertManager.m +++ b/React/Modules/RCTAlertManager.m @@ -20,6 +20,7 @@ @implementation RCTAlertManager { NSMutableArray *_alerts; + NSMutableArray *_alertControllers; NSMutableArray *_alertCallbacks; NSMutableArray *_alertButtonKeys; } @@ -30,6 +31,7 @@ RCT_EXPORT_MODULE() { if ((self = [super init])) { _alerts = [NSMutableArray new]; + _alertControllers = [NSMutableArray new]; _alertCallbacks = [NSMutableArray new]; _alertButtonKeys = [NSMutableArray new]; } @@ -43,9 +45,12 @@ RCT_EXPORT_MODULE() - (void)invalidate { - for (UIAlertView *alert in _alerts) { - [alert dismissWithClickedButtonIndex:0 animated:YES]; - } + for (UIAlertView *alert in _alerts) { + [alert dismissWithClickedButtonIndex:0 animated:YES]; + } + for (UIAlertController *alertController in _alertControllers) { + [alertController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; + } } /** @@ -69,6 +74,7 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args NSString *message = args[@"message"]; NSString *type = args[@"type"]; NSArray *buttons = args[@"buttons"]; + BOOL allowsTextInput = [type isEqual:@"plain-text"]; if (!title && !message) { RCTLogError(@"Must specify either an alert title, or message, or both"); @@ -77,41 +83,88 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args RCTLogError(@"Must have at least one button."); return; } - + if (RCTRunningInAppExtension()) { return; } - - UIAlertView *alertView = RCTAlertView(title, nil, self, nil, nil); - NSMutableArray *buttonKeys = [[NSMutableArray alloc] initWithCapacity:buttons.count]; - if ([type isEqualToString:@"plain-text"]) { - alertView.alertViewStyle = UIAlertViewStylePlainTextInput; - [alertView textFieldAtIndex:0].text = message; - } else { - alertView.message = message; + UIViewController *presentingController = RCTSharedApplication().delegate.window.rootViewController; + if (presentingController == nil) { + RCTLogError(@"Tried to display alert view but there is no application window. args: %@", args); + return; } - NSInteger index = 0; - for (NSDictionary *button in buttons) { - if (button.count != 1) { - RCTLogError(@"Button definitions should have exactly one key."); +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0 + if ([UIAlertController class] == nil) { + UIAlertView *alertView = RCTAlertView(title, nil, self, nil, nil); + NSMutableArray *buttonKeys = [[NSMutableArray alloc] initWithCapacity:buttons.count]; + + if (allowsTextInput) { + alertView.alertViewStyle = UIAlertViewStylePlainTextInput; + [alertView textFieldAtIndex:0].text = message; + } else { + alertView.message = message; } - NSString *buttonKey = button.allKeys.firstObject; - NSString *buttonTitle = [button[buttonKey] description]; - [alertView addButtonWithTitle:buttonTitle]; - if ([buttonKey isEqualToString: @"cancel"]) { - alertView.cancelButtonIndex = index; + + NSInteger index = 0; + for (NSDictionary *button in buttons) { + if (button.count != 1) { + RCTLogError(@"Button definitions should have exactly one key."); + } + NSString *buttonKey = button.allKeys.firstObject; + NSString *buttonTitle = [button[buttonKey] description]; + [alertView addButtonWithTitle:buttonTitle]; + if ([buttonKey isEqualToString:@"cancel"]) { + alertView.cancelButtonIndex = index; + } + [buttonKeys addObject:buttonKey]; + index ++; } - [buttonKeys addObject:buttonKey]; - index ++; + + [_alerts addObject:alertView]; + [_alertCallbacks addObject:callback ?: ^(__unused id unused) {}]; + [_alertButtonKeys addObject:buttonKeys]; + + [alertView show]; + } else +#endif + { + UIAlertController *alertController = + [UIAlertController alertControllerWithTitle:title + message:nil + preferredStyle:UIAlertControllerStyleAlert]; + + if (allowsTextInput) { + [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.text = message; + }]; + } else { + alertController.message = message; + } + + for (NSDictionary *button in buttons) { + if (button.count != 1) { + RCTLogError(@"Button definitions should have exactly one key."); + } + NSString *buttonKey = button.allKeys.firstObject; + NSString *buttonTitle = [button[buttonKey] description]; + UIAlertActionStyle buttonStyle = [buttonKey isEqualToString:@"cancel"] ? UIAlertActionStyleCancel : UIAlertActionStyleDefault; + UITextField *textField = allowsTextInput ? alertController.textFields.firstObject : nil; + [alertController addAction:[UIAlertAction actionWithTitle:buttonTitle + style:buttonStyle + handler:^(UIAlertAction *action) { + if (callback) { + if (allowsTextInput) { + callback(@[buttonKey, textField.text]); + } else { + callback(@[buttonKey]); + } + } + }]]; + } + + [presentingController presentViewController:alertController animated:YES completion:nil]; } - - [_alerts addObject:alertView]; - [_alertCallbacks addObject:callback ?: ^(__unused id unused) {}]; - [_alertButtonKeys addObject:buttonKeys]; - - [alertView show]; } #pragma mark - UIAlertViewDelegate