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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2015 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 #include "base/strings/sys_string_conversions.h"
5 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h" 6 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h"
6 #include "chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h" 7 #include "chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h"
8 #import "chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h"
7 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" 9 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
8 #include "chrome/browser/ui/chrome_style.h" 10 #include "chrome/browser/ui/chrome_style.h"
11 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_control_u tils.h"
9 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sh eet.h" 12 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sh eet.h"
10 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_wi ndow.h" 13 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_wi ndow.h"
11 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h" 14 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
12 #include "grit/generated_resources.h" 15 #include "grit/generated_resources.h"
13 #include "ui/base/cocoa/window_size_constants.h" 16 #include "ui/base/cocoa/window_size_constants.h"
14 #include "ui/base/l10n/l10n_util.h" 17 #include "ui/base/l10n/l10n_util.h"
15 18
16 namespace { 19 namespace {
20
17 const CGFloat kButtonGap = 6.0f; 21 const CGFloat kButtonGap = 6.0f;
22 const CGFloat kDialogMinWidth = 250.0f;
23 const CGFloat kCvcInputWidth = 64.0f;
24
18 } // namespace 25 } // namespace
19 26
20 namespace autofill { 27 namespace autofill {
21 28
22 // static 29 // static
23 CardUnmaskPromptView* CardUnmaskPromptView::CreateAndShow( 30 CardUnmaskPromptView* CardUnmaskPromptView::CreateAndShow(
24 CardUnmaskPromptController* controller) { 31 CardUnmaskPromptController* controller) {
25 return new CardUnmaskPromptViewBridge(controller); 32 return new CardUnmaskPromptViewBridge(controller);
26 } 33 }
27 34
28 #pragma mark CardUnmaskPromptViewBridge 35 #pragma mark CardUnmaskPromptViewBridge
29 36
30 CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge( 37 CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge(
31 CardUnmaskPromptController* controller) 38 CardUnmaskPromptController* controller)
32 : controller_(controller) { 39 : controller_(controller) {
33 sheet_controller_.reset([[CardUnmaskPromptViewCocoa alloc] 40 view_controller_.reset([[CardUnmaskPromptViewCocoa alloc]
34 initWithWebContents:controller_->GetWebContents() 41 initWithWebContents:controller_->GetWebContents()
35 bridge:this]); 42 bridge:this]);
43
44 // Setup the constrained window that will show the view.
45 base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc]
46 initWithContentRect:[[view_controller_ view] bounds]]);
47 [window setContentView:[view_controller_ view]];
36 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet( 48 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
37 [[CustomConstrainedWindowSheet alloc] 49 [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
38 initWithCustomWindow:[sheet_controller_ window]]);
39 constrained_window_.reset( 50 constrained_window_.reset(
40 new ConstrainedWindowMac(this, controller_->GetWebContents(), sheet)); 51 new ConstrainedWindowMac(this, controller_->GetWebContents(), sheet));
41 } 52 }
42 53
43 CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() { 54 CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() {
44 } 55 }
45 56
46 void CardUnmaskPromptViewBridge::ControllerGone() { 57 void CardUnmaskPromptViewBridge::ControllerGone() {
58 controller_ = nullptr;
59 PerformClose();
47 } 60 }
48 61
49 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() { 62 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() {
50 } 63 }
51 64
52 void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) { 65 void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) {
53 } 66 }
54 67
55 void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed( 68 void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed(
56 ConstrainedWindowMac* window) { 69 ConstrainedWindowMac* window) {
57 constrained_window_.reset(); 70 constrained_window_.reset();
58 controller_->OnUnmaskDialogClosed(); 71 if (controller_)
72 controller_->OnUnmaskDialogClosed();
73 }
74
75 CardUnmaskPromptController* CardUnmaskPromptViewBridge::GetController() {
76 return controller_;
59 } 77 }
60 78
61 void CardUnmaskPromptViewBridge::PerformClose() { 79 void CardUnmaskPromptViewBridge::PerformClose() {
62 constrained_window_->CloseWebContentsModalDialog(); 80 constrained_window_->CloseWebContentsModalDialog();
63 } 81 }
64 82
65 } // autofill 83 } // autofill
66 84
67 #pragma mark CardUnmaskPromptViewCocoa 85 #pragma mark CardUnmaskPromptViewCocoa
68 86
69 @implementation CardUnmaskPromptViewCocoa 87 @implementation CardUnmaskPromptViewCocoa
70 88
89 + (AutofillPopUpButton*)buildDatePopupWithModel:(ui::ComboboxModel&)model {
90 AutofillPopUpButton* popup =
91 [[AutofillPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
92
93 for (int i = 0; i < model.GetItemCount(); ++i) {
94 [popup addItemWithTitle:base::SysUTF16ToNSString(model.GetItemAt(i))];
95 }
96 [popup setDefaultValue:base::SysUTF16ToNSString(
97 model.GetItemAt(model.GetDefaultIndex()))];
98 [popup sizeToFit];
99 return popup;
100 }
101
102 + (void)setDatePopup:(AutofillPopUpButton*)popup
103 originX:(CGFloat)originX
104 originY:(CGFloat)originY
105 height:(CGFloat)height {
106 [popup setFrameOrigin:NSMakePoint(originX, originY)];
107 [popup setFrameSize:NSMakeSize(NSWidth([popup frame]), height)];
bondd 2015/03/02 23:04:04 After combining setFrameOrigin + setFrameSize -> s
108 }
109
71 - (id)initWithWebContents:(content::WebContents*)webContents 110 - (id)initWithWebContents:(content::WebContents*)webContents
72 bridge:(autofill::CardUnmaskPromptViewBridge*)bridge { 111 bridge:(autofill::CardUnmaskPromptViewBridge*)bridge {
73 DCHECK(webContents); 112 DCHECK(webContents);
74 DCHECK(bridge); 113 DCHECK(bridge);
75 114
76 NSRect frame = NSMakeRect(0, 0, 550, 600); 115 if ((self = [super initWithNibName:nil bundle:nil])) {
77 base::scoped_nsobject<ConstrainedWindowCustomWindow> window(
78 [[ConstrainedWindowCustomWindow alloc] initWithContentRect:frame]);
79 if ((self = [super initWithWindow:window])) {
80 webContents_ = webContents; 116 webContents_ = webContents;
81 bridge_ = bridge; 117 bridge_ = bridge;
82
83 [self buildWindowButtons];
84 } 118 }
85 return self; 119 return self;
86 } 120 }
87 121
88 - (IBAction)closeSheet:(id)sender { 122 - (IBAction)closeSheet:(id)sender {
89 bridge_->PerformClose(); 123 bridge_->PerformClose();
90 } 124 }
91 125
92 - (void)buildWindowButtons { 126 - (void)loadView {
93 base::scoped_nsobject<NSView> buttonContainer( 127 autofill::CardUnmaskPromptController* controller = bridge_->GetController();
128 DCHECK(controller);
129
130 base::scoped_nsobject<NSView> mainView(
94 [[NSView alloc] initWithFrame:NSZeroRect]); 131 [[NSView alloc] initWithFrame:NSZeroRect]);
95 132
96 base::scoped_nsobject<NSButton> button( 133 // Title label.
134 NSTextField* title = constrained_window::CreateLabel();
135 NSAttributedString* titleString =
136 constrained_window::GetAttributedLabelString(
137 SysUTF16ToNSString(controller->GetWindowTitle()),
138 chrome_style::kTitleFontStyle, NSNaturalTextAlignment,
139 NSLineBreakByWordWrapping);
140 [title setAttributedStringValue:titleString];
141 [title sizeToFit];
142 [mainView addSubview:title];
143
144 // Instructions label.
145 NSTextField* instructions = constrained_window::CreateLabel();
146 NSAttributedString* instructionsString =
147 constrained_window::GetAttributedLabelString(
148 SysUTF16ToNSString(controller->GetInstructionsMessage()),
149 chrome_style::kTextFontStyle, NSNaturalTextAlignment,
150 NSLineBreakByWordWrapping);
151 [instructions setAttributedStringValue:instructionsString];
152 // 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.
153 [mainView addSubview:instructions];
154
155 // Expiration date.
156 base::scoped_nsobject<AutofillPopUpButton> monthPopup;
157 base::scoped_nsobject<AutofillPopUpButton> yearPopup;
158 NSSize expirationDateSize = NSZeroSize;
159 if (controller->ShouldRequestExpirationDate()) {
160 // Month.
161 autofill::MonthComboboxModel monthModel;
162 monthPopup.reset(
163 [CardUnmaskPromptViewCocoa buildDatePopupWithModel:monthModel]);
164 [mainView addSubview:monthPopup];
165
166 // Year.
167 autofill::YearComboboxModel yearModel;
168 yearPopup.reset(
169 [CardUnmaskPromptViewCocoa buildDatePopupWithModel:yearModel]);
170 [mainView addSubview:yearPopup];
171
172 // Dimensions.
173 expirationDateSize.width = NSWidth([monthPopup frame]) +
174 NSWidth([yearPopup frame]) + kButtonGap * 2;
175 expirationDateSize.height =
176 std::max(NSHeight([monthPopup frame]), NSHeight([yearPopup frame]));
177 }
178
179 // CVC text input.
180 base::scoped_nsobject<NSTextField> cvcInput(
181 [[NSTextField alloc] initWithFrame:NSZeroRect]);
182 [[cvcInput cell]
183 setPlaceholderString:l10n_util::GetNSString(
184 IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC)];
185 [[cvcInput cell] setScrollable:YES];
186 [cvcInput sizeToFit];
187 [mainView addSubview:cvcInput];
188
189 // CVC image.
190 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
191 NSImage* cvcImage =
192 rb.GetNativeImageNamed(controller->GetCvcImageRid()).ToNSImage();
193 base::scoped_nsobject<NSImageView> cvcImageView(
194 [[NSImageView alloc] initWithFrame:NSZeroRect]);
195 [cvcImageView setImage:cvcImage];
196 [mainView addSubview:cvcImageView];
197
198 // Cancel button.
199 base::scoped_nsobject<NSButton> cancelButton(
97 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); 200 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
98 [button setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)]; 201 [cancelButton setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)];
99 [button setKeyEquivalent:kKeyEquivalentEscape]; 202 [cancelButton setKeyEquivalent:kKeyEquivalentEscape];
100 [button setTarget:self]; 203 [cancelButton setTarget:self];
101 [button setAction:@selector(closeSheet:)]; 204 [cancelButton setAction:@selector(closeSheet:)];
102 [button sizeToFit]; 205 [cancelButton sizeToFit];
103 [buttonContainer addSubview:button]; 206 [mainView addSubview:cancelButton];
104 207
105 CGFloat nextX = NSMaxX([button frame]) + kButtonGap; 208 // Verify button.
106 button.reset([[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); 209 base::scoped_nsobject<NSButton> verifyButton(
107 [button setFrameOrigin:NSMakePoint(nextX, 0)]; 210 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
108 [button setTitle:l10n_util::GetNSStringWithFixup( 211 // TODO(bondd): use l10n string.
109 IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON)]; 212 [verifyButton setTitle:@"Verify"];
110 [button setKeyEquivalent:kKeyEquivalentReturn]; 213 [verifyButton setKeyEquivalent:kKeyEquivalentReturn];
111 [button setTarget:self]; 214 [verifyButton setTarget:self];
112 [button setAction:@selector(closeSheet:)]; 215 [verifyButton setAction:@selector(closeSheet:)];
113 [button sizeToFit]; 216 [verifyButton sizeToFit];
114 [buttonContainer addSubview:button]; 217 [mainView addSubview:verifyButton];
115 218
116 const CGFloat dialogOffset = NSWidth([[self window] frame]) - 219 // Calculate input row dimensions.
117 chrome_style::kHorizontalPadding - 220 NSSize inputRowSize;
118 NSMaxX([button frame]); 221 inputRowSize.width = kCvcInputWidth + kButtonGap + [cvcImage size].width +
119 [buttonContainer 222 expirationDateSize.width;
120 setFrame:NSMakeRect(dialogOffset, chrome_style::kClientBottomPadding, 223 CGFloat maxCvcHeight =
121 NSMaxX([button frame]), NSMaxY([button frame]))]; 224 std::max(NSHeight([cvcInput frame]), [cvcImage size].height);
225 inputRowSize.height = std::max(maxCvcHeight, expirationDateSize.height);
122 226
123 [[[self window] contentView] addSubview:buttonContainer]; 227 // Calculate dialog width.
228 CGFloat dialogWidth = std::max(NSWidth([title frame]), inputRowSize.width) +
229 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
230 dialogWidth = std::max(dialogWidth, kDialogMinWidth);
231
232 // 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
233
234 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.
235 CGFloat curY = chrome_style::kClientBottomPadding;
236
237 // Verify and Cancel buttons.
238 curX -= NSWidth([verifyButton frame]);
239 [verifyButton setFrameOrigin:NSMakePoint(curX, curY)];
240 curX -= kButtonGap + NSWidth([cancelButton frame]);
241 [cancelButton setFrameOrigin:NSMakePoint(curX, curY)];
242 curY += NSHeight([cancelButton frame]);
243
244 // Get start position of input row.
245 curX = chrome_style::kHorizontalPadding;
246 curY += chrome_style::kRowPadding;
247
248 // Expiration date.
249 if (controller->ShouldRequestExpirationDate()) {
250 [CardUnmaskPromptViewCocoa setDatePopup:monthPopup
251 originX:curX
252 originY:curY
253 height:inputRowSize.height];
254 curX += NSWidth([monthPopup frame]) + kButtonGap;
255
256 [CardUnmaskPromptViewCocoa setDatePopup:yearPopup
257 originX:curX
258 originY:curY
259 height:inputRowSize.height];
260 curX += NSWidth([yearPopup frame]) + kButtonGap;
261 }
262
263 // 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
264 CGFloat cvcInputY =
265 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.
266 [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.
267 [cvcInput
268 setFrameSize:NSMakeSize(kCvcInputWidth, NSHeight([cvcInput frame]))];
269 curX += NSWidth([cvcInput frame]) + kButtonGap;
270
271 // CVC image.
272 [cvcImageView setFrameOrigin:NSMakePoint(curX, curY)];
273 [cvcImageView
274 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.
275 curX += NSWidth([cvcImageView frame]);
276
277 // Instruction label.
278 curX = chrome_style::kHorizontalPadding;
279 curY += inputRowSize.height + chrome_style::kRowPadding;
280 [instructions setFrameOrigin:NSMakePoint(curX, curY)];
281 CGFloat maxTextWidth = dialogWidth - chrome_style::kHorizontalPadding * 2;
282 NSSize instructionsSize = [[instructions cell]
283 cellSizeForBounds:NSMakeRect(0.0, 0.0, maxTextWidth, CGFLOAT_MAX)];
284 [instructions setFrameSize:instructionsSize];
285
286 // Title label.
287 curY += instructionsSize.height + chrome_style::kRowPadding;
288 [title setFrameOrigin:NSMakePoint(curX, curY)];
289
290 // Dialog size.
291 CGFloat dialogHeight =
292 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.
293
294 [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.
295 [self setView:mainView];
124 } 296 }
125 297
126 @end 298 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698