| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/browser/passwords/password_generation_prompt_view.h" | 5 #import "ios/chrome/browser/passwords/password_generation_prompt_view.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/ios/weak_nsobject.h" | |
| 10 #include "base/mac/scoped_nsobject.h" | |
| 11 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
| 12 #include "components/strings/grit/components_strings.h" | 10 #include "components/strings/grit/components_strings.h" |
| 13 #import "ios/chrome/browser/passwords/password_generation_prompt_delegate.h" | 11 #import "ios/chrome/browser/passwords/password_generation_prompt_delegate.h" |
| 14 #import "ios/chrome/browser/ui/rtl_geometry.h" | 12 #import "ios/chrome/browser/ui/rtl_geometry.h" |
| 15 #include "ios/chrome/browser/ui/ui_util.h" | 13 #include "ios/chrome/browser/ui/ui_util.h" |
| 16 #import "ios/chrome/browser/ui/uikit_ui_util.h" | 14 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 17 #include "ios/chrome/common/string_util.h" | 15 #include "ios/chrome/common/string_util.h" |
| 18 #include "ios/chrome/grit/ios_strings.h" | 16 #include "ios/chrome/grit/ios_strings.h" |
| 19 #include "ios/chrome/grit/ios_theme_resources.h" | 17 #include "ios/chrome/grit/ios_theme_resources.h" |
| 20 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate
rialButtons.h" | 18 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate
rialButtons.h" |
| 21 #import "ios/third_party/material_components_ios/src/components/Typography/src/M
aterialTypography.h" | 19 #import "ios/third_party/material_components_ios/src/components/Typography/src/M
aterialTypography.h" |
| 22 #include "ui/base/l10n/l10n_util.h" | 20 #include "ui/base/l10n/l10n_util.h" |
| 23 #include "ui/base/resource/resource_bundle.h" | 21 #include "ui/base/resource/resource_bundle.h" |
| 24 | 22 |
| 23 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 24 #error "This file requires ARC support." |
| 25 #endif |
| 26 |
| 25 namespace { | 27 namespace { |
| 26 | 28 |
| 27 // Material Design Component constraints. | 29 // Material Design Component constraints. |
| 28 const CGFloat kMDCPadding = 24; | 30 const CGFloat kMDCPadding = 24; |
| 29 | 31 |
| 30 // Horizontal and vertical padding for the entire view. | 32 // Horizontal and vertical padding for the entire view. |
| 31 const CGFloat kPadding = 8.0f; | 33 const CGFloat kPadding = 8.0f; |
| 32 | 34 |
| 33 // Colors for primary and secondary user interactions. | 35 // Colors for primary and secondary user interactions. |
| 34 const int kPrimaryActionColor = 0x5595FE; | 36 const int kPrimaryActionColor = 0x5595FE; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 | 79 |
| 78 // Returns an autoreleased text view to explain password generation with a link. | 80 // Returns an autoreleased text view to explain password generation with a link. |
| 79 - (UITextView*)description; | 81 - (UITextView*)description; |
| 80 | 82 |
| 81 // Returns an autoreleased view that shows the lock icon. | 83 // Returns an autoreleased view that shows the lock icon. |
| 82 - (UIImageView*)keyIconView; | 84 - (UIImageView*)keyIconView; |
| 83 | 85 |
| 84 @end | 86 @end |
| 85 | 87 |
| 86 @implementation PasswordGenerationPromptView { | 88 @implementation PasswordGenerationPromptView { |
| 87 base::scoped_nsobject<NSString> _password; | 89 NSString* _password; |
| 88 base::WeakNSProtocol<id<PasswordGenerationPromptDelegate>> _delegate; | 90 __weak id<PasswordGenerationPromptDelegate> _delegate; |
| 89 base::scoped_nsobject<NSURL> _URL; | 91 NSURL* _URL; |
| 90 base::scoped_nsobject<UILabel> _title; | 92 UILabel* _title; |
| 91 } | 93 } |
| 92 | 94 |
| 93 - (instancetype)initWithPassword:(NSString*)password | 95 - (instancetype)initWithPassword:(NSString*)password |
| 94 delegate: | 96 delegate: |
| 95 (id<PasswordGenerationPromptDelegate>)delegate { | 97 (id<PasswordGenerationPromptDelegate>)delegate { |
| 96 self = [super initWithFrame:CGRectZero]; | 98 self = [super initWithFrame:CGRectZero]; |
| 97 if (self) { | 99 if (self) { |
| 98 _URL.reset( | 100 _URL = [NSURL URLWithString:@"chromeinternal://showpasswords"]; |
| 99 [[NSURL URLWithString:@"chromeinternal://showpasswords"] retain]); | 101 _delegate = delegate; |
| 100 _delegate.reset(delegate); | 102 _password = [password copy]; |
| 101 _password.reset([password copy]); | |
| 102 } | 103 } |
| 103 return self; | 104 return self; |
| 104 } | 105 } |
| 105 | 106 |
| 106 - (void)configure { | 107 - (void)configure { |
| 107 UIView* headerView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease]; | 108 UIView* headerView = [[UIView alloc] initWithFrame:CGRectZero]; |
| 108 UIImageView* icon = [self keyIconView]; | 109 UIImageView* icon = [self keyIconView]; |
| 109 UILabel* title = [self titleLabel]; | 110 UILabel* title = [self titleLabel]; |
| 110 UILabel* password = [self passwordLabel:_password]; | 111 UILabel* password = [self passwordLabel:_password]; |
| 111 UITextView* description = [self description]; | 112 UITextView* description = [self description]; |
| 112 | 113 |
| 113 _title.reset([title retain]); | 114 _title = title; |
| 114 | 115 |
| 115 [headerView addSubview:icon]; | 116 [headerView addSubview:icon]; |
| 116 [headerView addSubview:title]; | 117 [headerView addSubview:title]; |
| 117 [headerView addSubview:password]; | 118 [headerView addSubview:password]; |
| 118 [self addSubview:headerView]; | 119 [self addSubview:headerView]; |
| 119 [self addSubview:description]; | 120 [self addSubview:description]; |
| 120 | 121 |
| 121 // ----------------------------------------------- | 122 // ----------------------------------------------- |
| 122 // | | | 123 // | | |
| 123 // | (lock) Use password generated by Chrome? | | 124 // | (lock) Use password generated by Chrome? | |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 } | 184 } |
| 184 | 185 |
| 185 - (UILabel*)titleLabel { | 186 - (UILabel*)titleLabel { |
| 186 NSMutableDictionary* attrsDictionary = [NSMutableDictionary | 187 NSMutableDictionary* attrsDictionary = [NSMutableDictionary |
| 187 dictionaryWithObject:[[MDCTypography fontLoader] | 188 dictionaryWithObject:[[MDCTypography fontLoader] |
| 188 mediumFontOfSize:kTitleLabelFontSize] | 189 mediumFontOfSize:kTitleLabelFontSize] |
| 189 forKey:NSFontAttributeName]; | 190 forKey:NSFontAttributeName]; |
| 190 [attrsDictionary setObject:UIColorFromRGB(kTitleLabelFontColor) | 191 [attrsDictionary setObject:UIColorFromRGB(kTitleLabelFontColor) |
| 191 forKey:NSForegroundColorAttributeName]; | 192 forKey:NSForegroundColorAttributeName]; |
| 192 | 193 |
| 193 NSMutableAttributedString* string = [[[NSMutableAttributedString alloc] | 194 NSMutableAttributedString* string = [[NSMutableAttributedString alloc] |
| 194 initWithString:l10n_util::GetNSString( | 195 initWithString:l10n_util::GetNSString( |
| 195 IDS_IOS_GENERATED_PASSWORD_PROMPT_TITLE) | 196 IDS_IOS_GENERATED_PASSWORD_PROMPT_TITLE) |
| 196 attributes:attrsDictionary] autorelease]; | 197 attributes:attrsDictionary]; |
| 197 | 198 |
| 198 base::scoped_nsobject<UILabel> titleLabel([[UILabel alloc] init]); | 199 UILabel* titleLabel = [[UILabel alloc] init]; |
| 199 [titleLabel setAttributedText:string]; | 200 [titleLabel setAttributedText:string]; |
| 200 [titleLabel setNumberOfLines:0]; | 201 [titleLabel setNumberOfLines:0]; |
| 201 [titleLabel sizeToFit]; | 202 [titleLabel sizeToFit]; |
| 202 return titleLabel.autorelease(); | 203 return titleLabel = nil; |
| 203 } | 204 } |
| 204 | 205 |
| 205 - (UILabel*)passwordLabel:(NSString*)password { | 206 - (UILabel*)passwordLabel:(NSString*)password { |
| 206 base::scoped_nsobject<UILabel> passwordLabel([[UILabel alloc] init]); | 207 UILabel* passwordLabel = [[UILabel alloc] init]; |
| 207 [passwordLabel setText:password]; | 208 [passwordLabel setText:password]; |
| 208 [passwordLabel setTextColor:UIColorFromRGB(kPasswordLabelFontColor)]; | 209 [passwordLabel setTextColor:UIColorFromRGB(kPasswordLabelFontColor)]; |
| 209 [passwordLabel setFont:[[MDCTypography fontLoader] | 210 [passwordLabel setFont:[[MDCTypography fontLoader] |
| 210 regularFontOfSize:kPasswordLabelFontSize]]; | 211 regularFontOfSize:kPasswordLabelFontSize]]; |
| 211 [passwordLabel setNumberOfLines:1]; | 212 [passwordLabel setNumberOfLines:1]; |
| 212 [passwordLabel sizeToFit]; | 213 [passwordLabel sizeToFit]; |
| 213 return passwordLabel.autorelease(); | 214 return passwordLabel = nil; |
| 214 } | 215 } |
| 215 | 216 |
| 216 - (UITextView*)description { | 217 - (UITextView*)description { |
| 217 NSRange linkRange; | 218 NSRange linkRange; |
| 218 NSString* description = ParseStringWithLink( | 219 NSString* description = ParseStringWithLink( |
| 219 l10n_util::GetNSString(IDS_IOS_GENERATED_PASSWORD_PROMPT_DESCRIPTION), | 220 l10n_util::GetNSString(IDS_IOS_GENERATED_PASSWORD_PROMPT_DESCRIPTION), |
| 220 &linkRange); | 221 &linkRange); |
| 221 | 222 |
| 222 base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( | 223 NSMutableParagraphStyle* paragraphStyle = |
| 223 [[NSMutableParagraphStyle alloc] init]); | 224 [[NSMutableParagraphStyle alloc] init]; |
| 224 [paragraphStyle setLineSpacing:kDescriptionLabelLineSpacing]; | 225 [paragraphStyle setLineSpacing:kDescriptionLabelLineSpacing]; |
| 225 | 226 |
| 226 NSDictionary* attributeDictionary = | 227 NSDictionary* attributeDictionary = |
| 227 [NSDictionary dictionaryWithObjectsAndKeys: | 228 [NSDictionary dictionaryWithObjectsAndKeys: |
| 228 UIColorFromRGB(kDescriptionLabelFontColor), | 229 UIColorFromRGB(kDescriptionLabelFontColor), |
| 229 NSForegroundColorAttributeName, paragraphStyle.get(), | 230 NSForegroundColorAttributeName, paragraphStyle, |
| 230 NSParagraphStyleAttributeName, | 231 NSParagraphStyleAttributeName, |
| 231 [[MDCTypography fontLoader] | 232 [[MDCTypography fontLoader] |
| 232 regularFontOfSize:kDescriptionLabelFontSize], | 233 regularFontOfSize:kDescriptionLabelFontSize], |
| 233 NSFontAttributeName, nil]; | 234 NSFontAttributeName, nil]; |
| 234 | 235 |
| 235 base::scoped_nsobject<NSMutableAttributedString> attributedString( | 236 NSMutableAttributedString* attributedString = |
| 236 [[NSMutableAttributedString alloc] initWithString:description | 237 [[NSMutableAttributedString alloc] initWithString:description |
| 237 attributes:attributeDictionary]); | 238 attributes:attributeDictionary]; |
| 238 | 239 |
| 239 UITextView* descriptionView = | 240 UITextView* descriptionView = |
| 240 [[[UITextView alloc] initWithFrame:CGRectZero textContainer:nil] | 241 [[UITextView alloc] initWithFrame:CGRectZero textContainer:nil]; |
| 241 autorelease]; | |
| 242 descriptionView.scrollEnabled = NO; | 242 descriptionView.scrollEnabled = NO; |
| 243 descriptionView.selectable = YES; | 243 descriptionView.selectable = YES; |
| 244 descriptionView.editable = NO; | 244 descriptionView.editable = NO; |
| 245 descriptionView.delegate = self; | 245 descriptionView.delegate = self; |
| 246 descriptionView.userInteractionEnabled = YES; | 246 descriptionView.userInteractionEnabled = YES; |
| 247 | 247 |
| 248 descriptionView.linkTextAttributes = | 248 descriptionView.linkTextAttributes = |
| 249 [NSDictionary dictionaryWithObject:UIColorFromRGB(kPrimaryActionColor) | 249 [NSDictionary dictionaryWithObject:UIColorFromRGB(kPrimaryActionColor) |
| 250 forKey:NSForegroundColorAttributeName]; | 250 forKey:NSForegroundColorAttributeName]; |
| 251 | 251 |
| 252 [attributedString addAttribute:NSLinkAttributeName | 252 [attributedString addAttribute:NSLinkAttributeName |
| 253 value:_URL | 253 value:_URL |
| 254 range:linkRange]; | 254 range:linkRange]; |
| 255 descriptionView.attributedText = attributedString; | 255 descriptionView.attributedText = attributedString; |
| 256 return descriptionView; | 256 return descriptionView; |
| 257 } | 257 } |
| 258 | 258 |
| 259 - (UIImageView*)keyIconView { | 259 - (UIImageView*)keyIconView { |
| 260 UIImage* keyIcon = ui::ResourceBundle::GetSharedInstance() | 260 UIImage* keyIcon = ui::ResourceBundle::GetSharedInstance() |
| 261 .GetImageNamed(IDR_IOS_INFOBAR_AUTOLOGIN) | 261 .GetImageNamed(IDR_IOS_INFOBAR_AUTOLOGIN) |
| 262 .ToUIImage(); | 262 .ToUIImage(); |
| 263 UIImageView* keyIconView = | 263 UIImageView* keyIconView = [[UIImageView alloc] initWithImage:keyIcon]; |
| 264 [[[UIImageView alloc] initWithImage:keyIcon] autorelease]; | |
| 265 [keyIconView setFrame:{CGPointZero, keyIcon.size}]; | 264 [keyIconView setFrame:{CGPointZero, keyIcon.size}]; |
| 266 return keyIconView; | 265 return keyIconView; |
| 267 } | 266 } |
| 268 | 267 |
| 269 #pragma mark - UITextViewDelegate | 268 #pragma mark - UITextViewDelegate |
| 270 | 269 |
| 271 - (BOOL)textView:(UITextView*)textView | 270 - (BOOL)textView:(UITextView*)textView |
| 272 shouldInteractWithURL:(NSURL*)URL | 271 shouldInteractWithURL:(NSURL*)URL |
| 273 inRange:(NSRange)characterRange | 272 inRange:(NSRange)characterRange |
| 274 interaction:(UITextItemInteraction)interaction { | 273 interaction:(UITextItemInteraction)interaction { |
| 275 DCHECK([URL isEqual:_URL.get()]); | 274 DCHECK([URL isEqual:_URL]); |
| 276 [_delegate showSavedPasswords:self]; | 275 [_delegate showSavedPasswords:self]; |
| 277 return NO; | 276 return NO; |
| 278 } | 277 } |
| 279 | 278 |
| 280 @end | 279 @end |
| 281 | 280 |
| 282 #pragma mark - Classes emulating MDCDialog | 281 #pragma mark - Classes emulating MDCDialog |
| 283 | 282 |
| 284 @interface PasswordGenerationPromptDialog () { | 283 @interface PasswordGenerationPromptDialog () { |
| 285 base::WeakNSObject<UIViewController> _viewController; | 284 __weak UIViewController* _viewController; |
| 286 base::WeakNSProtocol<id<PasswordGenerationPromptDelegate>> _weakDelegate; | 285 __weak id<PasswordGenerationPromptDelegate> _weakDelegate; |
| 287 } | 286 } |
| 288 | 287 |
| 289 // Dismiss the dialog. | 288 // Dismiss the dialog. |
| 290 - (void)dismiss; | 289 - (void)dismiss; |
| 291 // Callback called when the user accept to use the password. | 290 // Callback called when the user accept to use the password. |
| 292 - (void)acceptPassword; | 291 - (void)acceptPassword; |
| 293 // Creates the view containing the buttons. | 292 // Creates the view containing the buttons. |
| 294 - (UIView*)createButtons; | 293 - (UIView*)createButtons; |
| 295 | 294 |
| 296 @end | 295 @end |
| 297 | 296 |
| 298 @implementation PasswordGenerationPromptDialog | 297 @implementation PasswordGenerationPromptDialog |
| 299 | 298 |
| 300 - (instancetype)initWithDelegate:(id<PasswordGenerationPromptDelegate>)delegate | 299 - (instancetype)initWithDelegate:(id<PasswordGenerationPromptDelegate>)delegate |
| 301 viewController:(UIViewController*)viewController { | 300 viewController:(UIViewController*)viewController { |
| 302 self = [super initWithFrame:CGRectZero]; | 301 self = [super initWithFrame:CGRectZero]; |
| 303 if (self) { | 302 if (self) { |
| 304 _viewController.reset(viewController); | 303 _viewController = viewController; |
| 305 _weakDelegate.reset(delegate); | 304 _weakDelegate = delegate; |
| 306 } | 305 } |
| 307 return self; | 306 return self; |
| 308 } | 307 } |
| 309 | 308 |
| 310 - (void)dismiss { | 309 - (void)dismiss { |
| 311 [_viewController dismissViewControllerAnimated:NO completion:nil]; | 310 [_viewController dismissViewControllerAnimated:NO completion:nil]; |
| 312 } | 311 } |
| 313 | 312 |
| 314 - (void)acceptPassword { | 313 - (void)acceptPassword { |
| 315 [_weakDelegate acceptPasswordGeneration:nil]; | 314 [_weakDelegate acceptPasswordGeneration:nil]; |
| 316 [self dismiss]; | 315 [self dismiss]; |
| 317 } | 316 } |
| 318 | 317 |
| 319 // Creates the view containing the buttons. | 318 // Creates the view containing the buttons. |
| 320 - (UIView*)createButtons { | 319 - (UIView*)createButtons { |
| 321 UIView* view = [[[UIView alloc] initWithFrame:CGRectZero] autorelease]; | 320 UIView* view = [[UIView alloc] initWithFrame:CGRectZero]; |
| 322 | 321 |
| 323 NSString* cancelTitle = l10n_util::GetNSString(IDS_CANCEL); | 322 NSString* cancelTitle = l10n_util::GetNSString(IDS_CANCEL); |
| 324 MDCFlatButton* cancelButton = [[[MDCFlatButton alloc] init] autorelease]; | 323 MDCFlatButton* cancelButton = [[MDCFlatButton alloc] init]; |
| 325 [cancelButton setTitle:cancelTitle forState:UIControlStateNormal]; | 324 [cancelButton setTitle:cancelTitle forState:UIControlStateNormal]; |
| 326 [cancelButton sizeToFit]; | 325 [cancelButton sizeToFit]; |
| 327 [cancelButton setCustomTitleColor:[UIColor blackColor]]; | 326 [cancelButton setCustomTitleColor:[UIColor blackColor]]; |
| 328 [cancelButton addTarget:self | 327 [cancelButton addTarget:self |
| 329 action:@selector(dismiss) | 328 action:@selector(dismiss) |
| 330 forControlEvents:UIControlEventTouchUpInside]; | 329 forControlEvents:UIControlEventTouchUpInside]; |
| 331 | 330 |
| 332 NSString* acceptTitle = | 331 NSString* acceptTitle = |
| 333 l10n_util::GetNSString(IDS_IOS_GENERATED_PASSWORD_ACCEPT); | 332 l10n_util::GetNSString(IDS_IOS_GENERATED_PASSWORD_ACCEPT); |
| 334 MDCFlatButton* OKButton = [[[MDCFlatButton alloc] init] autorelease]; | 333 MDCFlatButton* OKButton = [[MDCFlatButton alloc] init]; |
| 335 [OKButton setTitle:acceptTitle forState:UIControlStateNormal]; | 334 [OKButton setTitle:acceptTitle forState:UIControlStateNormal]; |
| 336 [OKButton sizeToFit]; | 335 [OKButton sizeToFit]; |
| 337 [OKButton setCustomTitleColor:[UIColor blackColor]]; | 336 [OKButton setCustomTitleColor:[UIColor blackColor]]; |
| 338 [OKButton addTarget:self | 337 [OKButton addTarget:self |
| 339 action:@selector(acceptPassword) | 338 action:@selector(acceptPassword) |
| 340 forControlEvents:UIControlEventTouchUpInside]; | 339 forControlEvents:UIControlEventTouchUpInside]; |
| 341 | 340 |
| 342 [cancelButton setTranslatesAutoresizingMaskIntoConstraints:NO]; | 341 [cancelButton setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 343 [OKButton setTranslatesAutoresizingMaskIntoConstraints:NO]; | 342 [OKButton setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 344 | 343 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 356 options:NSLayoutFormatAlignAllTop | 355 options:NSLayoutFormatAlignAllTop |
| 357 metrics:nil | 356 metrics:nil |
| 358 views:views]]; | 357 views:views]]; |
| 359 | 358 |
| 360 return view; | 359 return view; |
| 361 } | 360 } |
| 362 | 361 |
| 363 // Creates the view containing the password text and the buttons. | 362 // Creates the view containing the password text and the buttons. |
| 364 - (void)configureGlobalViewWithPassword:(NSString*)password { | 363 - (void)configureGlobalViewWithPassword:(NSString*)password { |
| 365 PasswordGenerationPromptView* passwordContentView = | 364 PasswordGenerationPromptView* passwordContentView = |
| 366 [[[PasswordGenerationPromptView alloc] initWithPassword:password | 365 [[PasswordGenerationPromptView alloc] initWithPassword:password |
| 367 delegate:_weakDelegate] | 366 delegate:_weakDelegate]; |
| 368 autorelease]; | |
| 369 | 367 |
| 370 [passwordContentView configure]; | 368 [passwordContentView configure]; |
| 371 | 369 |
| 372 [passwordContentView setTranslatesAutoresizingMaskIntoConstraints:NO]; | 370 [passwordContentView setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 373 | 371 |
| 374 UIView* buttons = [self createButtons]; | 372 UIView* buttons = [self createButtons]; |
| 375 [buttons setTranslatesAutoresizingMaskIntoConstraints:NO]; | 373 [buttons setTranslatesAutoresizingMaskIntoConstraints:NO]; |
| 376 | 374 |
| 377 [self addSubview:passwordContentView]; | 375 [self addSubview:passwordContentView]; |
| 378 [self addSubview:buttons]; | 376 [self addSubview:buttons]; |
| 379 | 377 |
| 380 NSDictionary* views = | 378 NSDictionary* views = |
| 381 @{ @"view" : passwordContentView, | 379 @{ @"view" : passwordContentView, |
| 382 @"buttons" : buttons }; | 380 @"buttons" : buttons }; |
| 383 NSDictionary* metrics = @{ @"MDCPadding" : @(kMDCPadding) }; | 381 NSDictionary* metrics = @{ @"MDCPadding" : @(kMDCPadding) }; |
| 384 [self addConstraints:[NSLayoutConstraint | 382 [self addConstraints:[NSLayoutConstraint |
| 385 constraintsWithVisualFormat: | 383 constraintsWithVisualFormat: |
| 386 @"V:|[view]-(MDCPadding)-[buttons]-|" | 384 @"V:|[view]-(MDCPadding)-[buttons]-|" |
| 387 options:NSLayoutAttributeTrailing | 385 options:NSLayoutAttributeTrailing |
| 388 metrics:metrics | 386 metrics:metrics |
| 389 views:views]]; | 387 views:views]]; |
| 390 [self addConstraints:[NSLayoutConstraint | 388 [self addConstraints:[NSLayoutConstraint |
| 391 constraintsWithVisualFormat:@"H:|[view]|" | 389 constraintsWithVisualFormat:@"H:|[view]|" |
| 392 options:0 | 390 options:0 |
| 393 metrics:nil | 391 metrics:nil |
| 394 views:views]]; | 392 views:views]]; |
| 395 } | 393 } |
| 396 | 394 |
| 397 @end | 395 @end |
| OLD | NEW |