| // Copyright 2019 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. |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| #import "remoting/ios/app/notification_dialog_view_controller.h" |
| |
| #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h" |
| #import "ios/third_party/material_components_ios/src/components/Dialogs/src/MaterialDialogs.h" |
| #import "remoting/ios/app/remoting_theme.h" |
| |
| #include <algorithm> |
| |
| #include "base/check.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "remoting/base/string_resources.h" |
| #include "remoting/client/notification/notification_message.h" |
| #include "remoting/ios/app/view_utils.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| static const CGFloat kLabelInset = 20.f; |
| static const CGFloat kSwitchInset = 10.f; |
| static const CGFloat kButtonHeight = 48.f; |
| static const CGFloat kDontShowAgainFontSize = 14.f; |
| static const CGFloat kDontShowAgainViewHeightAdjustment = 10.f; |
| |
| @implementation NotificationDialogViewController { |
| NSString* _messageText; |
| NSString* _linkText; |
| NSURL* _linkUrl; |
| BOOL _allowSilence; |
| NotificationDialogCompletionBlock _completion; |
| MDCDialogTransitionController* _transitionController; |
| UILabel* _messageLabel; |
| MDCButton* _linkButton; |
| MDCButton* _dismissButton; |
| |
| // These will be nil if |_allowSilence| is NO. |
| UISwitch* _dontShowAgainSwitch; |
| UILabel* _dontShowAgainLabel; |
| } |
| |
| #pragma mark - UIViewController |
| |
| - (instancetype)initWithNotificationMessage: |
| (const remoting::NotificationMessage&)message |
| allowSilence:(BOOL)allowSilence { |
| self = [super init]; |
| if (self) { |
| _messageText = base::SysUTF8ToNSString(message.message_text); |
| _linkText = base::SysUTF8ToNSString(message.link_text); |
| _linkUrl = [NSURL URLWithString:base::SysUTF8ToNSString(message.link_url)]; |
| _allowSilence = allowSilence; |
| |
| _transitionController = [MDCDialogTransitionController new]; |
| self.modalPresentationStyle = UIModalPresentationCustom; |
| self.transitioningDelegate = _transitionController; |
| } |
| return self; |
| } |
| |
| - (void)viewDidLoad { |
| [super viewDidLoad]; |
| |
| self.view.backgroundColor = RemotingTheme.dialogBackgroundColor; |
| |
| _messageLabel = [UILabel new]; |
| _messageLabel.textColor = RemotingTheme.dialogTextColor; |
| _messageLabel.lineBreakMode = NSLineBreakByWordWrapping; |
| _messageLabel.numberOfLines = 0; |
| _messageLabel.text = _messageText; |
| _messageLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.view addSubview:_messageLabel]; |
| |
| UIView* dontShowAgainView = [UIView new]; |
| dontShowAgainView.translatesAutoresizingMaskIntoConstraints = NO; |
| [self.view addSubview:dontShowAgainView]; |
| |
| _linkButton = [MDCFlatButton new]; |
| [_linkButton setTitle:_linkText forState:UIControlStateNormal]; |
| [_linkButton addTarget:self |
| action:@selector(didTapLinkButton:) |
| forControlEvents:UIControlEventTouchUpInside]; |
| [self addButton:_linkButton isPrimary:YES]; |
| |
| _dismissButton = [MDCFlatButton new]; |
| [_dismissButton setTitle:l10n_util::GetNSString(IDS_DISMISS) |
| forState:UIControlStateNormal]; |
| [_dismissButton addTarget:self |
| action:@selector(didTapDismissButton:) |
| forControlEvents:UIControlEventTouchUpInside]; |
| [self addButton:_dismissButton isPrimary:NO]; |
| |
| [NSLayoutConstraint activateConstraints:@[ |
| [_messageLabel.topAnchor constraintEqualToAnchor:self.view.topAnchor |
| constant:kLabelInset], |
| [_messageLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor |
| constant:kLabelInset], |
| [_messageLabel.trailingAnchor |
| constraintEqualToAnchor:self.view.trailingAnchor |
| constant:-kLabelInset], |
| |
| [dontShowAgainView.topAnchor |
| constraintEqualToAnchor:_messageLabel.bottomAnchor |
| constant:kLabelInset], |
| [dontShowAgainView.leadingAnchor |
| constraintEqualToAnchor:self.view.leadingAnchor], |
| [dontShowAgainView.trailingAnchor |
| constraintEqualToAnchor:self.view.trailingAnchor], |
| |
| [_dismissButton.topAnchor |
| constraintEqualToAnchor:dontShowAgainView.bottomAnchor], |
| [_dismissButton.heightAnchor constraintEqualToConstant:kButtonHeight], |
| [_dismissButton.bottomAnchor |
| constraintEqualToAnchor:self.view.bottomAnchor], |
| [_dismissButton.leadingAnchor |
| constraintGreaterThanOrEqualToAnchor:self.view.leadingAnchor], |
| |
| [_linkButton.topAnchor constraintEqualToAnchor:_dismissButton.topAnchor], |
| [_linkButton.leadingAnchor |
| constraintEqualToAnchor:_dismissButton.trailingAnchor], |
| [_linkButton.trailingAnchor |
| constraintEqualToAnchor:self.view.trailingAnchor], |
| [_linkButton.bottomAnchor |
| constraintEqualToAnchor:_dismissButton.bottomAnchor], |
| [_linkButton.heightAnchor constraintEqualToConstant:kButtonHeight], |
| ]]; |
| |
| if (_allowSilence) { |
| // This is to allow user to toggle switch by tapping the label. Tap events |
| // won't be bubbled down to the switch. |
| UITapGestureRecognizer* dontShowAgainTapGestureRecognizer = |
| [[UITapGestureRecognizer alloc] |
| initWithTarget:self |
| action:@selector(didTapDontShowAgain:)]; |
| dontShowAgainTapGestureRecognizer.numberOfTapsRequired = 1; |
| [dontShowAgainView addGestureRecognizer:dontShowAgainTapGestureRecognizer]; |
| dontShowAgainView.userInteractionEnabled = YES; |
| |
| NSString* dontShowAgainText = l10n_util::GetNSString(IDS_DONT_SHOW_AGAIN); |
| |
| _dontShowAgainSwitch = [UISwitch new]; |
| _dontShowAgainSwitch.translatesAutoresizingMaskIntoConstraints = NO; |
| _dontShowAgainSwitch.transform = CGAffineTransformMakeScale(0.5, 0.5); |
| _dontShowAgainSwitch.accessibilityLabel = dontShowAgainText; |
| [dontShowAgainView addSubview:_dontShowAgainSwitch]; |
| |
| _dontShowAgainLabel = [UILabel new]; |
| _dontShowAgainLabel.textColor = RemotingTheme.dialogTextColor; |
| _dontShowAgainLabel.font = [UIFont systemFontOfSize:kDontShowAgainFontSize]; |
| _dontShowAgainLabel.text = dontShowAgainText; |
| _dontShowAgainLabel.translatesAutoresizingMaskIntoConstraints = NO; |
| [dontShowAgainView addSubview:_dontShowAgainLabel]; |
| |
| [NSLayoutConstraint activateConstraints:@[ |
| [dontShowAgainView.heightAnchor |
| constraintEqualToAnchor:_dontShowAgainLabel.heightAnchor |
| constant:kDontShowAgainViewHeightAdjustment], |
| |
| [_dontShowAgainSwitch.leadingAnchor |
| constraintEqualToAnchor:dontShowAgainView.leadingAnchor |
| constant:kSwitchInset], |
| [_dontShowAgainSwitch.centerYAnchor |
| constraintEqualToAnchor:dontShowAgainView.centerYAnchor], |
| |
| [_dontShowAgainLabel.leadingAnchor |
| constraintEqualToAnchor:_dontShowAgainSwitch.trailingAnchor], |
| [_dontShowAgainLabel.trailingAnchor |
| constraintEqualToAnchor:dontShowAgainView.trailingAnchor |
| constant:-kLabelInset], |
| [_dontShowAgainLabel.centerYAnchor |
| constraintEqualToAnchor:_dontShowAgainSwitch.centerYAnchor], |
| ]]; |
| } |
| |
| [self.view setNeedsLayout]; |
| } |
| |
| - (void)viewDidLayoutSubviews { |
| CGFloat contentWidth = |
| MAX(_messageLabel.intrinsicContentSize.width + 2 * kLabelInset, |
| _dismissButton.intrinsicContentSize.width + |
| _linkButton.intrinsicContentSize.width); |
| CGFloat contentHeight = _messageLabel.intrinsicContentSize.height + |
| 2 * kLabelInset + kButtonHeight; |
| if (_allowSilence) { |
| contentWidth = |
| MAX(contentWidth, |
| kSwitchInset + _dontShowAgainSwitch.intrinsicContentSize.width + |
| _dontShowAgainLabel.intrinsicContentSize.width + kLabelInset); |
| contentHeight += _dontShowAgainLabel.intrinsicContentSize.height + |
| kDontShowAgainViewHeightAdjustment; |
| } |
| self.preferredContentSize = CGSizeMake(contentWidth, contentHeight); |
| } |
| |
| - (void)presentOnTopVCWithCompletion: |
| (NotificationDialogCompletionBlock)completion { |
| DCHECK(completion); |
| DCHECK(!_completion); |
| _completion = completion; |
| [remoting::TopPresentingVC() presentViewController:self |
| animated:YES |
| completion:nil]; |
| } |
| |
| - (void)viewDidDisappear:(BOOL)animated { |
| DCHECK(_completion); |
| _completion(_dontShowAgainSwitch && _dontShowAgainSwitch.on); |
| // Release the block as long as the dialog is disappeared, since it could |
| // potentially have retain loop. |
| _completion = nil; |
| } |
| |
| #pragma mark - Private |
| |
| - (void)addButton:(UIButton*)button isPrimary:(BOOL)isPrimary { |
| button.translatesAutoresizingMaskIntoConstraints = NO; |
| button.backgroundColor = UIColor.clearColor; |
| UIColor* titleColor = isPrimary |
| ? RemotingTheme.dialogPrimaryButtonTextColor |
| : RemotingTheme.dialogSecondaryButtonTextColor; |
| [button setTitleColor:titleColor forState:UIControlStateNormal]; |
| [self.view addSubview:button]; |
| } |
| |
| - (void)didTapLinkButton:(id)button { |
| [self dismissViewControllerAnimated:YES |
| completion:^() { |
| [UIApplication.sharedApplication openURL:_linkUrl |
| options:@{} |
| completionHandler:nil]; |
| }]; |
| } |
| |
| - (void)didTapDismissButton:(id)button { |
| [self dismissViewControllerAnimated:YES completion:nil]; |
| } |
| |
| - (void)didTapDontShowAgain:(id)sender { |
| [_dontShowAgainSwitch setOn:!_dontShowAgainSwitch.isOn animated:YES]; |
| } |
| |
| @end |