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 |