Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: ios/chrome/browser/passwords/password_generation_prompt_view.mm

Issue 2585233003: Upstream Chrome on iOS source code [2/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/passwords/password_generation_prompt_view.h"
6
7 #include <memory>
8
9 #include "base/ios/weak_nsobject.h"
10 #include "base/mac/scoped_nsobject.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "components/strings/grit/components_strings.h"
13 #import "ios/chrome/browser/passwords/password_generation_prompt_delegate.h"
14 #import "ios/chrome/browser/ui/rtl_geometry.h"
15 #include "ios/chrome/browser/ui/ui_util.h"
16 #import "ios/chrome/browser/ui/uikit_ui_util.h"
17 #include "ios/chrome/common/string_util.h"
18 #include "ios/chrome/grit/ios_strings.h"
19 #include "ios/chrome/grit/ios_theme_resources.h"
20 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate rialButtons.h"
21 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoF ontLoader.h"
22 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/base/resource/resource_bundle.h"
24
25 namespace {
26
27 // Material Design Component constraints.
28 const CGFloat kMDCPadding = 24;
29
30 // Horizontal and vertical padding for the entire view.
31 const CGFloat kPadding = 8.0f;
32
33 // Colors for primary and secondary user interactions.
34 const int kPrimaryActionColor = 0x5595FE;
35
36 // Constants for the password label.
37 const int kPasswordLabelFontSize = 16;
38 const int kPasswordLabelFontColor = 0x787878;
39 const CGFloat kPasswordLabelVerticalPadding = 5.0f;
40
41 // Constants for the title label.
42 const int kTitleLabelFontSize = 16;
43 const int kTitleLabelFontColor = 0x333333;
44 const CGFloat kTitleLabelVerticalPadding = 5.0f;
45
46 // Constants for the description label.
47 const int kDescriptionLabelFontSize = 14;
48 const int kDescriptionLabelFontColor = 0x787878;
49 const int kDescriptionLabelLineSpacing = 8;
50 const CGFloat kDescriptionLabelTopPadding = 10.0f;
51
52 } // namespace
53
54 // A view that prompts the user with a password generated by Chrome and explains
55 // what that means. The user can accept the password, cancel password
56 // generation, or click a link to view all their saved passwords.
57 @interface PasswordGenerationPromptView : UIView<UITextViewDelegate>
58
59 // Initializes a PasswordGenerationPromptView that shows the specified
60 // |password| and delegates user interaction events to |delegate|.
61 - (instancetype)initWithPassword:(NSString*)password
62 delegate:(id<PasswordGenerationPromptDelegate>)delegate
63 NS_DESIGNATED_INITIALIZER;
64
65 - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
66
67 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
68
69 // Configure the view, adding subviews and constraints.
70 - (void)configure;
71
72 // Returns an autoreleased label for the title of the view.
73 - (UILabel*)titleLabel;
74
75 // Returns an autoreleased label to propose a generated password.
76 - (UILabel*)passwordLabel:(NSString*)password;
77
78 // Returns an autoreleased text view to explain password generation with a link.
79 - (UITextView*)description;
80
81 // Returns an autoreleased view that shows the lock icon.
82 - (UIImageView*)keyIconView;
83
84 @end
85
86 @implementation PasswordGenerationPromptView {
87 base::scoped_nsobject<NSString> _password;
88 base::WeakNSProtocol<id<PasswordGenerationPromptDelegate>> _delegate;
89 base::scoped_nsobject<NSURL> _URL;
90 base::scoped_nsobject<UILabel> _title;
91 }
92
93 - (instancetype)initWithPassword:(NSString*)password
94 delegate:
95 (id<PasswordGenerationPromptDelegate>)delegate {
96 self = [super initWithFrame:CGRectZero];
97 if (self) {
98 _URL.reset(
99 [[NSURL URLWithString:@"chromeinternal://showpasswords"] retain]);
100 _delegate.reset(delegate);
101 _password.reset([password copy]);
102 }
103 return self;
104 }
105
106 - (void)configure {
107 UIView* headerView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
108 UIImageView* icon = [self keyIconView];
109 UILabel* title = [self titleLabel];
110 UILabel* password = [self passwordLabel:_password];
111 UITextView* description = [self description];
112
113 _title.reset([title retain]);
114
115 [headerView addSubview:icon];
116 [headerView addSubview:title];
117 [headerView addSubview:password];
118 [self addSubview:headerView];
119 [self addSubview:description];
120
121 // -----------------------------------------------
122 // | |
123 // | (lock) Use password generated by Chrome? |
124 // | Fsf6s88fssdf |
125 // | |
126 // | blah blah blah description blah blah |
127 // | blah blah [link to passwords] blah. |
128 // | |
129 // -----------------------------------------------
130
131 [headerView setTranslatesAutoresizingMaskIntoConstraints:NO];
132 [icon setTranslatesAutoresizingMaskIntoConstraints:NO];
133 [title setTranslatesAutoresizingMaskIntoConstraints:NO];
134 [password setTranslatesAutoresizingMaskIntoConstraints:NO];
135 [description setTranslatesAutoresizingMaskIntoConstraints:NO];
136
137 NSArray* constraints = @[
138 @"H:|[keyIcon]-[title]|", @"V:|[keyIcon]",
139 @"V:|-(padding)-[header]-(descriptionPadding)-[description]|",
140 @"H:|-(padding)-[header]-(padding)-|",
141 @"H:|-(padding)-[description]-(padding)-|"
142 ];
143
144 NSDictionary* viewsDictionary = @{
145 @"keyIcon" : icon,
146 @"title" : title,
147 @"passwd" : password,
148 @"header" : headerView,
149 @"description" : description
150 };
151
152 NSDictionary* metrics = @{
153 @"padding" : @(kPadding),
154 @"passwordPadding" : @(kPasswordLabelVerticalPadding),
155 @"descriptionPadding" : @(kDescriptionLabelTopPadding),
156 @"titlePadding" : @(kTitleLabelVerticalPadding)
157 };
158
159 ApplyVisualConstraintsWithMetricsAndOptions(
160 constraints, viewsDictionary, metrics, LayoutOptionForRTLSupport());
161
162 [headerView
163 addConstraints:
164 [NSLayoutConstraint
165 constraintsWithVisualFormat:
166 @"V:|-(titlePadding)-[title]-(passwordPadding)-[passwd]|"
167 options:NSLayoutFormatAlignAllLeading
168 metrics:metrics
169 views:viewsDictionary]];
170
171 [title setContentHuggingPriority:UILayoutPriorityRequired
172 forAxis:UILayoutConstraintAxisVertical];
173 [icon setContentHuggingPriority:UILayoutPriorityRequired
174 forAxis:UILayoutConstraintAxisHorizontal];
175 [headerView setContentHuggingPriority:UILayoutPriorityRequired
176 forAxis:UILayoutConstraintAxisVertical];
177 }
178
179 - (void)layoutSubviews {
180 [super layoutSubviews];
181 // Make sure the title is spread on multiple lines if needed.
182 [_title setPreferredMaxLayoutWidth:[_title frame].size.width];
183 }
184
185 - (UILabel*)titleLabel {
186 NSMutableDictionary* attrsDictionary = [NSMutableDictionary
187 dictionaryWithObject:[[MDFRobotoFontLoader sharedInstance]
188 mediumFontOfSize:kTitleLabelFontSize]
189 forKey:NSFontAttributeName];
190 [attrsDictionary setObject:UIColorFromRGB(kTitleLabelFontColor)
191 forKey:NSForegroundColorAttributeName];
192
193 NSMutableAttributedString* string = [[[NSMutableAttributedString alloc]
194 initWithString:l10n_util::GetNSString(
195 IDS_IOS_GENERATED_PASSWORD_PROMPT_TITLE)
196 attributes:attrsDictionary] autorelease];
197
198 base::scoped_nsobject<UILabel> titleLabel([[UILabel alloc] init]);
199 [titleLabel setAttributedText:string];
200 [titleLabel setNumberOfLines:0];
201 [titleLabel sizeToFit];
202 return titleLabel.autorelease();
203 }
204
205 - (UILabel*)passwordLabel:(NSString*)password {
206 base::scoped_nsobject<UILabel> passwordLabel([[UILabel alloc] init]);
207 [passwordLabel setText:password];
208 [passwordLabel setTextColor:UIColorFromRGB(kPasswordLabelFontColor)];
209 [passwordLabel setFont:[[MDFRobotoFontLoader sharedInstance]
210 regularFontOfSize:kPasswordLabelFontSize]];
211 [passwordLabel setNumberOfLines:1];
212 [passwordLabel sizeToFit];
213 return passwordLabel.autorelease();
214 }
215
216 - (UITextView*)description {
217 NSRange linkRange;
218 NSString* description = ParseStringWithLink(
219 l10n_util::GetNSString(IDS_IOS_GENERATED_PASSWORD_PROMPT_DESCRIPTION),
220 &linkRange);
221
222 base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
223 [[NSMutableParagraphStyle alloc] init]);
224 [paragraphStyle setLineSpacing:kDescriptionLabelLineSpacing];
225
226 NSDictionary* attributeDictionary =
227 [NSDictionary dictionaryWithObjectsAndKeys:
228 UIColorFromRGB(kDescriptionLabelFontColor),
229 NSForegroundColorAttributeName, paragraphStyle.get(),
230 NSParagraphStyleAttributeName,
231 [[MDFRobotoFontLoader sharedInstance]
232 regularFontOfSize:kDescriptionLabelFontSize],
233 NSFontAttributeName, nil];
234
235 base::scoped_nsobject<NSMutableAttributedString> attributedString(
236 [[NSMutableAttributedString alloc] initWithString:description
237 attributes:attributeDictionary]);
238
239 UITextView* descriptionView =
240 [[[UITextView alloc] initWithFrame:CGRectZero textContainer:nil]
241 autorelease];
242 descriptionView.scrollEnabled = NO;
243 descriptionView.selectable = YES;
244 descriptionView.editable = NO;
245 descriptionView.delegate = self;
246 descriptionView.userInteractionEnabled = YES;
247
248 descriptionView.linkTextAttributes =
249 [NSDictionary dictionaryWithObject:UIColorFromRGB(kPrimaryActionColor)
250 forKey:NSForegroundColorAttributeName];
251
252 [attributedString addAttribute:NSLinkAttributeName
253 value:_URL
254 range:linkRange];
255 descriptionView.attributedText = attributedString;
256 return descriptionView;
257 }
258
259 - (UIImageView*)keyIconView {
260 UIImage* keyIcon = ui::ResourceBundle::GetSharedInstance()
261 .GetImageNamed(IDR_IOS_INFOBAR_AUTOLOGIN)
262 .ToUIImage();
263 UIImageView* keyIconView =
264 [[[UIImageView alloc] initWithImage:keyIcon] autorelease];
265 [keyIconView setFrame:{CGPointZero, keyIcon.size}];
266 return keyIconView;
267 }
268
269 #pragma mark - UITextViewDelegate
270
271 - (BOOL)textView:(UITextView*)textView
272 shouldInteractWithURL:(NSURL*)URL
273 inRange:(NSRange)characterRange
274 interaction:(UITextItemInteraction)interaction {
275 DCHECK([URL isEqual:_URL.get()]);
276 [_delegate showSavedPasswords:self];
277 return NO;
278 }
279
280 @end
281
282 #pragma mark - Classes emulating MDCDialog
283
284 @interface PasswordGenerationPromptDialog () {
285 base::WeakNSObject<UIViewController> _viewController;
286 base::WeakNSProtocol<id<PasswordGenerationPromptDelegate>> _weakDelegate;
287 }
288
289 // Dismiss the dialog.
290 - (void)dismiss;
291 // Callback called when the user accept to use the password.
292 - (void)acceptPassword;
293 // Creates the view containing the buttons.
294 - (UIView*)createButtons;
295
296 @end
297
298 @implementation PasswordGenerationPromptDialog
299
300 - (instancetype)initWithDelegate:(id<PasswordGenerationPromptDelegate>)delegate
301 viewController:(UIViewController*)viewController {
302 self = [super initWithFrame:CGRectZero];
303 if (self) {
304 _viewController.reset(viewController);
305 _weakDelegate.reset(delegate);
306 }
307 return self;
308 }
309
310 - (void)dismiss {
311 [_viewController dismissViewControllerAnimated:NO completion:nil];
312 }
313
314 - (void)acceptPassword {
315 [_weakDelegate acceptPasswordGeneration:nil];
316 [self dismiss];
317 }
318
319 // Creates the view containing the buttons.
320 - (UIView*)createButtons {
321 UIView* view = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
322
323 NSString* cancelTitle = l10n_util::GetNSString(IDS_CANCEL);
324 MDCFlatButton* cancelButton = [[[MDCFlatButton alloc] init] autorelease];
325 [cancelButton setTitle:cancelTitle forState:UIControlStateNormal];
326 [cancelButton sizeToFit];
327 [cancelButton setCustomTitleColor:[UIColor blackColor]];
328 [cancelButton addTarget:self
329 action:@selector(dismiss)
330 forControlEvents:UIControlEventTouchUpInside];
331
332 NSString* acceptTitle =
333 l10n_util::GetNSString(IDS_IOS_GENERATED_PASSWORD_ACCEPT);
334 MDCFlatButton* OKButton = [[[MDCFlatButton alloc] init] autorelease];
335 [OKButton setTitle:acceptTitle forState:UIControlStateNormal];
336 [OKButton sizeToFit];
337 [OKButton setCustomTitleColor:[UIColor blackColor]];
338 [OKButton addTarget:self
339 action:@selector(acceptPassword)
340 forControlEvents:UIControlEventTouchUpInside];
341
342 [cancelButton setTranslatesAutoresizingMaskIntoConstraints:NO];
343 [OKButton setTranslatesAutoresizingMaskIntoConstraints:NO];
344
345 [view addSubview:cancelButton];
346 [view addSubview:OKButton];
347
348 NSDictionary* views = @{ @"cancel" : cancelButton, @"ok" : OKButton };
349 [view addConstraints:[NSLayoutConstraint
350 constraintsWithVisualFormat:@"V:|-[cancel]-|"
351 options:0
352 metrics:nil
353 views:views]];
354 [view addConstraints:[NSLayoutConstraint
355 constraintsWithVisualFormat:@"H:[cancel]-[ok]-|"
356 options:NSLayoutFormatAlignAllTop
357 metrics:nil
358 views:views]];
359
360 return view;
361 }
362
363 // Creates the view containing the password text and the buttons.
364 - (void)configureGlobalViewWithPassword:(NSString*)password {
365 PasswordGenerationPromptView* passwordContentView =
366 [[[PasswordGenerationPromptView alloc] initWithPassword:password
367 delegate:_weakDelegate]
368 autorelease];
369
370 [passwordContentView configure];
371
372 [passwordContentView setTranslatesAutoresizingMaskIntoConstraints:NO];
373
374 UIView* buttons = [self createButtons];
375 [buttons setTranslatesAutoresizingMaskIntoConstraints:NO];
376
377 [self addSubview:passwordContentView];
378 [self addSubview:buttons];
379
380 NSDictionary* views =
381 @{ @"view" : passwordContentView,
382 @"buttons" : buttons };
383 NSDictionary* metrics = @{ @"MDCPadding" : @(kMDCPadding) };
384 [self addConstraints:[NSLayoutConstraint
385 constraintsWithVisualFormat:
386 @"V:|[view]-(MDCPadding)-[buttons]-|"
387 options:NSLayoutAttributeTrailing
388 metrics:metrics
389 views:views]];
390 [self addConstraints:[NSLayoutConstraint
391 constraintsWithVisualFormat:@"H:|[view]|"
392 options:0
393 metrics:nil
394 views:views]];
395 }
396
397 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698