blob: 7b47f1e3f1630a1cfe6ebd6db63eb4950983d451 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
#include "base/logging.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/strings/grit/ui_strings.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface AlertCoordinator () {
// Variable backing a property from Subclassing category.
UIAlertController* _alertController;
// Title for the alert.
NSString* _title;
}
// Redefined to readwrite.
@property(nonatomic, readwrite, getter=isVisible) BOOL visible;
// Cancel action passed using the public API.
// It will called from the overridden block stored in the |cancelAction|
// property.
@property(nonatomic, copy) ProceduralBlock rawCancelAction;
// Called when the alert is dismissed to perform cleanup.
- (void)alertDismissed;
- (UIAlertController*)alertControllerWithTitle:(NSString*)title
message:(NSString*)message;
@end
@implementation AlertCoordinator
@synthesize visible = _visible;
@synthesize cancelButtonAdded = _cancelButtonAdded;
@synthesize cancelAction = _cancelAction;
@synthesize startAction = _startAction;
@synthesize noInteractionAction = _noInteractionAction;
@synthesize rawCancelAction = _rawCancelAction;
@synthesize message = _message;
- (instancetype)initWithBaseViewController:(UIViewController*)viewController {
NOTREACHED();
return nil;
}
- (instancetype)initWithBaseViewController:(UIViewController*)viewController
title:(NSString*)title
message:(NSString*)message {
self = [super initWithBaseViewController:viewController];
if (self) {
_title = [title copy];
_message = [message copy];
}
return self;
}
#pragma mark - Public Methods.
- (void)addItemWithTitle:(NSString*)title
action:(ProceduralBlock)actionBlock
style:(UIAlertActionStyle)style {
if (self.visible ||
(style == UIAlertActionStyleCancel && self.cancelButtonAdded)) {
return;
}
if (style == UIAlertActionStyleCancel)
_cancelButtonAdded = YES;
__weak AlertCoordinator* weakSelf = self;
UIAlertAction* alertAction =
[UIAlertAction actionWithTitle:title
style:style
handler:^(UIAlertAction*) {
[weakSelf setNoInteractionAction:nil];
if (actionBlock)
actionBlock();
[weakSelf alertDismissed];
}];
[self.alertController addAction:alertAction];
}
- (void)executeCancelHandler {
self.noInteractionAction = nil;
if (self.cancelAction)
self.cancelAction();
}
- (void)start {
// Check that the view is still visible on screen, otherwise just return and
// don't show the context menu.
if (![self.baseViewController.view window] &&
![self.baseViewController.view isKindOfClass:[UIWindow class]]) {
return;
}
// Display at least one button to let the user dismiss the alert.
if ([self.alertController actions].count == 0) {
[self addItemWithTitle:l10n_util::GetNSString(IDS_APP_OK)
action:nil
style:UIAlertActionStyleDefault];
}
// Call the start action before presenting the alert.
if (self.startAction)
self.startAction();
[self.baseViewController presentViewController:self.alertController
animated:YES
completion:nil];
self.visible = YES;
}
- (void)stop {
if (_noInteractionAction) {
_noInteractionAction();
_noInteractionAction = nil;
}
[[_alertController presentingViewController]
dismissViewControllerAnimated:NO
completion:nil];
[self alertDismissed];
}
#pragma mark - Property Implementation.
- (UIAlertController*)alertController {
if (!_alertController) {
UIAlertController* alert =
[self alertControllerWithTitle:_title message:_message];
if (alert)
_alertController = alert;
}
return _alertController;
}
- (NSString*)message {
return _message;
}
- (void)setCancelAction:(ProceduralBlock)cancelAction {
__weak AlertCoordinator* weakSelf = self;
self.rawCancelAction = cancelAction;
_cancelAction = [^{
AlertCoordinator* strongSelf = weakSelf;
[strongSelf setNoInteractionAction:nil];
if ([strongSelf rawCancelAction]) {
[strongSelf rawCancelAction]();
}
} copy];
}
#pragma mark - Private Methods.
- (void)alertDismissed {
self.visible = NO;
_cancelButtonAdded = NO;
_alertController = nil;
_cancelAction = nil;
_noInteractionAction = nil;
}
- (UIAlertController*)alertControllerWithTitle:(NSString*)title
message:(NSString*)message {
return
[UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
}
@end