OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 #import "ios/chrome/browser/ui/toolbar/keyboard_accessory_view.h" | 5 #import "ios/chrome/browser/ui/toolbar/keyboard_accessory_view.h" |
6 | 6 |
7 #import <NotificationCenter/NotificationCenter.h> | |
8 | |
7 #include "base/mac/foundation_util.h" | 9 #include "base/mac/foundation_util.h" |
10 #include "ios/chrome/browser/experimental_flags.h" | |
8 #include "ios/chrome/browser/ui/commands/ios_command_ids.h" | 11 #include "ios/chrome/browser/ui/commands/ios_command_ids.h" |
12 #import "ios/chrome/browser/ui/fancy_ui/colored_button.h" | |
13 #include "ios/chrome/browser/ui/rtl_geometry.h" | |
9 #include "ios/chrome/browser/ui/ui_util.h" | 14 #include "ios/chrome/browser/ui/ui_util.h" |
10 #import "ios/chrome/browser/ui/uikit_ui_util.h" | 15 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
11 #include "ios/chrome/grit/ios_strings.h" | 16 #include "ios/chrome/grit/ios_strings.h" |
12 | 17 |
13 #if !defined(__has_feature) || !__has_feature(objc_arc) | 18 #if !defined(__has_feature) || !__has_feature(objc_arc) |
14 #error "This file requires ARC support." | 19 #error "This file requires ARC support." |
15 #endif | 20 #endif |
16 | 21 |
17 @interface KeyboardAccessoryView () | 22 @interface KeyboardAccessoryView () |
18 | 23 |
19 @property(nonatomic, weak) id<KeyboardAccessoryViewDelegate> delegate; | 24 @property(nonatomic, weak) id<KeyboardAccessoryViewDelegate> delegate; |
20 @property(nonatomic, retain) UIButton* voiceSearchButton; | 25 @property(nonatomic, retain) UIButton* voiceSearchButton; |
21 | 26 |
22 // Creates a button with the same appearance as a keyboard key. | 27 // Creates a button with the same appearance as a keyboard key. |
23 - (UIView*)keyboardButtonWithTitle:(NSString*)title frame:(CGRect)frame; | 28 - (UIView*)keyboardButtonWithTitle:(NSString*)title frame:(CGRect)frame; |
29 // Creates a button shortcut for |title|. | |
30 - (UIView*)newShortcutButtonWithTitle:(NSString*)title; | |
31 // Creates a button with an icon based on |iconName|. | |
32 - (UIButton*)newIconButton:(NSString*)iconName; | |
24 // Called when a keyboard shortcut button is pressed. | 33 // Called when a keyboard shortcut button is pressed. |
25 - (void)keyboardButtonPressed:(NSString*)title; | 34 - (void)keyboardButtonPressed:(NSString*)title; |
26 | 35 |
27 @end | 36 @end |
28 | 37 |
29 @implementation KeyboardAccessoryView | 38 @implementation KeyboardAccessoryView |
30 | 39 |
31 @synthesize mode = _mode; | 40 @synthesize mode = _mode; |
32 @synthesize delegate = _delegate; | 41 @synthesize delegate = _delegate; |
33 @synthesize voiceSearchButton = _voiceSearchButton; | 42 @synthesize voiceSearchButton = _voiceSearchButton; |
34 | 43 |
35 - (instancetype)initWithButtons:(NSArray<NSString*>*)buttonTitles | 44 - (instancetype)initWithButtons:(NSArray<NSString*>*)buttonTitles |
36 delegate:(id<KeyboardAccessoryViewDelegate>)delegate { | 45 delegate:(id<KeyboardAccessoryViewDelegate>)delegate { |
37 const CGFloat kViewHeight = 70.0; | 46 const CGFloat kViewHeight = 70.0; |
38 const CGFloat kViewHeightCompact = 43.0; | 47 const CGFloat kViewHeightCompact = 43.0; |
39 const CGFloat kButtonInset = 5.0; | |
40 const CGFloat kButtonSizeX = 61.0; | |
41 const CGFloat kButtonSizeXCompact = 46.0; | |
42 const CGFloat kButtonSizeY = 62.0; | |
43 const CGFloat kButtonSizeYCompact = 35.0; | |
44 const CGFloat kBetweenButtonSpacing = 15.0; | |
45 const CGFloat kBetweenButtonSpacingCompact = 7.0; | |
46 const BOOL isCompact = IsCompact(); | 48 const BOOL isCompact = IsCompact(); |
47 | 49 |
48 CGFloat width = [[UIScreen mainScreen] bounds].size.width; | 50 CGFloat width = [[UIScreen mainScreen] bounds].size.width; |
49 CGFloat height = isCompact ? kViewHeightCompact : kViewHeight; | 51 CGFloat height = isCompact ? kViewHeightCompact : kViewHeight; |
50 CGRect frame = CGRectMake(0.0, 0.0, width, height); | 52 CGRect frame = CGRectMake(0.0, 0.0, width, height); |
51 | 53 |
52 self = [super initWithFrame:frame inputViewStyle:UIInputViewStyleKeyboard]; | 54 self = [super initWithFrame:frame inputViewStyle:UIInputViewStyleKeyboard]; |
53 if (self) { | 55 if (self) { |
54 _delegate = delegate; | 56 _delegate = delegate; |
57 if (experimental_flags::IsNewKeyboardAccessoryViewEnabled()) { | |
gambard
2017/06/09 12:35:42
This is a >160 lines methods. Maybe we can split i
jif
2017/06/09 13:19:37
Done.
| |
58 const CGFloat kButtonMinSizeX = 61.0; | |
59 const CGFloat kButtonMinSizeXCompact = 32.0; | |
60 const CGFloat kButtonSizeY = 62.0; | |
61 const CGFloat kButtonSizeYCompact = 30.0; | |
62 const CGFloat kBetweenButtonSpacing = 15.0; | |
63 const CGFloat kBetweenButtonSpacingCompact = 6.0; | |
64 const CGFloat kSeparatorAlpha = 0.1; | |
55 | 65 |
56 // Center buttons in available space by placing them within a parent view | 66 // Create stackview filled with the shortcut buttons |
57 // that auto-centers. | 67 UIStackView* stackView = [[UIStackView alloc] init]; |
58 CGFloat betweenButtonSpacing = | 68 [stackView setTranslatesAutoresizingMaskIntoConstraints:NO]; |
59 isCompact ? kBetweenButtonSpacingCompact : kBetweenButtonSpacing; | 69 stackView.spacing = |
60 const CGFloat buttonWidth = isCompact ? kButtonSizeXCompact : kButtonSizeX; | 70 isCompact ? kBetweenButtonSpacingCompact : kBetweenButtonSpacing; |
71 for (NSString* title in buttonTitles) { | |
72 UIView* button = [self newShortcutButtonWithTitle:title]; | |
73 [button setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
74 CGFloat buttonMinWidth = | |
75 isCompact ? kButtonMinSizeXCompact : kButtonMinSizeX; | |
76 [button.widthAnchor | |
77 constraintGreaterThanOrEqualToConstant:buttonMinWidth] | |
78 .active = YES; | |
79 CGFloat buttonHeight = isCompact ? kButtonSizeYCompact : kButtonSizeY; | |
80 [button.heightAnchor constraintEqualToConstant:buttonHeight].active = | |
81 YES; | |
82 [stackView addArrangedSubview:button]; | |
83 } | |
84 [self addSubview:stackView]; | |
61 | 85 |
62 CGFloat totalWidth = (buttonTitles.count * buttonWidth) + | 86 // Create and add image for camera search. |
63 ((buttonTitles.count - 1) * betweenButtonSpacing); | 87 UIButton* cameraButton = |
64 CGFloat indent = floor((width - totalWidth) / 2.0); | 88 [self newIconButton:@"qr_scanner_keyboard_accessory"]; |
65 if (indent < kButtonInset) | 89 [cameraButton |
66 indent = kButtonInset; | 90 addTarget:delegate |
67 CGRect parentViewRect = CGRectMake(indent, 0.0, totalWidth, height); | 91 action:@selector(keyboardAccessoryCameraSearchTouchUpInside) |
68 UIView* parentView = [[UIView alloc] initWithFrame:parentViewRect]; | 92 forControlEvents:UIControlEventTouchUpInside]; |
69 [parentView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | | 93 [self addSubview:cameraButton]; |
70 UIViewAutoresizingFlexibleRightMargin]; | |
71 [self addSubview:parentView]; | |
72 | 94 |
73 // Create the shortcut buttons, starting at the left edge of |parentView|. | 95 _voiceSearchButton = |
74 CGRect currentFrame = | 96 [self newIconButton:@"voice_icon_keyboard_accessory"]; |
75 CGRectMake(0.0, kButtonInset, buttonWidth, | 97 [self addSubview:_voiceSearchButton]; |
76 isCompact ? kButtonSizeYCompact : kButtonSizeY); | 98 [_voiceSearchButton |
99 addTarget:delegate | |
100 action:@selector(keyboardAccessoryVoiceSearchTouchDown) | |
101 forControlEvents:UIControlEventTouchDown]; | |
102 [_voiceSearchButton | |
103 addTarget:delegate | |
104 action:@selector(keyboardAccessoryVoiceSearchTouchUpInside) | |
105 forControlEvents:UIControlEventTouchUpInside]; | |
77 | 106 |
78 for (NSString* title in buttonTitles) { | 107 // Create separator |
79 UIView* button = [self keyboardButtonWithTitle:title frame:currentFrame]; | 108 UIView* separator = [[UIView alloc] init]; |
80 [parentView addSubview:button]; | 109 [separator setTranslatesAutoresizingMaskIntoConstraints:NO]; |
81 currentFrame.origin.x = | 110 [separator |
82 CGRectGetMaxX(currentFrame) + betweenButtonSpacing; | 111 setBackgroundColor:[UIColor colorWithWhite:0 alpha:kSeparatorAlpha]]; |
112 [separator.heightAnchor | |
113 constraintEqualToConstant:1.0 / [[UIScreen mainScreen] scale]] | |
114 .active = YES; | |
115 [self addSubview:separator]; | |
116 | |
117 // Position all the views. | |
118 NSDictionary* viewsDictionary = @{ | |
119 @"cameraButton" : cameraButton, | |
120 @"voiceSearch" : _voiceSearchButton, | |
121 @"stackView" : stackView, | |
122 @"separator" : separator, | |
123 }; | |
124 NSArray* constraints = @[ | |
125 @"H:|-8-[cameraButton]-8-[voiceSearch]-(>=16)-[stackView]", | |
126 @"H:|-0-[separator]-0-|", | |
127 @"V:[separator]-0-|", | |
128 ]; | |
129 ApplyVisualConstraintsWithOptions(constraints, viewsDictionary, | |
130 LayoutOptionForRTLSupport(), self); | |
131 AddSameCenterYConstraint(self, cameraButton); | |
132 AddSameCenterYConstraint(self, _voiceSearchButton); | |
133 AddSameCenterYConstraint(self, stackView); | |
134 | |
135 NSLayoutConstraint* horizontallyCenterStackViewConstraint = | |
136 [self.centerXAnchor constraintEqualToAnchor:stackView.centerXAnchor]; | |
137 horizontallyCenterStackViewConstraint.priority = | |
138 UILayoutPriorityDefaultHigh; | |
139 horizontallyCenterStackViewConstraint.active = YES; | |
140 } else { | |
141 const CGFloat kButtonInset = 5.0; | |
142 const CGFloat kButtonSizeX = 61.0; | |
143 const CGFloat kButtonSizeXCompact = 46.0; | |
144 const CGFloat kButtonSizeY = 62.0; | |
145 const CGFloat kButtonSizeYCompact = 35.0; | |
146 const CGFloat kBetweenButtonSpacing = 15.0; | |
147 const CGFloat kBetweenButtonSpacingCompact = 7.0; | |
148 | |
149 // Center buttons in available space by placing them within a parent view | |
150 // that auto-centers. | |
151 CGFloat betweenButtonSpacing = | |
152 isCompact ? kBetweenButtonSpacingCompact : kBetweenButtonSpacing; | |
153 const CGFloat buttonWidth = | |
154 isCompact ? kButtonSizeXCompact : kButtonSizeX; | |
155 | |
156 CGFloat totalWidth = (buttonTitles.count * buttonWidth) + | |
157 ((buttonTitles.count - 1) * betweenButtonSpacing); | |
158 CGFloat indent = floor((width - totalWidth) / 2.0); | |
159 if (indent < kButtonInset) | |
160 indent = kButtonInset; | |
161 CGRect parentViewRect = CGRectMake(indent, 0.0, totalWidth, height); | |
162 UIView* parentView = [[UIView alloc] initWithFrame:parentViewRect]; | |
163 [parentView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | | |
164 UIViewAutoresizingFlexibleRightMargin]; | |
165 [self addSubview:parentView]; | |
166 | |
167 // Create the shortcut buttons, starting at the left edge of |parentView|. | |
168 CGRect currentFrame = | |
169 CGRectMake(0.0, kButtonInset, buttonWidth, | |
170 isCompact ? kButtonSizeYCompact : kButtonSizeY); | |
171 | |
172 for (NSString* title in buttonTitles) { | |
173 UIView* button = | |
174 [self keyboardButtonWithTitle:title frame:currentFrame]; | |
175 [parentView addSubview:button]; | |
176 currentFrame.origin.x = | |
177 CGRectGetMaxX(currentFrame) + betweenButtonSpacing; | |
178 } | |
179 | |
180 // Create the voice search button and add it over the text buttons. | |
181 _voiceSearchButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
182 [_voiceSearchButton setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; | |
183 SetA11yLabelAndUiAutomationName( | |
184 _voiceSearchButton, IDS_IOS_ACCNAME_VOICE_SEARCH, @"Voice Search"); | |
185 UIImage* voiceRow = [UIImage imageNamed:@"custom_row_voice"]; | |
186 UIImage* voiceRowPressed = | |
187 [UIImage imageNamed:@"custom_row_voice_pressed"]; | |
188 [_voiceSearchButton setBackgroundImage:voiceRow | |
189 forState:UIControlStateNormal]; | |
190 [_voiceSearchButton setBackgroundImage:voiceRowPressed | |
191 forState:UIControlStateHighlighted]; | |
192 | |
193 UIImage* voiceIcon = | |
194 [UIImage imageNamed:@"voice_icon_keyboard_accessory"]; | |
195 [_voiceSearchButton setAdjustsImageWhenHighlighted:NO]; | |
196 [_voiceSearchButton setImage:voiceIcon forState:UIControlStateNormal]; | |
197 [_voiceSearchButton setFrame:[self bounds]]; | |
198 [_voiceSearchButton | |
199 addTarget:delegate | |
200 action:@selector(keyboardAccessoryVoiceSearchTouchDown) | |
201 forControlEvents:UIControlEventTouchDown]; | |
202 [_voiceSearchButton | |
203 addTarget:delegate | |
204 action:@selector(keyboardAccessoryVoiceSearchTouchUpInside) | |
205 forControlEvents:UIControlEventTouchUpInside]; | |
206 [self addSubview:_voiceSearchButton]; | |
83 } | 207 } |
84 | |
85 // Create the voice search button and add it over the text buttons. | |
86 _voiceSearchButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
87 [_voiceSearchButton setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; | |
88 SetA11yLabelAndUiAutomationName( | |
89 _voiceSearchButton, IDS_IOS_ACCNAME_VOICE_SEARCH, @"Voice Search"); | |
90 UIImage* voiceRow = [UIImage imageNamed:@"custom_row_voice"]; | |
91 UIImage* voiceRowPressed = [UIImage imageNamed:@"custom_row_voice_pressed"]; | |
92 [_voiceSearchButton setBackgroundImage:voiceRow | |
93 forState:UIControlStateNormal]; | |
94 [_voiceSearchButton setBackgroundImage:voiceRowPressed | |
95 forState:UIControlStateHighlighted]; | |
96 | |
97 UIImage* voiceIcon = [UIImage imageNamed:@"voice_icon_keyboard_accessory"]; | |
98 [_voiceSearchButton setAdjustsImageWhenHighlighted:NO]; | |
99 [_voiceSearchButton setImage:voiceIcon forState:UIControlStateNormal]; | |
100 [_voiceSearchButton setFrame:[self bounds]]; | |
101 | |
102 [_voiceSearchButton | |
103 addTarget:delegate | |
104 action:@selector(keyboardAccessoryVoiceSearchTouchDown) | |
105 forControlEvents:UIControlEventTouchDown]; | |
106 [_voiceSearchButton | |
107 addTarget:delegate | |
108 action:@selector(keyboardAccessoryVoiceSearchTouchUpInside) | |
109 forControlEvents:UIControlEventTouchUpInside]; | |
110 [self addSubview:_voiceSearchButton]; | |
111 } | 208 } |
112 | 209 |
113 return self; | 210 return self; |
114 } | 211 } |
115 | 212 |
116 - (void)setMode:(KeyboardAccessoryViewMode)mode { | 213 - (void)setMode:(KeyboardAccessoryViewMode)mode { |
214 if (experimental_flags::IsNewKeyboardAccessoryViewEnabled()) { | |
215 return; | |
216 } | |
117 _mode = mode; | 217 _mode = mode; |
118 switch (mode) { | 218 switch (mode) { |
119 case VOICE_SEARCH: | 219 case VOICE_SEARCH: |
120 [_voiceSearchButton setHidden:NO]; | 220 [_voiceSearchButton setHidden:NO]; |
121 break; | 221 break; |
122 case KEY_SHORTCUTS: | 222 case KEY_SHORTCUTS: |
123 [_voiceSearchButton setHidden:YES]; | 223 [_voiceSearchButton setHidden:YES]; |
124 break; | 224 break; |
125 } | 225 } |
126 } | 226 } |
(...skipping 18 matching lines...) Expand all Loading... | |
145 [button.titleLabel setFont:font]; | 245 [button.titleLabel setFont:font]; |
146 [button setBackgroundImage:backgroundImage forState:UIControlStateNormal]; | 246 [button setBackgroundImage:backgroundImage forState:UIControlStateNormal]; |
147 [button addTarget:self | 247 [button addTarget:self |
148 action:@selector(keyboardButtonPressed:) | 248 action:@selector(keyboardButtonPressed:) |
149 forControlEvents:UIControlEventTouchUpInside]; | 249 forControlEvents:UIControlEventTouchUpInside]; |
150 button.isAccessibilityElement = YES; | 250 button.isAccessibilityElement = YES; |
151 [button setAccessibilityLabel:title]; | 251 [button setAccessibilityLabel:title]; |
152 return button; | 252 return button; |
153 } | 253 } |
154 | 254 |
255 - (UIView*)newShortcutButtonWithTitle:(NSString*)title { | |
gambard
2017/06/09 12:35:42
Don't start method with new to avoid memory issue.
jif
2017/06/09 13:19:37
Good catch :-)
Done and done.
| |
256 const CGFloat kCornerRadius = 4.0; | |
257 const CGFloat kAlphaStateNormal = 0.1; | |
258 const CGFloat kAlphaStateHighlighted = 0.2; | |
259 const CGFloat kHorizontalEdgeInset = 8; | |
260 const CGFloat kIpadButtonTitleFontSize = 20.0; | |
261 const CGFloat kIphoneButtonTitleFontSize = 15.0; | |
262 | |
263 ColoredButton* button = [ColoredButton buttonWithType:UIButtonTypeCustom]; | |
264 UIFont* font = nil; | |
265 | |
266 [button setTitle:title forState:UIControlStateNormal]; | |
267 [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; | |
268 | |
269 [button setBackgroundColor:UIColorFromRGB(0, kAlphaStateNormal) | |
270 forState:UIControlStateNormal]; | |
271 [button setBackgroundColor:UIColorFromRGB(0, kAlphaStateHighlighted) | |
272 forState:UIControlStateHighlighted]; | |
273 | |
274 button.layer.cornerRadius = kCornerRadius; | |
275 button.contentEdgeInsets = | |
276 UIEdgeInsetsMake(0, kHorizontalEdgeInset, 0, kHorizontalEdgeInset); | |
277 button.clipsToBounds = YES; | |
278 | |
279 if (IsIPadIdiom()) { | |
280 font = GetUIFont(FONT_HELVETICA, false, kIpadButtonTitleFontSize); | |
281 } else { | |
282 font = GetUIFont(FONT_HELVETICA, true, kIphoneButtonTitleFontSize); | |
283 } | |
284 | |
285 [button.titleLabel setFont:font]; | |
286 | |
287 [button addTarget:self | |
288 action:@selector(keyboardButtonPressed:) | |
289 forControlEvents:UIControlEventTouchUpInside]; | |
290 button.isAccessibilityElement = YES; | |
291 [button setAccessibilityLabel:title]; | |
292 return button; | |
293 } | |
294 | |
295 - (UIButton*)newIconButton:(NSString*)iconName { | |
296 const CGFloat kIconTintAlphaStateNormal = 0.45; | |
297 const CGFloat kIconTintAlphaStateHighlighted = 0.6; | |
298 | |
299 UIColor* iconTintStateNormal = UIColorFromRGB(0, kIconTintAlphaStateNormal); | |
300 UIColor* iconTintStateHighlighted = | |
301 UIColorFromRGB(0, kIconTintAlphaStateHighlighted); | |
302 | |
303 ColoredButton* button = [ColoredButton buttonWithType:UIButtonTypeCustom]; | |
304 | |
305 [button setTintColor:iconTintStateNormal forState:UIControlStateNormal]; | |
306 [button setTintColor:iconTintStateHighlighted | |
307 forState:UIControlStateHighlighted]; | |
308 [button setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
309 UIImage* icon = [[UIImage imageNamed:iconName] | |
310 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; | |
311 [button setImage:icon forState:UIControlStateNormal]; | |
312 return button; | |
313 } | |
314 | |
155 - (BOOL)enableInputClicksWhenVisible { | 315 - (BOOL)enableInputClicksWhenVisible { |
156 return YES; | 316 return YES; |
157 } | 317 } |
158 | 318 |
159 - (void)keyboardButtonPressed:(id)sender { | 319 - (void)keyboardButtonPressed:(id)sender { |
160 UIButton* button = base::mac::ObjCCastStrict<UIButton>(sender); | 320 UIButton* button = base::mac::ObjCCastStrict<UIButton>(sender); |
161 [[UIDevice currentDevice] playInputClick]; | 321 [[UIDevice currentDevice] playInputClick]; |
162 [_delegate keyPressed:[button currentTitle]]; | 322 [_delegate keyPressed:[button currentTitle]]; |
163 } | 323 } |
164 | 324 |
165 @end | 325 @end |
OLD | NEW |