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

Side by Side Diff: ios/chrome/browser/ui/tab_switcher/tab_switcher_view.mm

Issue 2588733002: Upstream Chrome on iOS source code [9/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 2015 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/tab_switcher/tab_switcher_view.h"
6
7 #include "base/logging.h"
8 #include "base/mac/foundation_util.h"
9 #include "base/mac/scoped_nsobject.h"
10 #include "base/metrics/user_metrics.h"
11 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
12 #include "ios/chrome/browser/ui/rtl_geometry.h"
13 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_header_view.h"
14 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.h"
15 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.h"
16 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_view.h"
17 #include "ios/chrome/grit/ios_strings.h"
18 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate rialButtons.h"
19 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h"
20 #include "ui/base/l10n/l10n_util.h"
21
22 namespace {
23 const CGFloat kHeaderHeight = 95;
24 const CGFloat kNewTabButtonMarginFromEdges = 48;
25 const CGFloat kNewTabButtonWidth = 48;
26 }
27
28 @interface TabSwitcherView ()<UIScrollViewDelegate> {
29 base::scoped_nsobject<TabSwitcherHeaderView> _headerView;
30 base::scoped_nsobject<UIScrollView> _scrollView;
31 base::scoped_nsobject<MDCButton> _openNewTabButton;
32 base::scoped_nsobject<NSMutableArray> _panels;
33 ios_internal::NewTabButtonStyle _openNewTabButtonStyle;
34 NSInteger _previousPanelIndex;
35 }
36
37 // Returns the header view frame.
38 - (CGRect)headerViewFrame;
39 // Returns the scrollview frame.
40 - (CGRect)scrollViewFrame;
41 // Returns the new tab button frame.
42 - (CGRect)openNewTabButtonFrame;
43 // Returns the new tab button frame when hidden.
44 - (CGRect)openNewTabButtonFrameOffscreen;
45 // Called when the new tab button is pressed.
46 - (void)openNewTabButtonPressed;
47 // Returns the index of the panel presented in |_scrollview|. When two panels
48 // are visible, it returns the most visible one.
49 - (NSInteger)currentPageIndex;
50 // Select the panel at the given index, updating both the header and content.
51 // The scrollview scroll will be |animated| if requested.
52 - (void)selectPanelAtIndex:(NSInteger)index animated:(BOOL)animated;
53 @end
54
55 @implementation TabSwitcherView
56
57 @synthesize delegate = delegate_;
58
59 - (instancetype)initWithFrame:(CGRect)frame {
60 self = [super initWithFrame:frame];
61 if (self) {
62 _openNewTabButtonStyle = ios_internal::NewTabButtonStyle::UNINITIALIZED;
63 [self loadSubviews];
64 _panels.reset([[NSMutableArray alloc] init]);
65 _previousPanelIndex = -1;
66 }
67 return self;
68 }
69
70 - (TabSwitcherHeaderView*)headerView {
71 return _headerView;
72 }
73
74 - (UIScrollView*)scrollView {
75 return _scrollView;
76 }
77
78 - (void)layoutSubviews {
79 [super layoutSubviews];
80 NSInteger pageIndexBeforeLayout = [self currentPageIndex];
81 [CATransaction begin];
82 [CATransaction setDisableActions:YES];
83 [_headerView setFrame:[self headerViewFrame]];
84 [_scrollView setFrame:[self scrollViewFrame]];
85 [CATransaction commit];
86 [self updateScrollViewContent];
87 [self selectPanelAtIndex:pageIndexBeforeLayout animated:NO];
88 }
89
90 - (void)selectPanelAtIndex:(NSInteger)index {
91 [self selectPanelAtIndex:index animated:!UIAccessibilityIsVoiceOverRunning()];
92 }
93
94 - (void)addPanelView:(UIView*)view atIndex:(NSUInteger)index {
95 if (UseRTLLayout())
96 [view setTransform:CGAffineTransformMakeScale(-1, 1)];
97 [_scrollView addSubview:view];
98 [_panels insertObject:view atIndex:index];
99 [self updateScrollViewContent];
100 }
101
102 - (void)removePanelViewAtIndex:(NSUInteger)index {
103 [self removePanelViewAtIndex:index updateScrollView:YES];
104 }
105
106 - (void)removePanelViewAtIndex:(NSUInteger)index updateScrollView:(BOOL)update {
107 DCHECK_EQ([[_panels objectAtIndex:index] superview], _scrollView.get());
108 [[_panels objectAtIndex:index] removeFromSuperview];
109 [_panels removeObjectAtIndex:index];
110 if (update)
111 [self updateScrollViewContent];
112 }
113
114 - (NSInteger)currentPanelIndex {
115 return [self currentPageIndex];
116 }
117
118 - (void)updateOverlayButtonState {
119 NSInteger panelIndex = [self currentPageIndex];
120 ios_internal::NewTabButtonStyle newButtonStyle =
121 [delegate_ buttonStyleForPanelAtIndex:panelIndex];
122 [self setNewTabButtonStyle:newButtonStyle];
123 BOOL dismissButtonVisible =
124 [self.delegate shouldShowDismissButtonForPanelAtIndex:panelIndex];
125 [UIView beginAnimations:nil context:NULL];
126 [[_headerView dismissButton] setAlpha:dismissButtonVisible ? 1.0 : 0.0];
127 [UIView commitAnimations];
128 }
129
130 #pragma mark - Private
131
132 - (void)selectPanelAtIndex:(NSInteger)index animated:(BOOL)animated {
133 CGPoint pageOffset = CGPointZero;
134 pageOffset.x = self.bounds.size.width * index;
135 [_scrollView setContentOffset:pageOffset animated:animated];
136 [_headerView selectItemAtIndex:index];
137 UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,
138 nil);
139 }
140
141 - (NSInteger)currentPageIndex {
142 if ([_scrollView frame].size.width == 0)
143 return 0;
144 NSInteger index = floor(
145 [_scrollView contentOffset].x / [_scrollView frame].size.width + 0.5);
146 return std::max<NSInteger>(std::min<NSInteger>(index, [_panels count] - 1),
147 0);
148 }
149
150 - (void)updateHeaderSelection {
151 [_headerView selectItemAtIndex:[self currentPageIndex]];
152 }
153
154 - (CGRect)frameForPanelAtIndex:(NSInteger)index {
155 CGSize panelSize = [_scrollView frame].size;
156 CGRect panelFrame =
157 CGRectMake(panelSize.width * index, 0, panelSize.width, panelSize.height);
158 return panelFrame;
159 }
160
161 - (void)updateScrollViewContent {
162 CGSize panelSize = [_scrollView frame].size;
163 CGSize currentContentSize = [_scrollView contentSize];
164 currentContentSize.width = [_panels count] * panelSize.width;
165 [_scrollView setContentSize:currentContentSize];
166 for (NSUInteger i = 0; i < [_panels count]; i++) {
167 id panelView = [_panels objectAtIndex:i];
168 [panelView setFrame:[self frameForPanelAtIndex:i]];
169 }
170 }
171
172 - (void)loadSubviews {
173 // Creates and add the header view showing the list of panels.
174 base::scoped_nsobject<TabSwitcherHeaderView> headerView(
175 [[TabSwitcherHeaderView alloc] initWithFrame:[self headerViewFrame]]);
176 [self addSubview:headerView];
177 _headerView = headerView;
178
179 // Creates and add the scrollview containing the panels.
180 base::scoped_nsobject<UIScrollView> scrollView(
181 [[UIScrollView alloc] initWithFrame:[self scrollViewFrame]]);
182 [scrollView setBackgroundColor:[[MDCPalette greyPalette] tint900]];
183 [scrollView setAlwaysBounceHorizontal:YES];
184 [scrollView setDelegate:self];
185 [scrollView setPagingEnabled:YES];
186 [scrollView setDelegate:self];
187 if (UseRTLLayout())
188 [scrollView setTransform:CGAffineTransformMakeScale(-1, 1)];
189 [self addSubview:scrollView];
190 _scrollView = scrollView;
191
192 // Creates and add the floating new tab button.
193 _openNewTabButton.reset([[MDCFloatingButton alloc] init]);
194 UIImage* openNewTabButtonImage =
195 [[UIImage imageNamed:@"tabswitcher_new_tab_fab"]
196 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
197 [_openNewTabButton setImage:openNewTabButtonImage
198 forState:UIControlStateNormal];
199 [[_openNewTabButton imageView] setTintColor:[UIColor whiteColor]];
200 [_openNewTabButton setFrame:[self openNewTabButtonFrame]];
201 // When the button is positioned with autolayout, the animation of the
202 // button's position conflicts with other animations.
203 [_openNewTabButton
204 setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin |
205 UIViewAutoresizingFlexibleLeadingMargin()];
206 [_openNewTabButton addTarget:self
207 action:@selector(openNewTabButtonPressed)
208 forControlEvents:UIControlEventTouchUpInside];
209 [self addSubview:_openNewTabButton];
210 [self setNewTabButtonStyle:ios_internal::NewTabButtonStyle::GRAY];
211 }
212
213 - (CGRect)headerViewFrame {
214 const CGFloat kStatusBarHeight =
215 [[UIApplication sharedApplication] statusBarFrame].size.height;
216 CGRect headerViewFrame = self.bounds;
217 headerViewFrame.origin.y += kStatusBarHeight;
218 headerViewFrame.size.height = kHeaderHeight;
219 return headerViewFrame;
220 }
221
222 - (CGRect)scrollViewFrame {
223 CGRect scrollViewFrame = self.bounds;
224 scrollViewFrame.origin.y = CGRectGetMaxY([self headerViewFrame]);
225 scrollViewFrame.size.height -= scrollViewFrame.origin.y;
226 return scrollViewFrame;
227 }
228
229 - (CGRect)openNewTabButtonFrame {
230 CGRect buttonFrame = self.bounds;
231 buttonFrame.origin.y = self.bounds.size.height -
232 kNewTabButtonMarginFromEdges - kNewTabButtonWidth;
233 if (UseRTLLayout()) {
234 buttonFrame.origin.x = kNewTabButtonMarginFromEdges;
235 } else {
236 buttonFrame.origin.x = self.bounds.size.width -
237 kNewTabButtonMarginFromEdges - kNewTabButtonWidth;
238 }
239 buttonFrame.size.width = kNewTabButtonWidth;
240 buttonFrame.size.height = kNewTabButtonWidth;
241 return buttonFrame;
242 }
243
244 - (CGRect)openNewTabButtonFrameOffscreen {
245 CGRect buttonFrame = [self openNewTabButtonFrame];
246 buttonFrame.origin.y = self.bounds.size.height + kNewTabButtonWidth;
247 return buttonFrame;
248 }
249
250 - (void)openNewTabButtonPressed {
251 [self.delegate openNewTabInPanelAtIndex:[self currentPageIndex]];
252 }
253
254 - (void)setNewTabButtonStyle:(ios_internal::NewTabButtonStyle)newStyle {
255 if (newStyle == _openNewTabButtonStyle)
256 return;
257 _openNewTabButtonStyle = newStyle;
258 [UIView animateWithDuration:0.25
259 animations:^{
260 switch (_openNewTabButtonStyle) {
261 case ios_internal::NewTabButtonStyle::HIDDEN:
262 [_openNewTabButton setFrame:[self openNewTabButtonFrameOffscreen]];
263 break;
264 case ios_internal::NewTabButtonStyle::BLUE: {
265 [_openNewTabButton setFrame:[self openNewTabButtonFrame]];
266 MDCPalette* palette = [MDCPalette cr_bluePalette];
267 [_openNewTabButton
268 setInkColor:[[palette tint300] colorWithAlphaComponent:0.5f]];
269 [_openNewTabButton setBackgroundColor:[palette tint500]
270 forState:UIControlStateNormal];
271 [_openNewTabButton
272 setBackgroundColor:[UIColor colorWithWhite:0.8f alpha:1.0f]
273 forState:UIControlStateDisabled];
274 [_openNewTabButton
275 setAccessibilityLabel:l10n_util::GetNSString(
276 IDS_IOS_TAB_SWITCHER_CREATE_NEW_TAB)];
277 break;
278 }
279 case ios_internal::NewTabButtonStyle::GRAY: {
280 [_openNewTabButton setFrame:[self openNewTabButtonFrame]];
281 MDCPalette* palette = [MDCPalette greyPalette];
282 [_openNewTabButton
283 setInkColor:[[palette tint300] colorWithAlphaComponent:0.25f]];
284 [_openNewTabButton setBackgroundColor:[palette tint500]
285 forState:UIControlStateNormal];
286 [_openNewTabButton
287 setBackgroundColor:[UIColor colorWithWhite:0.8f alpha:1.0f]
288 forState:UIControlStateDisabled];
289 [_openNewTabButton
290 setAccessibilityLabel:
291 l10n_util::GetNSString(
292 IDS_IOS_TAB_SWITCHER_CREATE_NEW_INCOGNITO_TAB)];
293 break;
294 }
295 case ios_internal::NewTabButtonStyle::UNINITIALIZED:
296 NOTREACHED();
297 }
298 }
299 completion:^(BOOL finished) {
300 // Informs VoiceOver that the |_openNewTabButton| visibility may have
301 // changed.
302 UIAccessibilityPostNotification(
303 UIAccessibilityLayoutChangedNotification, nil);
304 }];
305 }
306
307 #pragma mark - UIScrollViewDelegate
308
309 - (void)scrollViewDidEndScrollingAnimation:(UIScrollView*)scrollView {
310 [self updateHeaderSelection];
311 }
312
313 - (void)scrollViewDidScroll:(UIScrollView*)scrollView {
314 if ([scrollView isDragging]) {
315 [self updateHeaderSelection];
316 }
317 [self updateOverlayButtonState];
318
319 NSInteger panelIndex = [self currentPanelIndex];
320 TabSwitcherPanelOverlayView* overlayView =
321 base::mac::ObjCCast<TabSwitcherPanelOverlayView>(
322 [_panels objectAtIndex:panelIndex]);
323 if (panelIndex != _previousPanelIndex && overlayView &&
324 [overlayView overlayType] ==
325 TabSwitcherPanelOverlayType::OVERLAY_PANEL_USER_SIGNED_OUT) {
326 base::RecordAction(
327 base::UserMetricsAction("Signin_Impression_FromTabSwitcher"));
328 }
329 _previousPanelIndex = panelIndex;
330 }
331
332 #pragma mark - UIScrollViewAccessibilityDelegate
333
334 - (NSString*)accessibilityScrollStatusForScrollView:(UIScrollView*)scrollView {
335 NSInteger panelIndex = [self currentPageIndex];
336 return [_headerView panelTitleAtIndex:panelIndex];
337 }
338
339 #pragma mark - UIAccessibilityAction
340
341 - (BOOL)accessibilityPerformEscape {
342 // If the Dismiss Button is visible, then the escape gesture triggers the
343 // dismissal of the tab switcher.
344 NSInteger panelIndex = [self currentPageIndex];
345 if ([self.delegate shouldShowDismissButtonForPanelAtIndex:panelIndex]) {
346 [delegate_ tabSwitcherViewDelegateDismissTabSwitcher:self];
347 return YES;
348 }
349 return NO;
350 }
351
352 - (BOOL)accessibilityPerformMagicTap {
353 // If the New Tab Button is visible, then the magic tap opens a new tab.
354 NSInteger panelIndex = [self currentPageIndex];
355 ios_internal::NewTabButtonStyle buttonStyle =
356 [delegate_ buttonStyleForPanelAtIndex:panelIndex];
357 switch (buttonStyle) {
358 case ios_internal::BLUE:
359 case ios_internal::GRAY:
360 [self.delegate openNewTabInPanelAtIndex:panelIndex];
361 return YES;
362 case ios_internal::UNINITIALIZED:
363 case ios_internal::HIDDEN:
364 return NO;
365 }
366 }
367
368 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/ui/tab_switcher/tab_switcher_view.h ('k') | ios/chrome/browser/ui/tabs/tab_strip_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698