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

Unified Diff: chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm

Issue 929293005: Autofill: Add contents of CVC unmask prompt dialog on OSX. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cup_01_initial_add
Patch Set: Address groby@ comments for patch set 1. Created 5 years, 10 months 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: chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
diff --git a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
index cc8897d4e7692583d115c363dd61d96f79105a6e..0c726097dcd2e83e462d8cb572e293ac270cb8ea 100644
--- a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
+++ b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/strings/sys_string_conversions.h"
#include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h"
#include "chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h"
+#import "chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h"
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
#include "chrome/browser/ui/chrome_style.h"
+#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_control_utils.h"
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
#import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
@@ -14,7 +17,11 @@
#include "ui/base/l10n/l10n_util.h"
namespace {
+
const CGFloat kButtonGap = 6.0f;
+const CGFloat kDialogMinWidth = 250.0f;
+const CGFloat kCvcInputWidth = 64.0f;
+
} // namespace
namespace autofill {
@@ -30,12 +37,16 @@ CardUnmaskPromptView* CardUnmaskPromptView::CreateAndShow(
CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge(
CardUnmaskPromptController* controller)
: controller_(controller) {
- sheet_controller_.reset([[CardUnmaskPromptViewCocoa alloc]
+ view_controller_.reset([[CardUnmaskPromptViewCocoa alloc]
initWithWebContents:controller_->GetWebContents()
bridge:this]);
+
+ // Setup the constrained window that will show the view.
+ base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc]
+ initWithContentRect:[[view_controller_ view] bounds]]);
+ [window setContentView:[view_controller_ view]];
base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
- [[CustomConstrainedWindowSheet alloc]
- initWithCustomWindow:[sheet_controller_ window]]);
+ [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
constrained_window_.reset(
new ConstrainedWindowMac(this, controller_->GetWebContents(), sheet));
}
@@ -44,6 +55,8 @@ CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() {
}
void CardUnmaskPromptViewBridge::ControllerGone() {
+ controller_ = nullptr;
+ PerformClose();
}
void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() {
@@ -55,7 +68,12 @@ void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) {
void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed(
ConstrainedWindowMac* window) {
constrained_window_.reset();
- controller_->OnUnmaskDialogClosed();
+ if (controller_)
+ controller_->OnUnmaskDialogClosed();
+}
+
+CardUnmaskPromptController* CardUnmaskPromptViewBridge::GetController() {
+ return controller_;
}
void CardUnmaskPromptViewBridge::PerformClose() {
@@ -68,19 +86,35 @@ void CardUnmaskPromptViewBridge::PerformClose() {
@implementation CardUnmaskPromptViewCocoa
++ (AutofillPopUpButton*)buildDatePopupWithModel:(ui::ComboboxModel&)model {
+ AutofillPopUpButton* popup =
+ [[AutofillPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
+
+ for (int i = 0; i < model.GetItemCount(); ++i) {
+ [popup addItemWithTitle:base::SysUTF16ToNSString(model.GetItemAt(i))];
+ }
+ [popup setDefaultValue:base::SysUTF16ToNSString(
+ model.GetItemAt(model.GetDefaultIndex()))];
+ [popup sizeToFit];
+ return popup;
+}
+
++ (void)setDatePopup:(AutofillPopUpButton*)popup
+ originX:(CGFloat)originX
+ originY:(CGFloat)originY
+ height:(CGFloat)height {
+ [popup setFrameOrigin:NSMakePoint(originX, originY)];
+ [popup setFrameSize:NSMakeSize(NSWidth([popup frame]), height)];
bondd 2015/03/02 23:04:04 After combining setFrameOrigin + setFrameSize -> s
+}
+
- (id)initWithWebContents:(content::WebContents*)webContents
bridge:(autofill::CardUnmaskPromptViewBridge*)bridge {
DCHECK(webContents);
DCHECK(bridge);
- NSRect frame = NSMakeRect(0, 0, 550, 600);
- base::scoped_nsobject<ConstrainedWindowCustomWindow> window(
- [[ConstrainedWindowCustomWindow alloc] initWithContentRect:frame]);
- if ((self = [super initWithWindow:window])) {
+ if ((self = [super initWithNibName:nil bundle:nil])) {
webContents_ = webContents;
bridge_ = bridge;
-
- [self buildWindowButtons];
}
return self;
}
@@ -89,38 +123,176 @@ void CardUnmaskPromptViewBridge::PerformClose() {
bridge_->PerformClose();
}
-- (void)buildWindowButtons {
- base::scoped_nsobject<NSView> buttonContainer(
+- (void)loadView {
+ autofill::CardUnmaskPromptController* controller = bridge_->GetController();
+ DCHECK(controller);
+
+ base::scoped_nsobject<NSView> mainView(
[[NSView alloc] initWithFrame:NSZeroRect]);
- base::scoped_nsobject<NSButton> button(
+ // Title label.
+ NSTextField* title = constrained_window::CreateLabel();
+ NSAttributedString* titleString =
+ constrained_window::GetAttributedLabelString(
+ SysUTF16ToNSString(controller->GetWindowTitle()),
+ chrome_style::kTitleFontStyle, NSNaturalTextAlignment,
+ NSLineBreakByWordWrapping);
+ [title setAttributedStringValue:titleString];
+ [title sizeToFit];
+ [mainView addSubview:title];
+
+ // Instructions label.
+ NSTextField* instructions = constrained_window::CreateLabel();
+ NSAttributedString* instructionsString =
+ constrained_window::GetAttributedLabelString(
+ SysUTF16ToNSString(controller->GetInstructionsMessage()),
+ chrome_style::kTextFontStyle, NSNaturalTextAlignment,
+ NSLineBreakByWordWrapping);
+ [instructions setAttributedStringValue:instructionsString];
+ // No need to call sizeToFit here. Size is calculated later.
groby-ooo-7-16 2015/02/28 00:49:17 Feel free to kill this comment :)
bondd 2015/03/02 23:04:04 Done.
+ [mainView addSubview:instructions];
+
+ // Expiration date.
+ base::scoped_nsobject<AutofillPopUpButton> monthPopup;
+ base::scoped_nsobject<AutofillPopUpButton> yearPopup;
+ NSSize expirationDateSize = NSZeroSize;
+ if (controller->ShouldRequestExpirationDate()) {
+ // Month.
+ autofill::MonthComboboxModel monthModel;
+ monthPopup.reset(
+ [CardUnmaskPromptViewCocoa buildDatePopupWithModel:monthModel]);
+ [mainView addSubview:monthPopup];
+
+ // Year.
+ autofill::YearComboboxModel yearModel;
+ yearPopup.reset(
+ [CardUnmaskPromptViewCocoa buildDatePopupWithModel:yearModel]);
+ [mainView addSubview:yearPopup];
+
+ // Dimensions.
+ expirationDateSize.width = NSWidth([monthPopup frame]) +
+ NSWidth([yearPopup frame]) + kButtonGap * 2;
+ expirationDateSize.height =
+ std::max(NSHeight([monthPopup frame]), NSHeight([yearPopup frame]));
+ }
+
+ // CVC text input.
+ base::scoped_nsobject<NSTextField> cvcInput(
+ [[NSTextField alloc] initWithFrame:NSZeroRect]);
+ [[cvcInput cell]
+ setPlaceholderString:l10n_util::GetNSString(
+ IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC)];
+ [[cvcInput cell] setScrollable:YES];
+ [cvcInput sizeToFit];
+ [mainView addSubview:cvcInput];
+
+ // CVC image.
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ NSImage* cvcImage =
+ rb.GetNativeImageNamed(controller->GetCvcImageRid()).ToNSImage();
+ base::scoped_nsobject<NSImageView> cvcImageView(
+ [[NSImageView alloc] initWithFrame:NSZeroRect]);
+ [cvcImageView setImage:cvcImage];
+ [mainView addSubview:cvcImageView];
+
+ // Cancel button.
+ base::scoped_nsobject<NSButton> cancelButton(
[[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
- [button setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)];
- [button setKeyEquivalent:kKeyEquivalentEscape];
- [button setTarget:self];
- [button setAction:@selector(closeSheet:)];
- [button sizeToFit];
- [buttonContainer addSubview:button];
-
- CGFloat nextX = NSMaxX([button frame]) + kButtonGap;
- button.reset([[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
- [button setFrameOrigin:NSMakePoint(nextX, 0)];
- [button setTitle:l10n_util::GetNSStringWithFixup(
- IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON)];
- [button setKeyEquivalent:kKeyEquivalentReturn];
- [button setTarget:self];
- [button setAction:@selector(closeSheet:)];
- [button sizeToFit];
- [buttonContainer addSubview:button];
-
- const CGFloat dialogOffset = NSWidth([[self window] frame]) -
- chrome_style::kHorizontalPadding -
- NSMaxX([button frame]);
- [buttonContainer
- setFrame:NSMakeRect(dialogOffset, chrome_style::kClientBottomPadding,
- NSMaxX([button frame]), NSMaxY([button frame]))];
-
- [[[self window] contentView] addSubview:buttonContainer];
+ [cancelButton setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)];
+ [cancelButton setKeyEquivalent:kKeyEquivalentEscape];
+ [cancelButton setTarget:self];
+ [cancelButton setAction:@selector(closeSheet:)];
+ [cancelButton sizeToFit];
+ [mainView addSubview:cancelButton];
+
+ // Verify button.
+ base::scoped_nsobject<NSButton> verifyButton(
+ [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
+ // TODO(bondd): use l10n string.
+ [verifyButton setTitle:@"Verify"];
+ [verifyButton setKeyEquivalent:kKeyEquivalentReturn];
+ [verifyButton setTarget:self];
+ [verifyButton setAction:@selector(closeSheet:)];
+ [verifyButton sizeToFit];
+ [mainView addSubview:verifyButton];
+
+ // Calculate input row dimensions.
+ NSSize inputRowSize;
+ inputRowSize.width = kCvcInputWidth + kButtonGap + [cvcImage size].width +
+ expirationDateSize.width;
+ CGFloat maxCvcHeight =
+ std::max(NSHeight([cvcInput frame]), [cvcImage size].height);
+ inputRowSize.height = std::max(maxCvcHeight, expirationDateSize.height);
+
+ // Calculate dialog width.
+ CGFloat dialogWidth = std::max(NSWidth([title frame]), inputRowSize.width) +
+ chrome_style::kHorizontalPadding * 2;
groby-ooo-7-16 2015/02/28 00:49:17 If you want to save yourself a whole lot of paddin
bondd 2015/03/02 23:04:04 Done. Now I use NSBox contentViewMargins for horiz
+ dialogWidth = std::max(dialogWidth, kDialogMinWidth);
+
+ // Layout the elements, starting at the bottom and moving up.
groby-ooo-7-16 2015/02/28 00:49:17 "Starting at the bottom" is pretty much implied in
bondd 2015/03/02 23:04:04 Acknowledged. I saw it in profile_signin_confirmat
+
+ CGFloat curX = dialogWidth - chrome_style::kHorizontalPadding;
groby-ooo-7-16 2015/02/28 00:49:17 Since you keep converting this to a point anyways
bondd 2015/03/02 23:04:04 Done.
+ CGFloat curY = chrome_style::kClientBottomPadding;
+
+ // Verify and Cancel buttons.
+ curX -= NSWidth([verifyButton frame]);
+ [verifyButton setFrameOrigin:NSMakePoint(curX, curY)];
+ curX -= kButtonGap + NSWidth([cancelButton frame]);
+ [cancelButton setFrameOrigin:NSMakePoint(curX, curY)];
+ curY += NSHeight([cancelButton frame]);
+
+ // Get start position of input row.
+ curX = chrome_style::kHorizontalPadding;
+ curY += chrome_style::kRowPadding;
+
+ // Expiration date.
+ if (controller->ShouldRequestExpirationDate()) {
+ [CardUnmaskPromptViewCocoa setDatePopup:monthPopup
+ originX:curX
+ originY:curY
+ height:inputRowSize.height];
+ curX += NSWidth([monthPopup frame]) + kButtonGap;
+
+ [CardUnmaskPromptViewCocoa setDatePopup:yearPopup
+ originX:curX
+ originY:curY
+ height:inputRowSize.height];
+ curX += NSWidth([yearPopup frame]) + kButtonGap;
+ }
+
+ // Center cvcInput vertically in the input row.
groby-ooo-7-16 2015/02/28 00:49:17 Does that ensure centering of popups as well?
bondd 2015/03/02 23:04:04 Yes, popups will be centered vertically. Popups ge
+ CGFloat cvcInputY =
+ curY + round((inputRowSize.height - NSHeight([cvcInput frame])) * 0.5);
groby-ooo-7-16 2015/02/28 00:49:17 Why round, instead of ceil?
bondd 2015/03/02 23:04:04 Done.
+ [cvcInput setFrameOrigin:NSMakePoint(curX, cvcInputY)];
groby-ooo-7-16 2015/02/28 00:49:17 setFrame:NSMakeRect(...
bondd 2015/03/02 23:04:04 Done.
+ [cvcInput
+ setFrameSize:NSMakeSize(kCvcInputWidth, NSHeight([cvcInput frame]))];
+ curX += NSWidth([cvcInput frame]) + kButtonGap;
+
+ // CVC image.
+ [cvcImageView setFrameOrigin:NSMakePoint(curX, curY)];
+ [cvcImageView
+ setFrameSize:NSMakeSize([cvcImage size].width, inputRowSize.height)];
groby-ooo-7-16 2015/02/28 00:49:17 setFrame:NSMakeRect(...
bondd 2015/03/02 23:04:04 Done.
+ curX += NSWidth([cvcImageView frame]);
+
+ // Instruction label.
+ curX = chrome_style::kHorizontalPadding;
+ curY += inputRowSize.height + chrome_style::kRowPadding;
+ [instructions setFrameOrigin:NSMakePoint(curX, curY)];
+ CGFloat maxTextWidth = dialogWidth - chrome_style::kHorizontalPadding * 2;
+ NSSize instructionsSize = [[instructions cell]
+ cellSizeForBounds:NSMakeRect(0.0, 0.0, maxTextWidth, CGFLOAT_MAX)];
+ [instructions setFrameSize:instructionsSize];
+
+ // Title label.
+ curY += instructionsSize.height + chrome_style::kRowPadding;
+ [title setFrameOrigin:NSMakePoint(curX, curY)];
+
+ // Dialog size.
+ CGFloat dialogHeight =
+ curY + NSHeight([title frame]) + chrome_style::kTitleTopPadding;
groby-ooo-7-16 2015/02/28 00:49:17 That's NSMaxY([title frame]) + chrome_style::kTitl
bondd 2015/03/02 23:04:04 Done.
+
+ [mainView setFrame:NSMakeRect(0, 0, dialogWidth, dialogHeight)];
groby-ooo-7-16 2015/02/28 00:49:17 You can probably just to -setFrameSize Ther orig
bondd 2015/03/02 23:04:04 Done.
+ [self setView:mainView];
}
@end

Powered by Google App Engine
This is Rietveld 408576698