OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view.h" |
| 6 |
| 7 #include "base/i18n/rtl.h" |
| 8 #import "base/ios/weak_nsobject.h" |
| 9 #include "base/logging.h" |
| 10 #import "base/mac/scoped_nsobject.h" |
| 11 #include "base/strings/sys_string_conversions.h" |
| 12 #import "ios/chrome/browser/ui/UIView+SizeClassSupport.h" |
| 13 #include "ios/chrome/browser/ui/fancy_ui/primary_action_button.h" |
| 14 #include "ios/chrome/browser/ui/first_run/first_run_util.h" |
| 15 #include "ios/chrome/browser/ui/ui_util.h" |
| 16 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 17 #import "ios/chrome/browser/ui/util/CRUILabel+AttributeUtils.h" |
| 18 #import "ios/chrome/browser/ui/util/label_link_controller.h" |
| 19 #include "ios/chrome/common/string_util.h" |
| 20 #include "ios/chrome/grit/ios_chromium_strings.h" |
| 21 #include "ios/chrome/grit/ios_strings.h" |
| 22 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoF
ontLoader.h" |
| 23 #include "ui/base/l10n/l10n_util.h" |
| 24 #include "url/gurl.h" |
| 25 |
| 26 namespace { |
| 27 |
| 28 // Accessibility identifier for the checkbox button. |
| 29 NSString* const kUMAMetricsButtonAccessibilityIdentifier = |
| 30 @"UMAMetricsButtonAccessibilityIdentifier"; |
| 31 |
| 32 // Color of "Terms of Service" link text. |
| 33 const int kLinkColorRGB = 0x5D9AFF; |
| 34 |
| 35 // The width of the container view for a REGULAR width size class. |
| 36 const CGFloat kContainerViewRegularWidth = 510.0; |
| 37 |
| 38 // The percentage of the view's width taken up by the container view for a |
| 39 // COMPACT width size class. |
| 40 const CGFloat kContainerViewCompactWidthPercentage = 0.8; |
| 41 |
| 42 // Layout constants. |
| 43 const CGFloat kImageTopPadding[SIZE_CLASS_COUNT] = {32.0, 50.0}; |
| 44 const CGFloat kTOSLabelTopPadding[SIZE_CLASS_COUNT] = {34.0, 40.0}; |
| 45 const CGFloat kOptInLabelTopPadding[SIZE_CLASS_COUNT] = {10.0, 14.0}; |
| 46 const CGFloat kCheckBoxPadding[SIZE_CLASS_COUNT] = {10.0, 16.0}; |
| 47 const CGFloat kOKButtonBottomPadding[SIZE_CLASS_COUNT] = {16.0, 24.0}; |
| 48 // Multiplier matches that used in LaunchScreen.xib to determine size of logo. |
| 49 const CGFloat kAppLogoProportionMultiplier = 0.381966; |
| 50 |
| 51 // Font sizes. |
| 52 const CGFloat kTitleLabelFontSize[SIZE_CLASS_COUNT] = {24.0, 36.0}; |
| 53 const CGFloat kTOSLabelFontSize[SIZE_CLASS_COUNT] = {14.0, 21.0}; |
| 54 const CGFloat kTOSLabelLineHeight[SIZE_CLASS_COUNT] = {20.0, 32.0}; |
| 55 const CGFloat kOptInLabelFontSize[SIZE_CLASS_COUNT] = {13.0, 19.0}; |
| 56 const CGFloat kOptInLabelLineHeight[SIZE_CLASS_COUNT] = {18.0, 26.0}; |
| 57 const CGFloat kOKButtonTitleLabelFontSize[SIZE_CLASS_COUNT] = {14.0, 20.0}; |
| 58 |
| 59 // Animation constants |
| 60 const CGFloat kAnimationDuration = .4; |
| 61 // Delay animation to avoid interaction with launch screen fadeout. |
| 62 const CGFloat kAnimationDelay = .5; |
| 63 |
| 64 // Image names. |
| 65 NSString* const kAppLogoImageName = @"launchscreen_app_logo"; |
| 66 NSString* const kCheckBoxImageName = @"checkbox"; |
| 67 NSString* const kCheckBoxCheckedImageName = @"checkbox_checked"; |
| 68 |
| 69 } // namespace |
| 70 |
| 71 @interface WelcomeToChromeView () { |
| 72 // Backing objects for properties of the same name. |
| 73 base::WeakNSProtocol<id<WelcomeToChromeViewDelegate>> _delegate; |
| 74 base::scoped_nsobject<UIView> _containerView; |
| 75 base::scoped_nsobject<UILabel> _titleLabel; |
| 76 base::scoped_nsobject<UIImageView> _imageView; |
| 77 base::scoped_nsobject<UILabel> _TOSLabel; |
| 78 base::scoped_nsobject<LabelLinkController> _TOSLabelLinkController; |
| 79 base::scoped_nsobject<UIButton> _checkBoxButton; |
| 80 base::scoped_nsobject<UILabel> _optInLabel; |
| 81 base::scoped_nsobject<PrimaryActionButton> _OKButton; |
| 82 } |
| 83 |
| 84 // Subview properties are lazily instantiated upon their first use. |
| 85 |
| 86 // A container view used to layout and center subviews. |
| 87 @property(nonatomic, readonly) UIView* containerView; |
| 88 // The "Welcome to Chrome" label that appears at the top of the view. |
| 89 @property(nonatomic, readonly) UILabel* titleLabel; |
| 90 // The Chrome logo image view. |
| 91 @property(nonatomic, readonly) UIImageView* imageView; |
| 92 // The "Terms of Service" label. |
| 93 @property(nonatomic, readonly) UILabel* TOSLabel; |
| 94 // The stats reporting opt-in label. |
| 95 @property(nonatomic, readonly) UILabel* optInLabel; |
| 96 // The stats reporting opt-in checkbox button. |
| 97 @property(nonatomic, readonly) UIButton* checkBoxButton; |
| 98 // The "Accept & Continue" button. |
| 99 @property(nonatomic, readonly) PrimaryActionButton* OKButton; |
| 100 |
| 101 // Subview layout methods. They must be called in the order declared here, as |
| 102 // subsequent subview layouts depend on the layouts that precede them. |
| 103 - (void)layoutTitleLabel; |
| 104 - (void)layoutImageView; |
| 105 - (void)layoutTOSLabel; |
| 106 - (void)layoutOptInLabel; |
| 107 - (void)layoutCheckBoxButton; |
| 108 - (void)layoutContainerView; |
| 109 - (void)layoutOKButton; |
| 110 |
| 111 // Calls the subview configuration selectors below. |
| 112 - (void)configureSubviews; |
| 113 |
| 114 // Subview configuration methods. |
| 115 - (void)configureTitleLabel; |
| 116 - (void)configureImageView; |
| 117 - (void)configureTOSLabel; |
| 118 - (void)configureOptInLabel; |
| 119 - (void)configureContainerView; |
| 120 - (void)configureOKButton; |
| 121 |
| 122 // Action triggered by the check box button. |
| 123 - (void)checkBoxButtonWasTapped; |
| 124 |
| 125 // Action triggered by the ok button. |
| 126 - (void)OKButtonWasTapped; |
| 127 |
| 128 // The TOS label button was tapped. |
| 129 // TODO(crbug.com/539961): Remove once link detection is fixed. |
| 130 - (void)TOSLinkWasTapped; |
| 131 |
| 132 @end |
| 133 |
| 134 @implementation WelcomeToChromeView |
| 135 |
| 136 - (instancetype)initWithFrame:(CGRect)frame { |
| 137 self = [super initWithFrame:frame]; |
| 138 if (self) { |
| 139 self.backgroundColor = [UIColor whiteColor]; |
| 140 self.autoresizingMask = |
| 141 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; |
| 142 } |
| 143 return self; |
| 144 } |
| 145 |
| 146 - (void)runLaunchAnimation { |
| 147 // Prepare for animation by making views (except for the logo) transparent |
| 148 // and finding the initial and final location of the logo. |
| 149 self.titleLabel.alpha = 0.0; |
| 150 self.TOSLabel.alpha = 0.0; |
| 151 self.optInLabel.alpha = 0.0; |
| 152 self.checkBoxButton.alpha = 0.0; |
| 153 self.OKButton.alpha = 0.0; |
| 154 |
| 155 // Get final location of logo based on result from previously run |
| 156 // layoutSubviews. |
| 157 CGRect finalLogoFrame = self.imageView.frame; |
| 158 // Ensure that frame position is valid and that layoutSubviews ran |
| 159 // before this method. |
| 160 DCHECK(finalLogoFrame.origin.x >= 0 && finalLogoFrame.origin.y >= 0); |
| 161 self.imageView.center = CGPointMake(CGRectGetMidX(self.containerView.bounds), |
| 162 CGRectGetMidY(self.containerView.bounds)); |
| 163 |
| 164 base::WeakNSObject<WelcomeToChromeView> weakSelf(self); |
| 165 [UIView animateWithDuration:kAnimationDuration |
| 166 delay:kAnimationDelay |
| 167 options:UIViewAnimationCurveEaseInOut |
| 168 animations:^{ |
| 169 [weakSelf imageView].frame = finalLogoFrame; |
| 170 [weakSelf titleLabel].alpha = 1.0; |
| 171 [weakSelf TOSLabel].alpha = 1.0; |
| 172 [weakSelf optInLabel].alpha = 1.0; |
| 173 [weakSelf checkBoxButton].alpha = 1.0; |
| 174 [weakSelf OKButton].alpha = 1.0; |
| 175 } |
| 176 completion:nil]; |
| 177 } |
| 178 |
| 179 #pragma mark - Accessors |
| 180 |
| 181 - (id<WelcomeToChromeViewDelegate>)delegate { |
| 182 return _delegate; |
| 183 } |
| 184 |
| 185 - (void)setDelegate:(id<WelcomeToChromeViewDelegate>)delegate { |
| 186 _delegate.reset(delegate); |
| 187 } |
| 188 |
| 189 - (BOOL)isCheckBoxSelected { |
| 190 return self.checkBoxButton.selected; |
| 191 } |
| 192 |
| 193 - (void)setCheckBoxSelected:(BOOL)checkBoxSelected { |
| 194 if (checkBoxSelected != self.checkBoxButton.selected) |
| 195 [self checkBoxButtonWasTapped]; |
| 196 } |
| 197 |
| 198 - (UIView*)containerView { |
| 199 if (!_containerView) { |
| 200 _containerView.reset([[UIView alloc] initWithFrame:CGRectZero]); |
| 201 [_containerView setBackgroundColor:[UIColor whiteColor]]; |
| 202 } |
| 203 return _containerView.get(); |
| 204 } |
| 205 |
| 206 - (UILabel*)titleLabel { |
| 207 if (!_titleLabel) { |
| 208 _titleLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); |
| 209 [_titleLabel setBackgroundColor:[UIColor whiteColor]]; |
| 210 [_titleLabel setNumberOfLines:0]; |
| 211 [_titleLabel setLineBreakMode:NSLineBreakByWordWrapping]; |
| 212 [_titleLabel setBaselineAdjustment:UIBaselineAdjustmentAlignBaselines]; |
| 213 [_titleLabel |
| 214 setText:l10n_util::GetNSString(IDS_IOS_FIRSTRUN_WELCOME_TO_CHROME)]; |
| 215 } |
| 216 return _titleLabel.get(); |
| 217 } |
| 218 |
| 219 - (UIImageView*)imageView { |
| 220 if (!_imageView) { |
| 221 UIImage* image = [UIImage imageNamed:kAppLogoImageName]; |
| 222 _imageView.reset([[UIImageView alloc] initWithImage:image]); |
| 223 [_imageView setBackgroundColor:[UIColor whiteColor]]; |
| 224 } |
| 225 return _imageView.get(); |
| 226 } |
| 227 |
| 228 - (UILabel*)TOSLabel { |
| 229 if (!_TOSLabel) { |
| 230 _TOSLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); |
| 231 [_TOSLabel setNumberOfLines:0]; |
| 232 [_TOSLabel setTextAlignment:NSTextAlignmentCenter]; |
| 233 } |
| 234 return _TOSLabel.get(); |
| 235 } |
| 236 |
| 237 - (UILabel*)optInLabel { |
| 238 if (!_optInLabel) { |
| 239 _optInLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); |
| 240 [_optInLabel setNumberOfLines:0]; |
| 241 [_optInLabel |
| 242 setText:l10n_util::GetNSString(IDS_IOS_FIRSTRUN_NEW_OPT_IN_LABEL)]; |
| 243 [_optInLabel setTextAlignment:NSTextAlignmentNatural]; |
| 244 } |
| 245 return _optInLabel.get(); |
| 246 } |
| 247 |
| 248 - (UIButton*)checkBoxButton { |
| 249 if (!_checkBoxButton) { |
| 250 _checkBoxButton.reset([[UIButton alloc] initWithFrame:CGRectZero]); |
| 251 [_checkBoxButton setBackgroundColor:[UIColor clearColor]]; |
| 252 [_checkBoxButton addTarget:self |
| 253 action:@selector(checkBoxButtonWasTapped) |
| 254 forControlEvents:UIControlEventTouchUpInside]; |
| 255 SetA11yLabelAndUiAutomationName(_checkBoxButton, |
| 256 IDS_IOS_FIRSTRUN_NEW_OPT_IN_LABEL, |
| 257 kUMAMetricsButtonAccessibilityIdentifier); |
| 258 [_checkBoxButton |
| 259 setAccessibilityValue:l10n_util::GetNSString(IDS_IOS_SETTING_OFF)]; |
| 260 [_checkBoxButton setImage:[UIImage imageNamed:kCheckBoxImageName] |
| 261 forState:UIControlStateNormal]; |
| 262 [_checkBoxButton setImage:[UIImage imageNamed:kCheckBoxCheckedImageName] |
| 263 forState:UIControlStateSelected]; |
| 264 } |
| 265 return _checkBoxButton.get(); |
| 266 } |
| 267 |
| 268 - (PrimaryActionButton*)OKButton { |
| 269 if (!_OKButton) { |
| 270 _OKButton.reset([[PrimaryActionButton alloc] initWithFrame:CGRectZero]); |
| 271 [_OKButton addTarget:self |
| 272 action:@selector(OKButtonWasTapped) |
| 273 forControlEvents:UIControlEventTouchUpInside]; |
| 274 NSString* acceptAndContinue = |
| 275 l10n_util::GetNSString(IDS_IOS_FIRSTRUN_OPT_IN_ACCEPT_BUTTON); |
| 276 [_OKButton setTitle:acceptAndContinue forState:UIControlStateNormal]; |
| 277 [_OKButton setTitle:acceptAndContinue forState:UIControlStateHighlighted]; |
| 278 // UIAutomation tests look for the Accept button to skip through the |
| 279 // First Run UI when it shows up. |
| 280 SetA11yLabelAndUiAutomationName( |
| 281 _OKButton, IDS_IOS_FIRSTRUN_OPT_IN_ACCEPT_BUTTON, @"Accept & Continue"); |
| 282 } |
| 283 return _OKButton.get(); |
| 284 } |
| 285 |
| 286 #pragma mark - Layout |
| 287 |
| 288 - (void)willMoveToSuperview:(nullable UIView*)newSuperview { |
| 289 [super willMoveToSuperview:newSuperview]; |
| 290 |
| 291 // Early return if the view hierarchy is already built. |
| 292 if (self.containerView.superview) { |
| 293 DCHECK_EQ(self, self.containerView.superview); |
| 294 return; |
| 295 } |
| 296 |
| 297 [self addSubview:self.containerView]; |
| 298 [self.containerView addSubview:self.titleLabel]; |
| 299 [self.containerView addSubview:self.imageView]; |
| 300 [self.containerView addSubview:self.TOSLabel]; |
| 301 [self.containerView addSubview:self.optInLabel]; |
| 302 [self.containerView addSubview:self.checkBoxButton]; |
| 303 [self addSubview:self.OKButton]; |
| 304 [self configureSubviews]; |
| 305 } |
| 306 |
| 307 - (void)layoutSubviews { |
| 308 [super layoutSubviews]; |
| 309 [self layoutTitleLabel]; |
| 310 [self layoutImageView]; |
| 311 [self layoutTOSLabel]; |
| 312 [self layoutOptInLabel]; |
| 313 [self layoutCheckBoxButton]; |
| 314 [self layoutContainerView]; |
| 315 [self layoutOKButton]; |
| 316 } |
| 317 |
| 318 - (void)layoutTitleLabel { |
| 319 // The label is centered and top-aligned with the container view. |
| 320 CGSize containerSize = self.containerView.bounds.size; |
| 321 containerSize.height = CGFLOAT_MAX; |
| 322 CGSize titleLabelSize = [self.titleLabel sizeThatFits:containerSize]; |
| 323 self.titleLabel.frame = AlignRectOriginAndSizeToPixels( |
| 324 CGRectMake((containerSize.width - titleLabelSize.width) / 2.0, 0.0, |
| 325 titleLabelSize.width, titleLabelSize.height)); |
| 326 } |
| 327 |
| 328 - (void)layoutImageView { |
| 329 // The image is centered and laid out below |titleLabel| as specified by |
| 330 // kImageTopPadding. |
| 331 CGSize imageViewSize = self.imageView.bounds.size; |
| 332 CGFloat imageViewTopPadding = kImageTopPadding[self.cr_heightSizeClass]; |
| 333 self.imageView.frame = AlignRectOriginAndSizeToPixels(CGRectMake( |
| 334 (CGRectGetWidth(self.containerView.bounds) - imageViewSize.width) / 2.0, |
| 335 CGRectGetMaxY(self.titleLabel.frame) + imageViewTopPadding, |
| 336 imageViewSize.width, imageViewSize.height)); |
| 337 } |
| 338 |
| 339 - (void)layoutTOSLabel { |
| 340 // The TOS label is centered and laid out below |imageView| as specified by |
| 341 // kTOSLabelTopPadding. |
| 342 CGSize containerSize = self.containerView.bounds.size; |
| 343 containerSize.height = CGFLOAT_MAX; |
| 344 self.TOSLabel.frame = {CGPointZero, containerSize}; |
| 345 NSString* TOSText = l10n_util::GetNSString(IDS_IOS_FIRSTRUN_AGREE_TO_TERMS); |
| 346 NSRange linkTextRange = NSMakeRange(NSNotFound, 0); |
| 347 NSString* strippedText = ParseStringWithLink(TOSText, &linkTextRange); |
| 348 DCHECK_NE(NSNotFound, static_cast<NSInteger>(linkTextRange.location)); |
| 349 DCHECK_NE(0u, linkTextRange.length); |
| 350 |
| 351 self.TOSLabel.text = strippedText; |
| 352 if (ios_internal::FixOrphanWord(self.TOSLabel)) { |
| 353 // If a newline is inserted, check whether it was added mid-link and adjust |
| 354 // |linkTextRange| accordingly. |
| 355 NSRange newlineRange = |
| 356 [self.TOSLabel.text rangeOfString:@"\n" options:0 range:linkTextRange]; |
| 357 if (newlineRange.length) |
| 358 linkTextRange.length++; |
| 359 } |
| 360 |
| 361 base::WeakNSObject<WelcomeToChromeView> weakSelf(self); |
| 362 ProceduralBlockWithURL action = ^(const GURL& url) { |
| 363 base::scoped_nsobject<WelcomeToChromeView> strongSelf([weakSelf retain]); |
| 364 if (!strongSelf) |
| 365 return; |
| 366 [[strongSelf delegate] welcomeToChromeViewDidTapTOSLink:strongSelf]; |
| 367 }; |
| 368 |
| 369 _TOSLabelLinkController.reset( |
| 370 [[LabelLinkController alloc] initWithLabel:_TOSLabel action:action]); |
| 371 [_TOSLabelLinkController |
| 372 addLinkWithRange:linkTextRange |
| 373 url:GURL("internal://terms-of-service")]; |
| 374 [_TOSLabelLinkController setLinkColor:UIColorFromRGB(kLinkColorRGB)]; |
| 375 |
| 376 CGSize TOSLabelSize = [self.TOSLabel sizeThatFits:containerSize]; |
| 377 CGFloat TOSLabelTopPadding = kTOSLabelTopPadding[self.cr_heightSizeClass]; |
| 378 self.TOSLabel.frame = AlignRectOriginAndSizeToPixels( |
| 379 CGRectMake((containerSize.width - TOSLabelSize.width) / 2.0, |
| 380 CGRectGetMaxY(self.imageView.frame) + TOSLabelTopPadding, |
| 381 TOSLabelSize.width, TOSLabelSize.height)); |
| 382 } |
| 383 |
| 384 - (void)layoutOptInLabel { |
| 385 // The opt in label is laid out to the right (or left in RTL) of the check box |
| 386 // button and below |TOSLabel| as specified by kOptInLabelTopPadding. |
| 387 CGSize checkBoxSize = |
| 388 [self.checkBoxButton imageForState:self.checkBoxButton.state].size; |
| 389 CGFloat checkBoxPadding = kCheckBoxPadding[self.cr_widthSizeClass]; |
| 390 CGFloat optInLabelSidePadding = checkBoxSize.width + 2.0 * checkBoxPadding; |
| 391 CGSize optInLabelSize = [self.optInLabel |
| 392 sizeThatFits:CGSizeMake(CGRectGetWidth(self.containerView.bounds) - |
| 393 optInLabelSidePadding, |
| 394 CGFLOAT_MAX)]; |
| 395 CGFloat optInLabelTopPadding = kOptInLabelTopPadding[self.cr_heightSizeClass]; |
| 396 CGFloat optInLabelOriginX = |
| 397 base::i18n::IsRTL() ? 0.0f : optInLabelSidePadding; |
| 398 self.optInLabel.frame = AlignRectOriginAndSizeToPixels( |
| 399 CGRectMake(optInLabelOriginX, |
| 400 CGRectGetMaxY(self.TOSLabel.frame) + optInLabelTopPadding, |
| 401 optInLabelSize.width, optInLabelSize.height)); |
| 402 ios_internal::FixOrphanWord(self.optInLabel); |
| 403 } |
| 404 |
| 405 - (void)layoutCheckBoxButton { |
| 406 // The checkBoxButton is laid out to the left of |optInLabel|. The view |
| 407 // itself is sized so that it covers the label, and the image insets are |
| 408 // chosen such that the check box image is centered vertically with |
| 409 // |optInLabel|. |
| 410 CGSize checkBoxSize = |
| 411 [self.checkBoxButton imageForState:self.checkBoxButton.state].size; |
| 412 CGFloat checkBoxPadding = kCheckBoxPadding[self.cr_widthSizeClass]; |
| 413 CGSize checkBoxButtonSize = |
| 414 CGSizeMake(CGRectGetWidth(self.optInLabel.frame) + checkBoxSize.width + |
| 415 2.0 * checkBoxPadding, |
| 416 std::max(CGRectGetHeight(self.optInLabel.frame), |
| 417 checkBoxSize.height + 2.0f * checkBoxPadding)); |
| 418 self.checkBoxButton.frame = AlignRectOriginAndSizeToPixels(CGRectMake( |
| 419 0.0f, |
| 420 CGRectGetMidY(self.optInLabel.frame) - checkBoxButtonSize.height / 2.0, |
| 421 checkBoxButtonSize.width, checkBoxButtonSize.height)); |
| 422 CGFloat largeHorizontalInset = |
| 423 checkBoxButtonSize.width - checkBoxSize.width - checkBoxPadding; |
| 424 CGFloat smallHorizontalInset = checkBoxPadding; |
| 425 self.checkBoxButton.imageEdgeInsets = UIEdgeInsetsMake( |
| 426 (checkBoxButtonSize.height - checkBoxSize.height) / 2.0, |
| 427 base::i18n::IsRTL() ? largeHorizontalInset : smallHorizontalInset, |
| 428 (checkBoxButtonSize.height - checkBoxSize.height) / 2.0, |
| 429 base::i18n::IsRTL() ? smallHorizontalInset : largeHorizontalInset); |
| 430 } |
| 431 |
| 432 - (void)layoutContainerView { |
| 433 // The container view is resized according to the final layout of |
| 434 // |checkBoxButton|, which is its lowest subview. The resized view is then |
| 435 // centered horizontally and vertically. |
| 436 CGSize containerViewSize = self.containerView.bounds.size; |
| 437 containerViewSize.height = CGRectGetMaxY(self.checkBoxButton.frame); |
| 438 self.containerView.frame = AlignRectOriginAndSizeToPixels(CGRectMake( |
| 439 (CGRectGetWidth(self.bounds) - containerViewSize.width) / 2.0, |
| 440 (CGRectGetHeight(self.bounds) - containerViewSize.height) / 2.0, |
| 441 containerViewSize.width, CGRectGetMaxY(self.checkBoxButton.frame))); |
| 442 } |
| 443 |
| 444 - (void)layoutOKButton { |
| 445 // The OK button is laid out at the bottom of the view as specified by |
| 446 // kOKButtonBottomPadding. |
| 447 CGFloat OKButtonBottomPadding = |
| 448 kOKButtonBottomPadding[self.cr_widthSizeClass]; |
| 449 CGSize OKButtonSize = self.OKButton.bounds.size; |
| 450 self.OKButton.frame = AlignRectOriginAndSizeToPixels(CGRectMake( |
| 451 (CGRectGetWidth(self.bounds) - OKButtonSize.width) / 2.0, |
| 452 CGRectGetMaxY(self.bounds) - OKButtonSize.height - OKButtonBottomPadding, |
| 453 OKButtonSize.width, OKButtonSize.height)); |
| 454 } |
| 455 |
| 456 - (void)traitCollectionDidChange: |
| 457 (nullable UITraitCollection*)previousTraitCollection { |
| 458 [super traitCollectionDidChange:previousTraitCollection]; |
| 459 [self configureSubviews]; |
| 460 } |
| 461 |
| 462 - (void)configureSubviews { |
| 463 [self configureContainerView]; |
| 464 [self configureTitleLabel]; |
| 465 [self configureImageView]; |
| 466 [self configureTOSLabel]; |
| 467 [self configureOptInLabel]; |
| 468 [self configureOKButton]; |
| 469 [self setNeedsLayout]; |
| 470 } |
| 471 |
| 472 - (void)configureTitleLabel { |
| 473 self.titleLabel.font = [[MDFRobotoFontLoader sharedInstance] |
| 474 regularFontOfSize:kTitleLabelFontSize[self.cr_widthSizeClass]]; |
| 475 } |
| 476 |
| 477 - (void)configureImageView { |
| 478 CGFloat sideLength = self.imageView.image.size.width; |
| 479 if (self.cr_widthSizeClass == COMPACT) { |
| 480 sideLength = self.bounds.size.width * kAppLogoProportionMultiplier; |
| 481 } else if (self.cr_heightSizeClass == COMPACT) { |
| 482 sideLength = self.bounds.size.height * kAppLogoProportionMultiplier; |
| 483 } |
| 484 self.imageView.bounds = AlignRectOriginAndSizeToPixels( |
| 485 CGRectMake(self.imageView.bounds.origin.x, self.imageView.bounds.origin.y, |
| 486 sideLength, sideLength)); |
| 487 } |
| 488 |
| 489 - (void)configureTOSLabel { |
| 490 self.TOSLabel.font = [[MDFRobotoFontLoader sharedInstance] |
| 491 regularFontOfSize:kTOSLabelFontSize[self.cr_widthSizeClass]]; |
| 492 self.TOSLabel.cr_lineHeight = kTOSLabelLineHeight[self.cr_widthSizeClass]; |
| 493 } |
| 494 |
| 495 - (void)configureOptInLabel { |
| 496 self.optInLabel.font = [[MDFRobotoFontLoader sharedInstance] |
| 497 regularFontOfSize:kOptInLabelFontSize[self.cr_widthSizeClass]]; |
| 498 self.optInLabel.cr_lineHeight = kOptInLabelLineHeight[self.cr_widthSizeClass]; |
| 499 } |
| 500 |
| 501 - (void)configureContainerView { |
| 502 CGFloat containerViewWidth = |
| 503 self.cr_widthSizeClass == COMPACT |
| 504 ? kContainerViewCompactWidthPercentage * CGRectGetWidth(self.bounds) |
| 505 : kContainerViewRegularWidth; |
| 506 self.containerView.frame = |
| 507 CGRectMake(0.0, 0.0, containerViewWidth, CGFLOAT_MAX); |
| 508 } |
| 509 |
| 510 - (void)configureOKButton { |
| 511 self.OKButton.titleLabel.font = [[MDFRobotoFontLoader sharedInstance] |
| 512 mediumFontOfSize:kOKButtonTitleLabelFontSize[self.cr_widthSizeClass]]; |
| 513 [self.OKButton sizeToFit]; |
| 514 } |
| 515 |
| 516 #pragma mark - |
| 517 |
| 518 - (void)checkBoxButtonWasTapped { |
| 519 self.checkBoxButton.selected = !self.checkBoxButton.selected; |
| 520 self.checkBoxButton.accessibilityValue = |
| 521 self.checkBoxButton.selected |
| 522 ? l10n_util::GetNSString(IDS_IOS_SETTING_ON) |
| 523 : l10n_util::GetNSString(IDS_IOS_SETTING_OFF); |
| 524 } |
| 525 |
| 526 - (void)OKButtonWasTapped { |
| 527 [self.delegate welcomeToChromeViewDidTapOKButton:self]; |
| 528 } |
| 529 |
| 530 - (void)TOSLinkWasTapped { |
| 531 [self.delegate welcomeToChromeViewDidTapTOSLink:self]; |
| 532 } |
| 533 |
| 534 @end |
OLD | NEW |