Skip to content

Commit

Permalink
Creates coordinator for displaying alerts
Browse files Browse the repository at this point in the history
This CL creates an AlertControllerCoordinator which can handle displaying alerts.
This coordinator can display action sheets and modal alerts.

BUG=629515

Review-Url: https://codereview.chromium.org/2119373002
Cr-Commit-Position: refs/heads/master@{#407431}
  • Loading branch information
gambard authored and Commit bot committed Jul 25, 2016
1 parent b9e3d96 commit b61a961
Show file tree
Hide file tree
Showing 8 changed files with 518 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ios/chrome/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ test("ios_chrome_unittests") {
"browser/snapshots/snapshots_util_unittest.mm",
"browser/ssl/ios_ssl_error_handler_unittest.mm",
"browser/translate/translate_service_ios_unittest.cc",
"browser/ui/alert_coordinator/alert_coordinator_unittest.mm",
"browser/ui/commands/set_up_for_testing_command_unittest.mm",
"browser/ui/context_menu/context_menu_coordinator_unittest.mm",
"browser/ui/elements/selector_coordinator_unittest.mm",
Expand Down Expand Up @@ -119,7 +120,9 @@ test("ios_chrome_unittests") {
"//testing/gtest",
"//third_party/google_toolbox_for_mac",
"//third_party/ocmock",
"//ui/base:base",
"//ui/gfx:test_support",
"//ui/strings:ui_strings",
]

assert_no_deps = ios_assert_no_deps
Expand Down
2 changes: 2 additions & 0 deletions ios/chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,8 @@ source_set("browser") {
"translate/translate_service_ios.h",
"ui/UIView+SizeClassSupport.h",
"ui/UIView+SizeClassSupport.mm",
"ui/alert_coordinator/alert_coordinator.h",
"ui/alert_coordinator/alert_coordinator.mm",
"ui/animation_util.h",
"ui/animation_util.mm",
"ui/autofill/autofill_client_ios.h",
Expand Down
2 changes: 2 additions & 0 deletions ios/chrome/browser/ui/alert_coordinator/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gambard@chromium.org
jyquinn@chromium.org
53 changes: 53 additions & 0 deletions ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// 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.

#ifndef IOS_CHROME_BROWSER_UI_ALERT_COORDINATOR_ALERT_COORDINATOR_H_
#define IOS_CHROME_BROWSER_UI_ALERT_COORDINATOR_ALERT_COORDINATOR_H_

#import <UIKit/UIKit.h>

#include "base/ios/block_types.h"
#import "ios/chrome/browser/chrome_coordinator.h"

// A coordinator specialization for the case where the coordinator is
// creating and managing an alert (popup or action sheet) to be displayed to the
// user. Dismiss it with no animation.
// The type of alert displayed depends on the init called.
// Calling |-stop| on this coordinator destroys the current alert.
@interface AlertCoordinator : ChromeCoordinator

// Whether a cancel button has been added.
@property(nonatomic, readonly) BOOL cancelButtonAdded;
// Message of the alert.
@property(nonatomic, copy) NSString* message;
// Whether the alert is visible. This will be true after |-start| is called
// until a subsequent |-stop|.
@property(nonatomic, readonly, getter=isVisible) BOOL visible;

- (instancetype)initWithBaseViewController:(UIViewController*)viewController
NS_UNAVAILABLE;

// Init a coordinator for displaying a alert on this view controller. If
// |-configureForActionSheetWithRect:popoverView:| is not called, it will be a
// modal alert.
- (instancetype)initWithBaseViewController:(UIViewController*)viewController
title:(NSString*)title
NS_DESIGNATED_INITIALIZER;

// Call this before adding any button to change the alert to an action sheet.
- (void)configureForActionSheetWithRect:(CGRect)rect popoverView:(UIView*)view;

// Adds an item at the end of the menu. It does nothing if |visible| is true or
// if trying to add an item with a UIAlertActionStyleCancel while
// |cancelButtonAdded| is true.
- (void)addItemWithTitle:(NSString*)title
action:(ProceduralBlock)actionBlock
style:(UIAlertActionStyle)style;

// Returns the number of actions attached to the current alert.
- (NSUInteger)actionsCount;

@end

#endif // IOS_CHROME_BROWSER_UI_ALERT_COORDINATOR_ALERT_COORDINATOR_H_
159 changes: 159 additions & 0 deletions ios/chrome/browser/ui/alert_coordinator/alert_coordinator.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// 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"

#import "base/ios/weak_nsobject.h"
#import "base/mac/scoped_nsobject.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/strings/grit/ui_strings.h"

@interface AlertCoordinator () {
// Variables backing properties of the same name.
base::scoped_nsobject<UIAlertController> _alertController;
base::scoped_nsobject<NSString> _message;

// Title for the alert.
base::scoped_nsobject<NSString> _title;
// Rectangle for the popover alert.
CGRect _rect;
// View for the popovert alert.
base::scoped_nsobject<UIView> _view;
// Style for this alert.
UIAlertControllerStyle _style;
}

// Redefined to readwrite.
@property(nonatomic, readwrite, getter=isVisible) BOOL visible;
// Lazy initializer to create the |_alert|.
@property(nonatomic, readonly) UIAlertController* alertController;

// Called when the alert is dismissed to perform cleanup.
- (void)alertDismissed;

@end

@implementation AlertCoordinator

@synthesize visible = _visible;
@synthesize cancelButtonAdded = _cancelButtonAdded;

- (instancetype)initWithBaseViewController:(UIViewController*)viewController {
NOTREACHED();
return nil;
}

- (instancetype)initWithBaseViewController:(UIViewController*)viewController
title:(NSString*)title {
self = [super initWithBaseViewController:viewController];
if (self) {
_style = UIAlertControllerStyleAlert;
_title.reset([title copy]);
}
return self;
}

#pragma mark - Public Methods.

- (void)configureForActionSheetWithRect:(CGRect)rect popoverView:(UIView*)view {
if (_alertController)
return;

_style = UIAlertControllerStyleActionSheet;
_view.reset([view retain]);
_rect = rect;
}

- (void)addItemWithTitle:(NSString*)title
action:(ProceduralBlock)actionBlock
style:(UIAlertActionStyle)style {
if (self.visible ||
(style == UIAlertActionStyleCancel && self.cancelButtonAdded)) {
return;
}

if (style == UIAlertActionStyleCancel)
_cancelButtonAdded = YES;

base::WeakNSObject<AlertCoordinator> weakSelf(self);

UIAlertAction* alertAction =
[UIAlertAction actionWithTitle:title
style:style
handler:^(UIAlertAction*) {
[weakSelf alertDismissed];
if (actionBlock)
actionBlock();
}];

[self.alertController addAction:alertAction];
}

- (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 actionsCount] == 0) {
[self addItemWithTitle:l10n_util::GetNSString(IDS_APP_OK)
action:nil
style:UIAlertActionStyleDefault];
}

[self.baseViewController presentViewController:self.alertController
animated:YES
completion:nil];
self.visible = YES;
}

- (void)stop {
[_alertController dismissViewControllerAnimated:NO completion:nil];
[self alertDismissed];
}

- (NSUInteger)actionsCount {
return [_alertController actions].count;
}

#pragma mark - Property Implementation.

- (UIAlertController*)alertController {
if (!_alertController) {
UIAlertController* alert =
[UIAlertController alertControllerWithTitle:_title
message:_message
preferredStyle:_style];

if (alert)
_alertController.reset([alert retain]);

if (_style == UIAlertControllerStyleActionSheet) {
alert.popoverPresentationController.sourceView = _view;
alert.popoverPresentationController.sourceRect = _rect;
}
}
return _alertController;
}

- (NSString*)message {
return _message;
}

- (void)setMessage:(NSString*)message {
_message.reset([message copy]);
}

#pragma mark - Private Methods.

- (void)alertDismissed {
self.visible = NO;
_cancelButtonAdded = NO;
_alertController.reset();
}

@end
Loading

0 comments on commit b61a961

Please sign in to comment.