| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- /*
- * Copyright 2017 Google
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #import "UIViewController+Alerts.h"
- #import <objc/runtime.h>
- /*! @var kPleaseWaitAssociatedObjectKey
- @brief Key used to identify the "please wait" spinner associated object.
- */
- static NSString *const kPleaseWaitAssociatedObjectKey =
- @"_UIViewControllerAlertCategory_PleaseWaitScreenAssociatedObject";
- /*! @var kUseStatusBarSpinnerAssociatedObjectKey
- @brief The address of this constant is the key used to identify the "use status bar spinner"
- associated object.
- */
- static const void *const kUseStatusBarSpinnerAssociatedObjectKey;
- /*! @var kOK
- @brief Text for an 'OK' button.
- */
- static NSString *const kOK = @"OK";
- /*! @var kCancel
- @brief Text for an 'Cancel' button.
- */
- static NSString *const kCancel = @"Cancel";
- /*! @class SimpleTextPromptDelegate
- @brief A @c UIAlertViewDelegate which allows @c UIAlertView to be used with blocks more easily.
- */
- @interface SimpleTextPromptDelegate : NSObject <UIAlertViewDelegate>
- /*! @fn init
- @brief Please use initWithCompletionHandler.
- */
- - (nullable instancetype)init NS_UNAVAILABLE;
- /*! @fn initWithCompletionHandler:
- @brief Designated initializer.
- @param completionHandler The block to call when the alert view is dismissed.
- */
- - (nullable instancetype)initWithCompletionHandler:(AlertPromptCompletionBlock)completionHandler
- NS_DESIGNATED_INITIALIZER;
- @end
- @implementation UIViewController (Alerts)
- - (void)setUseStatusBarSpinner:(BOOL)useStatusBarSpinner {
- objc_setAssociatedObject(self,
- &kUseStatusBarSpinnerAssociatedObjectKey,
- useStatusBarSpinner ? @(YES) : nil,
- OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
- - (BOOL)useStatusBarSpinner {
- return objc_getAssociatedObject(self, &kUseStatusBarSpinnerAssociatedObjectKey) ? YES : NO;
- }
- /*! @fn supportsAlertController
- @brief Determines if the current platform supports @c UIAlertController.
- @return YES if the current platform supports @c UIAlertController.
- */
- - (BOOL)supportsAlertController {
- return NSClassFromString(@"UIAlertController") != nil;
- }
- - (void)showMessagePrompt:(NSString *)message {
- [self showMessagePromptWithTitle:nil message:message showCancelButton:NO completion:nil];
- }
- - (void)showMessagePromptWithTitle:(nullable NSString *)title
- message:(NSString *)message
- showCancelButton:(BOOL)showCancelButton
- completion:(nullable AlertPromptCompletionBlock)completion {
- if (message) {
- [UIPasteboard generalPasteboard].string = message;
- }
- if ([self supportsAlertController]) {
- UIAlertController *alert =
- [UIAlertController alertControllerWithTitle:title
- message:message
- preferredStyle:UIAlertControllerStyleAlert];
- UIAlertAction *okAction =
- [UIAlertAction actionWithTitle:kOK
- style:UIAlertActionStyleDefault
- handler:^(UIAlertAction * _Nonnull action) {
- if (completion) {
- completion(YES, nil);
- }
- }];
- [alert addAction:okAction];
- if (showCancelButton) {
- UIAlertAction *cancelAction =
- [UIAlertAction actionWithTitle:kCancel
- style:UIAlertActionStyleCancel
- handler:^(UIAlertAction * _Nonnull action) {
- completion(NO, nil);
- }];
- [alert addAction:cancelAction];
- }
- [self presentViewController:alert animated:YES completion:nil];
- } else {
- UIAlertView *alert =
- [[UIAlertView alloc] initWithTitle:title
- message:message
- delegate:nil
- cancelButtonTitle:nil
- otherButtonTitles:kOK, nil];
- [alert show];
- }
- }
- - (void)showTextInputPromptWithMessage:(NSString *)message
- completionBlock:(AlertPromptCompletionBlock)completion {
- [self showTextInputPromptWithMessage:message
- keyboardType:UIKeyboardTypeDefault
- completionBlock:completion];
- }
- - (void)showTextInputPromptWithMessage:(NSString *)message
- keyboardType:(UIKeyboardType)keyboardType
- completionBlock:(nonnull AlertPromptCompletionBlock)completion {
- if ([self supportsAlertController]) {
- UIAlertController *prompt =
- [UIAlertController alertControllerWithTitle:nil
- message:message
- preferredStyle:UIAlertControllerStyleAlert];
- __weak UIAlertController *weakPrompt = prompt;
- UIAlertAction *cancelAction =
- [UIAlertAction actionWithTitle:kCancel
- style:UIAlertActionStyleCancel
- handler:^(UIAlertAction * _Nonnull action) {
- completion(NO, nil);
- }];
- UIAlertAction *okAction = [UIAlertAction actionWithTitle:kOK
- style:UIAlertActionStyleDefault
- handler:^(UIAlertAction * _Nonnull action) {
- UIAlertController *strongPrompt = weakPrompt;
- completion(YES, strongPrompt.textFields[0].text);
- }];
- [prompt addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) {
- textField.keyboardType = keyboardType;
- }];
- [prompt addAction:cancelAction];
- [prompt addAction:okAction];
- [[AppDelegate sharedAppDelegate].topViewController presentViewController:prompt animated:YES completion:nil];
- } else {
- SimpleTextPromptDelegate *prompt =
- [[SimpleTextPromptDelegate alloc] initWithCompletionHandler:completion];
- UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil
- message:message
- delegate:prompt
- cancelButtonTitle:@"Cancel"
- otherButtonTitles:@"Ok", nil];
- alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
- [alertView show];
- }
- }
- - (void)showSpinner:(nullable void(^)(void))completion {
- if (self.useStatusBarSpinner) {
- [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
- completion();
- return;
- }
- if ([self supportsAlertController]) {
- [self showModernSpinner:completion];
- } else {
- [self showIOS7Spinner:completion];
- }
- }
- - (void)showModernSpinner:(nullable void (^)(void))completion {
- UIAlertController *pleaseWaitAlert =
- objc_getAssociatedObject(self,
- (__bridge const void *)kPleaseWaitAssociatedObjectKey);
- if (pleaseWaitAlert) {
- if (completion) {
- completion();
- }
- return;
- }
- pleaseWaitAlert = [UIAlertController alertControllerWithTitle:nil
- message:@"Please Wait...\n\n\n\n"
- preferredStyle:UIAlertControllerStyleAlert];
- UIActivityIndicatorView *spinner =
- [[UIActivityIndicatorView alloc]
- initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
- spinner.color = [UIColor blackColor];
- spinner.center = CGPointMake(pleaseWaitAlert.view.bounds.size.width / 2,
- pleaseWaitAlert.view.bounds.size.height / 2);
- spinner.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin |
- UIViewAutoresizingFlexibleTopMargin |
- UIViewAutoresizingFlexibleLeftMargin |
- UIViewAutoresizingFlexibleRightMargin;
- [spinner startAnimating];
- [pleaseWaitAlert.view addSubview:spinner];
- objc_setAssociatedObject(self,
- (__bridge const void *)(kPleaseWaitAssociatedObjectKey),
- pleaseWaitAlert,
- OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- [self presentViewController:pleaseWaitAlert animated:YES completion:completion];
- }
- - (void)showIOS7Spinner:(nullable void (^)(void))completion {
- UIWindow *pleaseWaitWindow =
- objc_getAssociatedObject(self,
- (__bridge const void *)kPleaseWaitAssociatedObjectKey);
- if (pleaseWaitWindow) {
- if (completion) {
- completion();
- }
- return;
- }
- pleaseWaitWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- pleaseWaitWindow.backgroundColor = [UIColor clearColor];
- pleaseWaitWindow.windowLevel = UIWindowLevelStatusBar - 1;
- UIView *pleaseWaitView = [[UIView alloc] initWithFrame:pleaseWaitWindow.bounds];
- pleaseWaitView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
- UIViewAutoresizingFlexibleHeight;
- pleaseWaitView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
- UIActivityIndicatorView *spinner =
- [[UIActivityIndicatorView alloc]
- initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
- spinner.center = pleaseWaitView.center;
- [pleaseWaitView addSubview:spinner];
- [spinner startAnimating];
- pleaseWaitView.layer.opacity = 0.0;
- [self.view addSubview:pleaseWaitView];
- [pleaseWaitWindow addSubview:pleaseWaitView];
- [pleaseWaitWindow makeKeyAndVisible];
- objc_setAssociatedObject(self,
- (__bridge const void *)(kPleaseWaitAssociatedObjectKey),
- pleaseWaitWindow,
- OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- [UIView animateWithDuration:0.5f animations:^{
- pleaseWaitView.layer.opacity = 1.0f;
- } completion:^(BOOL finished) {
- if (completion) {
- completion();
- }
- }];
- }
- - (void)hideSpinner:(nullable void(^)(void))completion {
- if (self.useStatusBarSpinner) {
- [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
- completion();
- return;
- }
- if ([self supportsAlertController]) {
- [self hideModernSpinner:completion];
- } else {
- [self hideIOS7Spinner:completion];
- }
- }
- - (void)hideModernSpinner:(nullable void(^)(void))completion {
- UIAlertController *pleaseWaitAlert =
- objc_getAssociatedObject(self,
- (__bridge const void *)kPleaseWaitAssociatedObjectKey);
- [pleaseWaitAlert dismissViewControllerAnimated:YES completion:completion];
- objc_setAssociatedObject(self,
- (__bridge const void *)(kPleaseWaitAssociatedObjectKey),
- nil,
- OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
- - (void)hideIOS7Spinner:(nullable void(^)(void))completion {
- UIWindow *pleaseWaitWindow =
- objc_getAssociatedObject(self,
- (__bridge const void *)kPleaseWaitAssociatedObjectKey);
- UIView *pleaseWaitView;
- pleaseWaitView = pleaseWaitWindow.subviews.firstObject;
- [UIView animateWithDuration:0.5f animations:^{
- pleaseWaitView.layer.opacity = 0.0f;
- } completion:^(BOOL finished) {
- [pleaseWaitWindow resignKeyWindow];
- objc_setAssociatedObject(self,
- (__bridge const void *)(kPleaseWaitAssociatedObjectKey),
- nil,
- OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if (completion) {
- completion();
- }
- }];
- }
- @end
- @implementation SimpleTextPromptDelegate {
- AlertPromptCompletionBlock _completionHandler;
- SimpleTextPromptDelegate *_retainedSelf;
- }
- - (instancetype)initWithCompletionHandler:(AlertPromptCompletionBlock)completionHandler {
- self = [super init];
- if (self) {
- _completionHandler = completionHandler;
- _retainedSelf = self;
- }
- return self;
- }
- - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
- if (buttonIndex == alertView.firstOtherButtonIndex) {
- _completionHandler(YES, [alertView textFieldAtIndex:0].text);
- } else {
- _completionHandler(NO, nil);
- }
- _completionHandler = nil;
- _retainedSelf = nil;
- }
- @end
|