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