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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/passwords/password_generation_prompt_view.mm
diff --git a/ios/chrome/browser/passwords/password_generation_prompt_view.mm b/ios/chrome/browser/passwords/password_generation_prompt_view.mm
new file mode 100644
index 0000000000000000000000000000000000000000..bc543260ea9e87ea44d09b0b7273da5fb7487d50
--- /dev/null
+++ b/ios/chrome/browser/passwords/password_generation_prompt_view.mm
@@ -0,0 +1,397 @@
+// Copyright 2014 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.
+
+#import "ios/chrome/browser/passwords/password_generation_prompt_view.h"
+
+#include <memory>
+
+#include "base/ios/weak_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/passwords/password_generation_prompt_delegate.h"
+#import "ios/chrome/browser/ui/rtl_geometry.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/common/string_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ios/chrome/grit/ios_theme_resources.h"
+#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
+#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+// Material Design Component constraints.
+const CGFloat kMDCPadding = 24;
+
+// Horizontal and vertical padding for the entire view.
+const CGFloat kPadding = 8.0f;
+
+// Colors for primary and secondary user interactions.
+const int kPrimaryActionColor = 0x5595FE;
+
+// Constants for the password label.
+const int kPasswordLabelFontSize = 16;
+const int kPasswordLabelFontColor = 0x787878;
+const CGFloat kPasswordLabelVerticalPadding = 5.0f;
+
+// Constants for the title label.
+const int kTitleLabelFontSize = 16;
+const int kTitleLabelFontColor = 0x333333;
+const CGFloat kTitleLabelVerticalPadding = 5.0f;
+
+// Constants for the description label.
+const int kDescriptionLabelFontSize = 14;
+const int kDescriptionLabelFontColor = 0x787878;
+const int kDescriptionLabelLineSpacing = 8;
+const CGFloat kDescriptionLabelTopPadding = 10.0f;
+
+} // namespace
+
+// A view that prompts the user with a password generated by Chrome and explains
+// what that means. The user can accept the password, cancel password
+// generation, or click a link to view all their saved passwords.
+@interface PasswordGenerationPromptView : UIView<UITextViewDelegate>
+
+// Initializes a PasswordGenerationPromptView that shows the specified
+// |password| and delegates user interaction events to |delegate|.
+- (instancetype)initWithPassword:(NSString*)password
+ delegate:(id<PasswordGenerationPromptDelegate>)delegate
+ NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
+
+- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
+
+// Configure the view, adding subviews and constraints.
+- (void)configure;
+
+// Returns an autoreleased label for the title of the view.
+- (UILabel*)titleLabel;
+
+// Returns an autoreleased label to propose a generated password.
+- (UILabel*)passwordLabel:(NSString*)password;
+
+// Returns an autoreleased text view to explain password generation with a link.
+- (UITextView*)description;
+
+// Returns an autoreleased view that shows the lock icon.
+- (UIImageView*)keyIconView;
+
+@end
+
+@implementation PasswordGenerationPromptView {
+ base::scoped_nsobject<NSString> _password;
+ base::WeakNSProtocol<id<PasswordGenerationPromptDelegate>> _delegate;
+ base::scoped_nsobject<NSURL> _URL;
+ base::scoped_nsobject<UILabel> _title;
+}
+
+- (instancetype)initWithPassword:(NSString*)password
+ delegate:
+ (id<PasswordGenerationPromptDelegate>)delegate {
+ self = [super initWithFrame:CGRectZero];
+ if (self) {
+ _URL.reset(
+ [[NSURL URLWithString:@"chromeinternal://showpasswords"] retain]);
+ _delegate.reset(delegate);
+ _password.reset([password copy]);
+ }
+ return self;
+}
+
+- (void)configure {
+ UIView* headerView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
+ UIImageView* icon = [self keyIconView];
+ UILabel* title = [self titleLabel];
+ UILabel* password = [self passwordLabel:_password];
+ UITextView* description = [self description];
+
+ _title.reset([title retain]);
+
+ [headerView addSubview:icon];
+ [headerView addSubview:title];
+ [headerView addSubview:password];
+ [self addSubview:headerView];
+ [self addSubview:description];
+
+ // -----------------------------------------------
+ // | |
+ // | (lock) Use password generated by Chrome? |
+ // | Fsf6s88fssdf |
+ // | |
+ // | blah blah blah description blah blah |
+ // | blah blah [link to passwords] blah. |
+ // | |
+ // -----------------------------------------------
+
+ [headerView setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [icon setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [title setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [password setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [description setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+ NSArray* constraints = @[
+ @"H:|[keyIcon]-[title]|", @"V:|[keyIcon]",
+ @"V:|-(padding)-[header]-(descriptionPadding)-[description]|",
+ @"H:|-(padding)-[header]-(padding)-|",
+ @"H:|-(padding)-[description]-(padding)-|"
+ ];
+
+ NSDictionary* viewsDictionary = @{
+ @"keyIcon" : icon,
+ @"title" : title,
+ @"passwd" : password,
+ @"header" : headerView,
+ @"description" : description
+ };
+
+ NSDictionary* metrics = @{
+ @"padding" : @(kPadding),
+ @"passwordPadding" : @(kPasswordLabelVerticalPadding),
+ @"descriptionPadding" : @(kDescriptionLabelTopPadding),
+ @"titlePadding" : @(kTitleLabelVerticalPadding)
+ };
+
+ ApplyVisualConstraintsWithMetricsAndOptions(
+ constraints, viewsDictionary, metrics, LayoutOptionForRTLSupport());
+
+ [headerView
+ addConstraints:
+ [NSLayoutConstraint
+ constraintsWithVisualFormat:
+ @"V:|-(titlePadding)-[title]-(passwordPadding)-[passwd]|"
+ options:NSLayoutFormatAlignAllLeading
+ metrics:metrics
+ views:viewsDictionary]];
+
+ [title setContentHuggingPriority:UILayoutPriorityRequired
+ forAxis:UILayoutConstraintAxisVertical];
+ [icon setContentHuggingPriority:UILayoutPriorityRequired
+ forAxis:UILayoutConstraintAxisHorizontal];
+ [headerView setContentHuggingPriority:UILayoutPriorityRequired
+ forAxis:UILayoutConstraintAxisVertical];
+}
+
+- (void)layoutSubviews {
+ [super layoutSubviews];
+ // Make sure the title is spread on multiple lines if needed.
+ [_title setPreferredMaxLayoutWidth:[_title frame].size.width];
+}
+
+- (UILabel*)titleLabel {
+ NSMutableDictionary* attrsDictionary = [NSMutableDictionary
+ dictionaryWithObject:[[MDFRobotoFontLoader sharedInstance]
+ mediumFontOfSize:kTitleLabelFontSize]
+ forKey:NSFontAttributeName];
+ [attrsDictionary setObject:UIColorFromRGB(kTitleLabelFontColor)
+ forKey:NSForegroundColorAttributeName];
+
+ NSMutableAttributedString* string = [[[NSMutableAttributedString alloc]
+ initWithString:l10n_util::GetNSString(
+ IDS_IOS_GENERATED_PASSWORD_PROMPT_TITLE)
+ attributes:attrsDictionary] autorelease];
+
+ base::scoped_nsobject<UILabel> titleLabel([[UILabel alloc] init]);
+ [titleLabel setAttributedText:string];
+ [titleLabel setNumberOfLines:0];
+ [titleLabel sizeToFit];
+ return titleLabel.autorelease();
+}
+
+- (UILabel*)passwordLabel:(NSString*)password {
+ base::scoped_nsobject<UILabel> passwordLabel([[UILabel alloc] init]);
+ [passwordLabel setText:password];
+ [passwordLabel setTextColor:UIColorFromRGB(kPasswordLabelFontColor)];
+ [passwordLabel setFont:[[MDFRobotoFontLoader sharedInstance]
+ regularFontOfSize:kPasswordLabelFontSize]];
+ [passwordLabel setNumberOfLines:1];
+ [passwordLabel sizeToFit];
+ return passwordLabel.autorelease();
+}
+
+- (UITextView*)description {
+ NSRange linkRange;
+ NSString* description = ParseStringWithLink(
+ l10n_util::GetNSString(IDS_IOS_GENERATED_PASSWORD_PROMPT_DESCRIPTION),
+ &linkRange);
+
+ base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
+ [[NSMutableParagraphStyle alloc] init]);
+ [paragraphStyle setLineSpacing:kDescriptionLabelLineSpacing];
+
+ NSDictionary* attributeDictionary =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ UIColorFromRGB(kDescriptionLabelFontColor),
+ NSForegroundColorAttributeName, paragraphStyle.get(),
+ NSParagraphStyleAttributeName,
+ [[MDFRobotoFontLoader sharedInstance]
+ regularFontOfSize:kDescriptionLabelFontSize],
+ NSFontAttributeName, nil];
+
+ base::scoped_nsobject<NSMutableAttributedString> attributedString(
+ [[NSMutableAttributedString alloc] initWithString:description
+ attributes:attributeDictionary]);
+
+ UITextView* descriptionView =
+ [[[UITextView alloc] initWithFrame:CGRectZero textContainer:nil]
+ autorelease];
+ descriptionView.scrollEnabled = NO;
+ descriptionView.selectable = YES;
+ descriptionView.editable = NO;
+ descriptionView.delegate = self;
+ descriptionView.userInteractionEnabled = YES;
+
+ descriptionView.linkTextAttributes =
+ [NSDictionary dictionaryWithObject:UIColorFromRGB(kPrimaryActionColor)
+ forKey:NSForegroundColorAttributeName];
+
+ [attributedString addAttribute:NSLinkAttributeName
+ value:_URL
+ range:linkRange];
+ descriptionView.attributedText = attributedString;
+ return descriptionView;
+}
+
+- (UIImageView*)keyIconView {
+ UIImage* keyIcon = ui::ResourceBundle::GetSharedInstance()
+ .GetImageNamed(IDR_IOS_INFOBAR_AUTOLOGIN)
+ .ToUIImage();
+ UIImageView* keyIconView =
+ [[[UIImageView alloc] initWithImage:keyIcon] autorelease];
+ [keyIconView setFrame:{CGPointZero, keyIcon.size}];
+ return keyIconView;
+}
+
+#pragma mark - UITextViewDelegate
+
+- (BOOL)textView:(UITextView*)textView
+ shouldInteractWithURL:(NSURL*)URL
+ inRange:(NSRange)characterRange
+ interaction:(UITextItemInteraction)interaction {
+ DCHECK([URL isEqual:_URL.get()]);
+ [_delegate showSavedPasswords:self];
+ return NO;
+}
+
+@end
+
+#pragma mark - Classes emulating MDCDialog
+
+@interface PasswordGenerationPromptDialog () {
+ base::WeakNSObject<UIViewController> _viewController;
+ base::WeakNSProtocol<id<PasswordGenerationPromptDelegate>> _weakDelegate;
+}
+
+// Dismiss the dialog.
+- (void)dismiss;
+// Callback called when the user accept to use the password.
+- (void)acceptPassword;
+// Creates the view containing the buttons.
+- (UIView*)createButtons;
+
+@end
+
+@implementation PasswordGenerationPromptDialog
+
+- (instancetype)initWithDelegate:(id<PasswordGenerationPromptDelegate>)delegate
+ viewController:(UIViewController*)viewController {
+ self = [super initWithFrame:CGRectZero];
+ if (self) {
+ _viewController.reset(viewController);
+ _weakDelegate.reset(delegate);
+ }
+ return self;
+}
+
+- (void)dismiss {
+ [_viewController dismissViewControllerAnimated:NO completion:nil];
+}
+
+- (void)acceptPassword {
+ [_weakDelegate acceptPasswordGeneration:nil];
+ [self dismiss];
+}
+
+// Creates the view containing the buttons.
+- (UIView*)createButtons {
+ UIView* view = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
+
+ NSString* cancelTitle = l10n_util::GetNSString(IDS_CANCEL);
+ MDCFlatButton* cancelButton = [[[MDCFlatButton alloc] init] autorelease];
+ [cancelButton setTitle:cancelTitle forState:UIControlStateNormal];
+ [cancelButton sizeToFit];
+ [cancelButton setCustomTitleColor:[UIColor blackColor]];
+ [cancelButton addTarget:self
+ action:@selector(dismiss)
+ forControlEvents:UIControlEventTouchUpInside];
+
+ NSString* acceptTitle =
+ l10n_util::GetNSString(IDS_IOS_GENERATED_PASSWORD_ACCEPT);
+ MDCFlatButton* OKButton = [[[MDCFlatButton alloc] init] autorelease];
+ [OKButton setTitle:acceptTitle forState:UIControlStateNormal];
+ [OKButton sizeToFit];
+ [OKButton setCustomTitleColor:[UIColor blackColor]];
+ [OKButton addTarget:self
+ action:@selector(acceptPassword)
+ forControlEvents:UIControlEventTouchUpInside];
+
+ [cancelButton setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [OKButton setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+ [view addSubview:cancelButton];
+ [view addSubview:OKButton];
+
+ NSDictionary* views = @{ @"cancel" : cancelButton, @"ok" : OKButton };
+ [view addConstraints:[NSLayoutConstraint
+ constraintsWithVisualFormat:@"V:|-[cancel]-|"
+ options:0
+ metrics:nil
+ views:views]];
+ [view addConstraints:[NSLayoutConstraint
+ constraintsWithVisualFormat:@"H:[cancel]-[ok]-|"
+ options:NSLayoutFormatAlignAllTop
+ metrics:nil
+ views:views]];
+
+ return view;
+}
+
+// Creates the view containing the password text and the buttons.
+- (void)configureGlobalViewWithPassword:(NSString*)password {
+ PasswordGenerationPromptView* passwordContentView =
+ [[[PasswordGenerationPromptView alloc] initWithPassword:password
+ delegate:_weakDelegate]
+ autorelease];
+
+ [passwordContentView configure];
+
+ [passwordContentView setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+ UIView* buttons = [self createButtons];
+ [buttons setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+ [self addSubview:passwordContentView];
+ [self addSubview:buttons];
+
+ NSDictionary* views =
+ @{ @"view" : passwordContentView,
+ @"buttons" : buttons };
+ NSDictionary* metrics = @{ @"MDCPadding" : @(kMDCPadding) };
+ [self addConstraints:[NSLayoutConstraint
+ constraintsWithVisualFormat:
+ @"V:|[view]-(MDCPadding)-[buttons]-|"
+ options:NSLayoutAttributeTrailing
+ metrics:metrics
+ views:views]];
+ [self addConstraints:[NSLayoutConstraint
+ constraintsWithVisualFormat:@"H:|[view]|"
+ options:0
+ metrics:nil
+ views:views]];
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698