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

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 2. Created 5 years, 9 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
« no previous file with comments | « chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
6 #include "chrome/browser/ui/autofill/autofill_dialog_models.h"
5 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h" 7 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h"
6 #include "chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h" 8 #include "chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h"
9 #import "chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h"
7 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" 10 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
8 #include "chrome/browser/ui/chrome_style.h" 11 #include "chrome/browser/ui/chrome_style.h"
12 #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" 13 #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" 14 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_wi ndow.h"
11 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h" 15 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
12 #include "grit/generated_resources.h" 16 #include "grit/generated_resources.h"
13 #include "ui/base/cocoa/window_size_constants.h" 17 #include "ui/base/cocoa/window_size_constants.h"
14 #include "ui/base/l10n/l10n_util.h" 18 #include "ui/base/l10n/l10n_util.h"
15 19
16 namespace { 20 namespace {
21
17 const CGFloat kButtonGap = 6.0f; 22 const CGFloat kButtonGap = 6.0f;
23 const CGFloat kDialogContentMinWidth = 210.0f;
24 const CGFloat kCvcInputWidth = 64.0f;
25
18 } // namespace 26 } // namespace
19 27
20 namespace autofill { 28 namespace autofill {
21 29
22 // static 30 // static
23 CardUnmaskPromptView* CardUnmaskPromptView::CreateAndShow( 31 CardUnmaskPromptView* CardUnmaskPromptView::CreateAndShow(
24 CardUnmaskPromptController* controller) { 32 CardUnmaskPromptController* controller) {
25 return new CardUnmaskPromptViewBridge(controller); 33 return new CardUnmaskPromptViewBridge(controller);
26 } 34 }
27 35
28 #pragma mark CardUnmaskPromptViewBridge 36 #pragma mark CardUnmaskPromptViewBridge
29 37
30 CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge( 38 CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge(
31 CardUnmaskPromptController* controller) 39 CardUnmaskPromptController* controller)
32 : controller_(controller) { 40 : controller_(controller) {
33 sheet_controller_.reset([[CardUnmaskPromptViewCocoa alloc] 41 view_controller_.reset([[CardUnmaskPromptViewCocoa alloc]
34 initWithWebContents:controller_->GetWebContents() 42 initWithWebContents:controller_->GetWebContents()
35 bridge:this]); 43 bridge:this]);
44
45 // Setup the constrained window that will show the view.
46 base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc]
47 initWithContentRect:[[view_controller_ view] bounds]]);
48 [window setContentView:[view_controller_ view]];
36 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet( 49 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
37 [[CustomConstrainedWindowSheet alloc] 50 [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]);
38 initWithCustomWindow:[sheet_controller_ window]]);
39 constrained_window_.reset( 51 constrained_window_.reset(
40 new ConstrainedWindowMac(this, controller_->GetWebContents(), sheet)); 52 new ConstrainedWindowMac(this, controller_->GetWebContents(), sheet));
41 } 53 }
42 54
43 CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() { 55 CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() {
44 } 56 }
45 57
46 void CardUnmaskPromptViewBridge::ControllerGone() { 58 void CardUnmaskPromptViewBridge::ControllerGone() {
59 controller_ = nullptr;
60 PerformClose();
47 } 61 }
48 62
49 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() { 63 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() {
50 } 64 }
51 65
52 void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) { 66 void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) {
53 } 67 }
54 68
55 void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed( 69 void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed(
56 ConstrainedWindowMac* window) { 70 ConstrainedWindowMac* window) {
57 constrained_window_.reset(); 71 constrained_window_.reset();
58 controller_->OnUnmaskDialogClosed(); 72 if (controller_)
73 controller_->OnUnmaskDialogClosed();
74 }
75
76 CardUnmaskPromptController* CardUnmaskPromptViewBridge::GetController() {
77 return controller_;
59 } 78 }
60 79
61 void CardUnmaskPromptViewBridge::PerformClose() { 80 void CardUnmaskPromptViewBridge::PerformClose() {
62 constrained_window_->CloseWebContentsModalDialog(); 81 constrained_window_->CloseWebContentsModalDialog();
63 } 82 }
64 83
65 } // autofill 84 } // autofill
66 85
67 #pragma mark CardUnmaskPromptViewCocoa 86 #pragma mark CardUnmaskPromptViewCocoa
68 87
69 @implementation CardUnmaskPromptViewCocoa 88 @implementation CardUnmaskPromptViewCocoa
70 89
90 + (AutofillPopUpButton*)buildDatePopupWithModel:(ui::ComboboxModel&)model {
91 AutofillPopUpButton* popup =
92 [[AutofillPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
93
94 for (int i = 0; i < model.GetItemCount(); ++i) {
95 [popup addItemWithTitle:base::SysUTF16ToNSString(model.GetItemAt(i))];
96 }
97 [popup setDefaultValue:base::SysUTF16ToNSString(
98 model.GetItemAt(model.GetDefaultIndex()))];
99 [popup sizeToFit];
100 return popup;
101 }
102
71 - (id)initWithWebContents:(content::WebContents*)webContents 103 - (id)initWithWebContents:(content::WebContents*)webContents
72 bridge:(autofill::CardUnmaskPromptViewBridge*)bridge { 104 bridge:(autofill::CardUnmaskPromptViewBridge*)bridge {
73 DCHECK(webContents); 105 DCHECK(webContents);
74 DCHECK(bridge); 106 DCHECK(bridge);
75 107
76 NSRect frame = NSMakeRect(0, 0, 550, 600); 108 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; 109 webContents_ = webContents;
81 bridge_ = bridge; 110 bridge_ = bridge;
82
83 [self buildWindowButtons];
84 } 111 }
85 return self; 112 return self;
86 } 113 }
87 114
88 - (IBAction)closeSheet:(id)sender { 115 - (IBAction)closeSheet:(id)sender {
89 bridge_->PerformClose(); 116 bridge_->PerformClose();
90 } 117 }
91 118
92 - (void)buildWindowButtons { 119 - (void)loadView {
93 base::scoped_nsobject<NSView> buttonContainer( 120 autofill::CardUnmaskPromptController* controller = bridge_->GetController();
94 [[NSView alloc] initWithFrame:NSZeroRect]); 121 DCHECK(controller);
95 122
96 base::scoped_nsobject<NSButton> button( 123 base::scoped_nsobject<NSBox> mainView(
124 [[NSBox alloc] initWithFrame:NSZeroRect]);
125 [mainView setBoxType:NSBoxCustom];
126 [mainView setBorderType:NSNoBorder];
127 [mainView setTitlePosition:NSNoTitle];
128 [mainView
129 setContentViewMargins:NSMakeSize(chrome_style::kHorizontalPadding, 0.0)];
130
131 // Title label.
132 NSTextField* title = constrained_window::CreateLabel();
133 NSAttributedString* titleString =
134 constrained_window::GetAttributedLabelString(
135 SysUTF16ToNSString(controller->GetWindowTitle()),
136 chrome_style::kTitleFontStyle, NSNaturalTextAlignment,
137 NSLineBreakByWordWrapping);
138 [title setAttributedStringValue:titleString];
139 [title sizeToFit];
140 [mainView addSubview:title];
141
142 // Instructions label.
143 NSTextField* instructions = constrained_window::CreateLabel();
144 NSAttributedString* instructionsString =
145 constrained_window::GetAttributedLabelString(
146 SysUTF16ToNSString(controller->GetInstructionsMessage()),
147 chrome_style::kTextFontStyle, NSNaturalTextAlignment,
148 NSLineBreakByWordWrapping);
149 [instructions setAttributedStringValue:instructionsString];
150 [mainView addSubview:instructions];
151
152 // Expiration date.
153 base::scoped_nsobject<AutofillPopUpButton> monthPopup;
154 base::scoped_nsobject<AutofillPopUpButton> yearPopup;
155 NSSize expirationDateSize = NSZeroSize;
156 if (controller->ShouldRequestExpirationDate()) {
157 // Month.
158 autofill::MonthComboboxModel monthModel;
159 monthPopup.reset(
160 [CardUnmaskPromptViewCocoa buildDatePopupWithModel:monthModel]);
161 [mainView addSubview:monthPopup];
162
163 // Year.
164 autofill::YearComboboxModel yearModel;
165 yearPopup.reset(
166 [CardUnmaskPromptViewCocoa buildDatePopupWithModel:yearModel]);
167 [mainView addSubview:yearPopup];
168
169 // Dimensions.
groby-ooo-7-16 2015/03/03 18:06:54 That is kind of awkward. Wrap the comboboxes in a
bondd 2015/03/04 20:45:30 Done.
170 expirationDateSize.width = NSWidth([monthPopup frame]) +
171 NSWidth([yearPopup frame]) + kButtonGap * 2;
172 expirationDateSize.height =
173 std::max(NSHeight([monthPopup frame]), NSHeight([yearPopup frame]));
174 }
175
176 // CVC text input.
177 base::scoped_nsobject<NSTextField> cvcInput(
178 [[NSTextField alloc] initWithFrame:NSZeroRect]);
179 [[cvcInput cell]
180 setPlaceholderString:l10n_util::GetNSString(
181 IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC)];
182 [[cvcInput cell] setScrollable:YES];
groby-ooo-7-16 2015/03/03 18:06:54 We know the maximum size of a CVC - can we just pi
bondd 2015/03/04 20:45:30 What I've got here is the same functionality as Vi
Evan Stade 2015/03/05 02:38:02 I'm with Rachel here. UX designers aren't going to
bondd 2015/03/06 23:57:15 Apparently it is not trivial to do in OSX either:
183 [cvcInput sizeToFit];
184 [mainView addSubview:cvcInput];
185
186 // CVC image.
187 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
188 NSImage* cvcImage =
189 rb.GetNativeImageNamed(controller->GetCvcImageRid()).ToNSImage();
190 base::scoped_nsobject<NSImageView> cvcImageView(
191 [[NSImageView alloc] initWithFrame:NSZeroRect]);
192 [cvcImageView setImage:cvcImage];
193 [mainView addSubview:cvcImageView];
194
195 // Cancel button.
196 base::scoped_nsobject<NSButton> cancelButton(
97 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); 197 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
98 [button setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)]; 198 [cancelButton setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)];
99 [button setKeyEquivalent:kKeyEquivalentEscape]; 199 [cancelButton setKeyEquivalent:kKeyEquivalentEscape];
100 [button setTarget:self]; 200 [cancelButton setTarget:self];
101 [button setAction:@selector(closeSheet:)]; 201 [cancelButton setAction:@selector(closeSheet:)];
102 [button sizeToFit]; 202 [cancelButton sizeToFit];
103 [buttonContainer addSubview:button]; 203 [mainView addSubview:cancelButton];
104 204
105 CGFloat nextX = NSMaxX([button frame]) + kButtonGap; 205 // Verify button.
106 button.reset([[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); 206 base::scoped_nsobject<NSButton> verifyButton(
107 [button setFrameOrigin:NSMakePoint(nextX, 0)]; 207 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
108 [button setTitle:l10n_util::GetNSStringWithFixup( 208 // TODO(bondd): use l10n string.
groby-ooo-7-16 2015/03/03 18:06:54 Please do so :)
bondd 2015/03/04 20:45:30 Same TODO exists in the Views implementation: http
Evan Stade 2015/03/05 02:38:02 right. It's less a matter of "the value of this st
109 IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON)]; 209 [verifyButton setTitle:@"Verify"];
110 [button setKeyEquivalent:kKeyEquivalentReturn]; 210 [verifyButton setKeyEquivalent:kKeyEquivalentReturn];
111 [button setTarget:self]; 211 [verifyButton setTarget:self];
112 [button setAction:@selector(closeSheet:)]; 212 [verifyButton setAction:@selector(closeSheet:)];
113 [button sizeToFit]; 213 [verifyButton sizeToFit];
114 [buttonContainer addSubview:button]; 214 [mainView addSubview:verifyButton];
115 215
116 const CGFloat dialogOffset = NSWidth([[self window] frame]) - 216 // Calculate input row dimensions.
117 chrome_style::kHorizontalPadding - 217 NSSize inputRowSize;
118 NSMaxX([button frame]); 218 inputRowSize.width = kCvcInputWidth + kButtonGap + [cvcImage size].width +
groby-ooo-7-16 2015/03/03 18:06:54 You can get that width by just positioning the ele
bondd 2015/03/04 20:45:30 Done.
119 [buttonContainer 219 expirationDateSize.width;
120 setFrame:NSMakeRect(dialogOffset, chrome_style::kClientBottomPadding, 220 CGFloat maxCvcHeight =
121 NSMaxX([button frame]), NSMaxY([button frame]))]; 221 std::max(NSHeight([cvcInput frame]), [cvcImage size].height);
222 inputRowSize.height = std::max(maxCvcHeight, expirationDateSize.height);
122 223
123 [[[self window] contentView] addSubview:buttonContainer]; 224 // Calculate dialog content width.
225 CGFloat contentWidth = std::max(NSWidth([title frame]), inputRowSize.width);
226 contentWidth = std::max(contentWidth, kDialogContentMinWidth);
227
228 // Layout the elements, starting at the bottom and moving up.
229
230 NSPoint pos = NSMakePoint(contentWidth, chrome_style::kClientBottomPadding);
231
232 // Verify and Cancel buttons.
233 pos.x -= NSWidth([verifyButton frame]);
234 [verifyButton setFrameOrigin:pos];
235 pos.x -= kButtonGap + NSWidth([cancelButton frame]);
236 [cancelButton setFrameOrigin:pos];
237 pos.y += NSHeight([cancelButton frame]);
238
239 // Get start position of input row.
240 pos.x = 0.0;
241 pos.y += chrome_style::kRowPadding;
242
243 // Expiration date.
groby-ooo-7-16 2015/03/03 18:06:54 This entire thing becomes [expirationView setFram
bondd 2015/03/04 20:45:30 Done.
244 if (controller->ShouldRequestExpirationDate()) {
245 [monthPopup setFrame:NSMakeRect(pos.x, pos.y, NSWidth([monthPopup frame]),
246 inputRowSize.height)];
247 pos.x += NSWidth([monthPopup frame]) + kButtonGap;
248
249 [yearPopup setFrame:NSMakeRect(pos.x, pos.y, NSWidth([yearPopup frame]),
250 inputRowSize.height)];
251 pos.x += NSWidth([yearPopup frame]) + kButtonGap;
252 }
253
254 // Center cvcInput vertically in the input row.
255 CGFloat cvcInputY =
256 pos.y + ceil((inputRowSize.height - NSHeight([cvcInput frame])) * 0.5);
257 [cvcInput setFrame:NSMakeRect(pos.x, cvcInputY, kCvcInputWidth,
258 NSHeight([cvcInput frame]))];
259 pos.x += NSWidth([cvcInput frame]) + kButtonGap;
260
261 // CVC image.
262 [cvcImageView setFrame:NSMakeRect(pos.x, pos.y, [cvcImage size].width,
263 inputRowSize.height)];
groby-ooo-7-16 2015/03/03 18:06:54 Why not just use the original image size? And do a
bondd 2015/03/04 20:45:30 Done.
264 pos.x += NSWidth([cvcImageView frame]);
265
266 // Instruction label.
267 pos.x = 0.0;
groby-ooo-7-16 2015/03/03 18:06:54 pos = NSMakePoint(0.0, NSMaxY([cvcImage frame]) +
bondd 2015/03/04 20:45:30 Done.
268 pos.y += inputRowSize.height + chrome_style::kRowPadding;
269 [instructions setFrameOrigin:pos];
270 NSSize instructionsSize = [[instructions cell]
271 cellSizeForBounds:NSMakeRect(0.0, 0.0, contentWidth, CGFLOAT_MAX)];
272 [instructions setFrameSize:instructionsSize];
273
274 // Title label.
275 pos.y += instructionsSize.height + chrome_style::kRowPadding;
groby-ooo-7-16 2015/03/03 18:06:54 NSMakePoint(0.0, NSMaxY([instructions frame] + chr
bondd 2015/03/04 20:45:30 Done.
276 [title setFrameOrigin:pos];
277
278 // Dialog size.
279 CGFloat dialogHeight = NSMaxY([title frame]) + chrome_style::kTitleTopPadding;
groby-ooo-7-16 2015/03/03 18:06:54 Shouldn't the bottom have the same padding? In whi
bondd 2015/03/04 20:45:30 AFAICT the padding is different for top and bottom
280
281 [mainView
282 setFrameSize:NSMakeSize(
groby-ooo-7-16 2015/03/03 18:06:54 [mainView sizeToFit] should do.
bondd 2015/03/04 20:45:30 See above comment - top and bottom padding are dif
283 contentWidth + [mainView contentViewMargins].width * 2.0,
284 dialogHeight)];
285 [self setView:mainView];
124 } 286 }
125 287
126 @end 288 @end
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698