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

Side by Side Diff: ios/chrome/browser/ui/find_bar/find_bar_controller_ios.mm

Issue 2590473002: Upstream Chrome on iOS source code [5/11]. (Closed)
Patch Set: Created 4 years 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
(Empty)
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h"
6
7 #include "base/format_macros.h"
8 #include "base/i18n/rtl.h"
9 #include "base/ios/ios_util.h"
10 #include "base/mac/bundle_locations.h"
11 #include "base/mac/foundation_util.h"
12 #include "base/mac/objc_property_releaser.h"
13 #include "base/mac/scoped_nsobject.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "components/strings/grit/components_strings.h"
16 #import "ios/chrome/browser/find_in_page/find_in_page_controller.h"
17 #import "ios/chrome/browser/find_in_page/find_in_page_model.h"
18 #import "ios/chrome/browser/ui/UIView+SizeClassSupport.h"
19 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
20 #import "ios/chrome/browser/ui/find_bar/find_bar_view.h"
21 #include "ios/chrome/browser/ui/ui_util.h"
22 #include "ui/base/l10n/l10n_util_mac.h"
23 #include "ui/base/resource/resource_bundle.h"
24
25 NSString* const kFindInPageContainerViewId = @"kFindInPageContainerViewId";
26
27 namespace {
28
29 // Find Bar height.
30 // Right padding on iPad find bar.
31 const CGFloat kFindBarIPhoneHeight = 56;
32 const CGFloat kFindBarIPadHeight = 62;
33
34 // Find Bar animation drop down duration.
35 const CGFloat kAnimationDuration = 0.15;
36
37 // For the first |kSearchDelayChars| characters, delay by |kSearchLongDelay|
38 // For the remaining characters, delay by |kSearchShortDelay|.
39 const NSUInteger kSearchDelayChars = 3;
40 const NSTimeInterval kSearchLongDelay = 1.0;
41 const NSTimeInterval kSearchShortDelay = 0.100;
42
43 } // anonymous namespace
44
45 #pragma mark - FindBarControllerIOS
46
47 @interface FindBarControllerIOS ()<UITextFieldDelegate> {
48 base::mac::ObjCPropertyReleaser _propertyReleaser_FindInPageController;
49 }
50
51 // Set up iPad UI
52 - (void)setUpIPad;
53 // Set up iPhone UI
54 - (void)setUpIPhone;
55 // Animate find bar to iPad top right, or, when possible, to align find bar
56 // horizontally with |alignmentFrame|.
57 - (void)showIPadFindBarView:(BOOL)animate
58 intoView:(UIView*)parentView
59 withFrame:(CGRect)targetFrame
60 alignWithFrame:(CGRect)alignmentFrame
61 selectText:(BOOL)selectText;
62 // Animate find bar over iPhone toolbar.
63 - (void)showIPhoneFindBarView:(BOOL)animate
64 intoView:(UIView*)parentView
65 withFrame:(CGRect)targetFrame
66 selectText:(BOOL)selectText;
67 // Returns the appropriate variant of the image for |image_name| based on
68 // |_isIncognito| and device idiom.
69 - (UIImage*)imageWithName:(NSString*)image_name;
70 // Delay searching for the first |kSearchDelayChars| characters of a search term
71 // to give time for a user to type out a longer word. Short words are currently
72 // very inefficient and lock up the UIWebView.
73 - (void)editingChanged:(id)sender;
74 // Return the expected find bar height. This will include the status bar height
75 // when running iOS7 on an iPhone.
76 - (CGFloat)findBarHeight;
77 // Selects text in such way that selection menu does not appear and
78 // a11y label is read. When -[UITextField selectAll:] is used, iOS
79 // will read "Select All" instead of a11y label.
80 - (void)selectAllText;
81
82 // Redefined to be readwrite. This view acts as background for |findBarView| and
83 // contains it as a subview.
84 @property(nonatomic, readwrite, strong) UIView* view;
85 // The view containing all the buttons and textfields that is common between
86 // iPhone and iPad.
87 @property(nonatomic, retain) FindBarView* findBarView;
88 // Typing delay timer.
89 @property(nonatomic, retain) NSTimer* delayTimer;
90 // Yes if incognito.
91 @property(nonatomic, assign) BOOL isIncognito;
92 @end
93
94 @implementation FindBarControllerIOS
95
96 @synthesize view = _view;
97 @synthesize findBarView = _findBarView;
98 @synthesize delayTimer = _delayTimer;
99 @synthesize isIncognito = _isIncognito;
100
101 #pragma mark - Lifecycle
102
103 - (instancetype)initWithIncognito:(BOOL)isIncognito {
104 self = [super init];
105 if (self) {
106 _propertyReleaser_FindInPageController.Init(self,
107 [FindBarControllerIOS class]);
108 _isIncognito = isIncognito;
109 }
110 return self;
111 }
112
113 #pragma mark View Setup & Teardown
114
115 - (UIView*)newFindBarView {
116 BOOL isIPad = IsIPadIdiom();
117 UIView* findBarBackground = nil;
118 if (isIPad) {
119 // Future self.view. Contains only |contentView|. Is an image view that is
120 // typecast elsewhere but always is exposed as a UIView.
121 findBarBackground =
122 [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 345, 62)];
123 findBarBackground.backgroundColor = [UIColor clearColor];
124 findBarBackground.userInteractionEnabled = YES;
125 } else {
126 findBarBackground =
127 [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 56)];
128 findBarBackground.backgroundColor = [UIColor whiteColor];
129 }
130
131 self.findBarView = [[[FindBarView alloc]
132 initWithDarkAppearance:self.isIncognito && !IsIPadIdiom()] autorelease];
133 [findBarBackground addSubview:self.findBarView];
134 self.findBarView.translatesAutoresizingMaskIntoConstraints = NO;
135 base::scoped_nsobject<NSMutableArray> constraints(
136 [[NSMutableArray alloc] init]);
137 [constraints addObjectsFromArray:@[
138 [self.findBarView.trailingAnchor
139 constraintEqualToAnchor:findBarBackground.trailingAnchor],
140 [self.findBarView.leadingAnchor
141 constraintEqualToAnchor:findBarBackground.leadingAnchor],
142 [self.findBarView.heightAnchor constraintEqualToConstant:56.0f]
143 ]];
144
145 if (isIPad) {
146 [constraints
147 addObject:[self.findBarView.centerYAnchor
148 constraintEqualToAnchor:findBarBackground.centerYAnchor
149 constant:-2]];
150 } else {
151 [constraints
152 addObject:[self.findBarView.bottomAnchor
153 constraintEqualToAnchor:findBarBackground.bottomAnchor]];
154 }
155
156 [NSLayoutConstraint activateConstraints:constraints];
157
158 self.findBarView.inputField.delegate = self;
159 [self.findBarView.inputField addTarget:self
160 action:@selector(editingChanged:)
161 forControlEvents:UIControlEventEditingChanged];
162 [self.findBarView.nextButton addTarget:self
163 action:@selector(hideKeyboard:)
164 forControlEvents:UIControlEventTouchUpInside];
165 [self.findBarView.previousButton addTarget:self
166 action:@selector(hideKeyboard:)
167 forControlEvents:UIControlEventTouchUpInside];
168
169 return findBarBackground;
170 }
171
172 - (void)setupViewInView:(UIView*)view {
173 self.view = [[self newFindBarView] autorelease];
174
175 // Idiom specific setup.
176 if ([self shouldShowCompactSearchBarInView:view])
177 [self setUpIPhone];
178 else
179 [self setUpIPad];
180
181 self.view.accessibilityIdentifier = kFindInPageContainerViewId;
182 }
183
184 - (void)teardownView {
185 [self.view removeFromSuperview];
186 self.view = nil;
187 }
188
189 - (void)setUpIPhone {
190 CGRect frame = self.view.frame;
191 frame.size.height = [self findBarHeight];
192 self.view.frame = frame;
193
194 if (self.isIncognito) {
195 [self.view setBackgroundColor:[UIColor colorWithWhite:115 / 255.0 alpha:1]];
196 }
197 }
198
199 - (void)setUpIPad {
200 self.view.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
201 UIEdgeInsets backgroundInsets = UIEdgeInsetsMake(6, 9, 10, 8);
202 UIImage* bgImage = [UIImage imageNamed:@"find_bg"];
203 bgImage = [bgImage resizableImageWithCapInsets:backgroundInsets];
204 UIImageView* bgView = (UIImageView*)self.view;
205 [bgView setImage:bgImage];
206 }
207
208 #pragma mark - Public
209
210 - (NSString*)searchTerm {
211 return [self.findBarView.inputField text];
212 }
213
214 - (BOOL)isFindInPageShown {
215 return self.view != nil;
216 }
217
218 - (BOOL)isFocused {
219 return [self.findBarView.inputField isFirstResponder];
220 }
221
222 - (void)updateResultsCount:(FindInPageModel*)model {
223 [self updateWithMatchNumber:model.currentIndex
224 matchCount:model.matches
225 searchText:model.text];
226 }
227
228 - (void)updateView:(FindInPageModel*)model
229 initialUpdate:(BOOL)initialUpdate
230 focusTextfield:(BOOL)focusTextfield {
231 [self.delayTimer invalidate];
232 self.delayTimer = nil;
233
234 if (initialUpdate) {
235 // Set initial text and first search.
236 [self.findBarView.inputField setText:model.text];
237 [self editingChanged:self.findBarView.inputField];
238 }
239
240 // Focus input field if necessary.
241 if (focusTextfield) {
242 [self.findBarView.inputField becomeFirstResponder];
243 } else {
244 [self.findBarView.inputField resignFirstResponder];
245 }
246
247 [self updateWithMatchNumber:model.currentIndex
248 matchCount:model.matches
249 searchText:model.text];
250 }
251
252 - (void)updateWithMatchNumber:(NSUInteger)matchNumber
253 matchCount:(NSUInteger)matchCount
254 searchText:(NSString*)searchText {
255 NSString* text = nil;
256 if (searchText.length != 0) {
257 NSString* indexStr = [NSString stringWithFormat:@"%" PRIdNS, matchNumber];
258 NSString* matchesStr = [NSString stringWithFormat:@"%" PRIdNS, matchCount];
259 text = l10n_util::GetNSStringF(IDS_FIND_IN_PAGE_COUNT,
260 base::SysNSStringToUTF16(indexStr),
261 base::SysNSStringToUTF16(matchesStr));
262 }
263 [self.findBarView updateResultsLabelWithText:text];
264
265 BOOL enabled = matchCount != 0;
266 self.findBarView.nextButton.enabled = enabled;
267 self.findBarView.previousButton.enabled = enabled;
268 }
269
270 - (void)addFindBarView:(BOOL)animate
271 intoView:(UIView*)view
272 withFrame:(CGRect)frame
273 alignWithFrame:(CGRect)omniboxFrame
274 selectText:(BOOL)selectText {
275 // If already showing find bar, nothing to do.
276 if (self.view) {
277 return;
278 }
279 if ([self shouldShowCompactSearchBarInView:view]) {
280 [self showIPhoneFindBarView:animate
281 intoView:view
282 withFrame:frame
283 selectText:selectText];
284 } else {
285 [self showIPadFindBarView:animate
286 intoView:view
287 withFrame:frame
288 alignWithFrame:omniboxFrame
289 selectText:selectText];
290 }
291 }
292
293 - (void)hideFindBarView:(BOOL)animate {
294 // If view is nil, nothing to hide.
295 if (!self.view) {
296 return;
297 }
298
299 self.findBarView.inputField.selectedTextRange = nil;
300 [self.delayTimer invalidate];
301 self.delayTimer = nil;
302
303 if (animate) {
304 [UIView animateWithDuration:kAnimationDuration
305 animations:^{
306 CGRect frame = self.view.frame;
307 frame.size.height = 0;
308 self.view.frame = frame;
309 }
310 completion:^(BOOL finished) {
311 [self teardownView];
312 }];
313 } else {
314 [self teardownView];
315 }
316 }
317
318 - (void)hideKeyboard:(id)sender {
319 [self.view endEditing:YES];
320 }
321
322 - (UIImage*)imageWithName:(NSString*)imageName {
323 NSString* name = !IsIPadIdiom() && self.isIncognito
324 ? [imageName stringByAppendingString:@"_incognito"]
325 : imageName;
326 return [UIImage imageNamed:name];
327 }
328
329 #pragma mark - Internal
330
331 - (void)selectAllText {
332 UITextRange* wholeTextRange = [self.findBarView.inputField
333 textRangeFromPosition:self.findBarView.inputField.beginningOfDocument
334 toPosition:self.findBarView.inputField.endOfDocument];
335 self.findBarView.inputField.selectedTextRange = wholeTextRange;
336 }
337
338 - (BOOL)shouldShowCompactSearchBarInView:(UIView*)view {
339 return !IsIPadIdiom();
340 }
341
342 // Animate find bar to iPad top right.
343 - (void)showIPadFindBarView:(BOOL)animate
344 intoView:(UIView*)parentView
345 withFrame:(CGRect)targetFrame
346 alignWithFrame:(CGRect)omniboxFrame
347 selectText:(BOOL)selectText {
348 DCHECK(IsIPadIdiom());
349 [self setupViewInView:parentView];
350 UIView* view = self.view;
351 CGRect frame = view.frame;
352 frame.size.width =
353 MIN(CGRectGetWidth(parentView.bounds), CGRectGetWidth(frame));
354 frame.origin.y = targetFrame.origin.y;
355 frame.size.height = 0;
356
357 CGFloat containerWidth = parentView.bounds.size.width;
358 CGFloat nibWidth = frame.size.width;
359
360 // On iPad, there are three possible frames for the Search bar:
361 // 1. In Regular width size class, it is short, right-aligned to the omnibox's
362 // right edge.
363 // 2. In Compact size class, if the short bar width is less than the omnibox,
364 // stretch and align the search bar to the omnibox.
365 // 3. Finally, if the short bar width is more than the omnibox, fill the
366 // container view from edge to edge, ignoring the omnibox.
367 if (view.cr_widthSizeClass == REGULAR) {
368 if (base::i18n::IsRTL()) {
369 frame.origin.x = CGRectGetMinX(omniboxFrame);
370 } else {
371 frame.origin.x =
372 CGRectGetMinX(omniboxFrame) + CGRectGetWidth(omniboxFrame) - nibWidth;
373 }
374 frame.size.width = nibWidth;
375 } else {
376 // Compact size class.
377 if (omniboxFrame.size.width > nibWidth) {
378 frame.origin.x = omniboxFrame.origin.x;
379 frame.size.width = omniboxFrame.size.width;
380 } else {
381 frame.origin.x = 0;
382 frame.size.width = containerWidth;
383 }
384 }
385
386 view.frame = frame;
387 [parentView addSubview:view];
388
389 CGFloat duration = (animate) ? kAnimationDuration : 0;
390 [UIView animateWithDuration:duration
391 animations:^{
392 CGRect frame = view.frame;
393 frame.size.height = [self findBarHeight];
394 view.frame = frame;
395 }
396 completion:^(BOOL finished) {
397 if (selectText)
398 [self selectAllText];
399 }];
400 }
401
402 // Animate find bar over iPhone toolbar.
403 - (void)showIPhoneFindBarView:(BOOL)animate
404 intoView:(UIView*)parentView
405 withFrame:(CGRect)targetFrame
406 selectText:(BOOL)selectText {
407 [self setupViewInView:parentView];
408 UIView* view = self.view;
409 CGRect frame = view.frame;
410 frame.size.width = targetFrame.size.width;
411 frame.origin.y = 0 - frame.size.height;
412 frame.origin.x = 0;
413 view.frame = frame;
414 [parentView addSubview:view];
415
416 CGFloat duration = (animate) ? kAnimationDuration : 0;
417 [UIView animateWithDuration:duration
418 animations:^{
419 CGRect frame = view.frame;
420 frame.origin.y = 0;
421 view.frame = frame;
422 }
423 completion:^(BOOL finished) {
424 if (selectText)
425 [self selectAllText];
426 }];
427 }
428
429 - (void)textChanged {
430 [self.view chromeExecuteCommand:self.findBarView.inputField];
431 }
432
433 - (void)editingChanged:(id)sender {
434 [self.delayTimer invalidate];
435 NSUInteger length = [[self searchTerm] length];
436 if (length == 0)
437 return [self textChanged];
438
439 // Delay delivery of text change event. Use a longer delay when the input
440 // length is short.
441 NSTimeInterval delay =
442 (length > kSearchDelayChars) ? kSearchShortDelay : kSearchLongDelay;
443 self.delayTimer =
444 [NSTimer scheduledTimerWithTimeInterval:delay
445 target:self
446 selector:@selector(textChanged)
447 userInfo:nil
448 repeats:NO];
449 }
450
451 - (CGFloat)findBarHeight {
452 if (IsIPadIdiom())
453 return kFindBarIPadHeight;
454 return StatusBarHeight() + kFindBarIPhoneHeight;
455 }
456
457 #pragma mark - UITextFieldDelegate
458
459 - (BOOL)textFieldShouldBeginEditing:(UITextField*)textField {
460 DCHECK(textField == self.findBarView.inputField);
461 [[NSNotificationCenter defaultCenter]
462 postNotificationName:kFindBarTextFieldWillBecomeFirstResponderNotification
463 object:self];
464 return YES;
465 }
466
467 - (void)textFieldDidEndEditing:(UITextField*)textField {
468 DCHECK(textField == self.findBarView.inputField);
469 [[NSNotificationCenter defaultCenter]
470 postNotificationName:kFindBarTextFieldDidResignFirstResponderNotification
471 object:self];
472 }
473
474 - (BOOL)textFieldShouldReturn:(UITextField*)textField {
475 DCHECK(textField == self.findBarView.inputField);
476 [self.findBarView.inputField resignFirstResponder];
477 return YES;
478 }
479
480 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h ('k') | ios/chrome/browser/ui/find_bar/find_bar_text_field.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698