blob: e64cc7e417bca6abb74624f4e3e70c6264805d85 [file] [log] [blame]
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/ntp/new_tab_page_bar.h"
#import <QuartzCore/QuartzCore.h>
#include <cmath>
#include "base/logging.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
#import "ios/chrome/browser/ui/ntp/new_tab_page_bar_button.h"
#import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
#import "ios/chrome/browser/ui/rtl_geometry.h"
#include "ios/chrome/browser/ui/ui_util.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h"
#import "ui/gfx/ios/NSString+CrStringDrawing.h"
#include "ui/gfx/scoped_ui_graphics_push_context_ios.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
const CGFloat kBarHeight = 48.0f;
const CGFloat kRegularLayoutButtonWidth = 168;
const int kOverlayViewColor = 0x5A7EF5;
const int kOverlayColorWidth = 98;
const int kNumberOfTabsIncognito = 2;
} // anonymous namespace
@interface NewTabPageBar () {
UIImageView* shadow_;
}
@property(nonatomic, readwrite, strong) NSArray* buttons;
@property(nonatomic, readwrite, strong) UIButton* popupButton;
- (void)setup;
- (void)calculateButtonWidth;
- (void)setupButton:(UIButton*)button;
- (BOOL)useIconsInButtons;
- (BOOL)showOverlay;
@end
@implementation NewTabPageBar {
// Which button is currently selected.
NSUInteger selectedIndex_;
// Don't allow tabbar animations on startup, only after first tap.
BOOL canAnimate_;
__weak id<NewTabPageBarDelegate> delegate_;
// Logo view, used to center the tab buttons.
UIImageView* logoView_;
// Overlay view, used to highlight the selected button.
UIImageView* overlayView_;
// Overlay view, used to highlight the selected button.
UIView* overlayColorView_;
// Width of a button.
CGFloat buttonWidth_;
// Percentage overlay sits over tab bar buttons.
CGFloat overlayPercentage_;
}
@synthesize items = items_;
@synthesize selectedIndex = selectedIndex_;
@synthesize popupButton = popupButton_;
@synthesize buttons = buttons_;
@synthesize delegate = delegate_;
@synthesize overlayPercentage = overlayPercentage_;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (id)initWithCoder:(NSCoder*)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
self.selectedIndex = NSNotFound;
canAnimate_ = NO;
self.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
self.autoresizesSubviews = YES;
self.backgroundColor = [UIColor clearColor];
if ([self showOverlay]) {
overlayView_ =
[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, buttonWidth_, 2)];
// Center |overlayColorView_| inside |overlayView_|.
CGFloat colorX = AlignValueToPixel((buttonWidth_ - kOverlayColorWidth) / 2);
overlayColorView_ = [[UIView alloc]
initWithFrame:CGRectMake(colorX, 0, kOverlayColorWidth, 2)];
[overlayColorView_
setBackgroundColor:UIColorFromRGB(kOverlayViewColor, 1.0)];
[overlayColorView_ layer].cornerRadius = 1.0;
[overlayColorView_
setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin];
[overlayView_ addSubview:overlayColorView_];
[self addSubview:overlayView_];
}
// Make the drop shadow.
UIImage* shadowImage = [UIImage imageNamed:@"ntp_bottom_bar_shadow"];
shadow_ = [[UIImageView alloc] initWithImage:shadowImage];
// Shadow is positioned directly above the new tab page bar.
[shadow_
setFrame:CGRectMake(0, -shadowImage.size.height, self.bounds.size.width,
shadowImage.size.height)];
[shadow_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[self addSubview:shadow_];
self.contentMode = UIViewContentModeRedraw;
}
- (void)layoutSubviews {
[super layoutSubviews];
// |buttonWidth_| changes with the screen orientation when the NTP button bar
// is enabled.
[self calculateButtonWidth];
CGFloat logoWidth = logoView_.image.size.width;
CGFloat padding = [self useIconsInButtons] ? logoWidth : 0;
CGFloat buttonPadding = floor((CGRectGetWidth(self.bounds) - padding -
buttonWidth_ * self.buttons.count) /
2 +
padding);
for (NSUInteger i = 0; i < self.buttons.count; ++i) {
NewTabPageBarButton* button = [self.buttons objectAtIndex:i];
LayoutRect layout = LayoutRectMake(
buttonPadding + (i * buttonWidth_), CGRectGetWidth(self.bounds), 0,
buttonWidth_, CGRectGetHeight(self.bounds));
button.frame = LayoutRectGetRect(layout);
[button
setContentToDisplay:[self useIconsInButtons]
? new_tab_page_bar_button::ContentType::IMAGE
: new_tab_page_bar_button::ContentType::TEXT];
}
// Position overlay image over percentage of tab bar button(s).
CGRect frame = [overlayView_ frame];
frame.origin.x = floor(
buttonWidth_ * self.buttons.count * overlayPercentage_ + buttonPadding);
frame.size.width = buttonWidth_;
DCHECK(!std::isnan(frame.origin.x));
DCHECK(!std::isnan(frame.size.width));
[overlayView_ setFrame:frame];
}
- (CGSize)sizeThatFits:(CGSize)size {
return CGSizeMake(size.width, kBarHeight);
}
- (void)calculateButtonWidth {
if ([self useIconsInButtons]) {
if ([items_ count] > 0) {
buttonWidth_ = self.bounds.size.width / [items_ count];
} else {
// In incognito on phones, there are no items shown.
buttonWidth_ = 0;
}
return;
}
buttonWidth_ = kRegularLayoutButtonWidth;
}
// When setting a new set of items on the tab bar, the buttons need to be
// regenerated and the old buttons need to be removed.
- (void)setItems:(NSArray*)newItems {
if (newItems == items_)
return;
items_ = newItems;
// Remove all the existing buttons from the view.
for (UIButton* button in self.buttons) {
[button removeFromSuperview];
}
// Create a set of new buttons.
[self calculateButtonWidth];
if (newItems.count) {
NSMutableArray* newButtons = [NSMutableArray array];
for (NSUInteger i = 0; i < newItems.count; ++i) {
NewTabPageBarItem* item = [newItems objectAtIndex:i];
NewTabPageBarButton* button = [NewTabPageBarButton buttonWithItem:item];
button.frame = CGRectIntegral(CGRectMake(
i * buttonWidth_, 0, buttonWidth_, self.bounds.size.height));
[self setupButton:button];
[self addSubview:button];
[newButtons addObject:button];
}
self.buttons = newButtons;
} else {
self.buttons = nil;
}
[self setNeedsLayout];
}
- (void)setOverlayPercentage:(CGFloat)overlayPercentage {
DCHECK(!std::isnan(overlayPercentage));
overlayPercentage_ = overlayPercentage;
[self setNeedsLayout];
}
- (void)setupButton:(UIButton*)button {
// Old NTP tab bar buttons have a non-standard control event for firing
// actions. Because they are tied to a scrollView that reacts immediately,
// and on phone there is a tooltip that fires on touchdown that needs to
// display while on the new tab, the control event for -buttonDidTap is touch
// down. On phone with dialogs enabled, treat the NTP buttons as normal
// buttons, where the standard is to fire an action on touch up inside.
if ([self showOverlay]) {
[button addTarget:self
action:@selector(buttonDidTap:)
forControlEvents:UIControlEventTouchDown];
} else {
[button addTarget:self
action:@selector(buttonDidTap:)
forControlEvents:UIControlEventTouchUpInside];
}
}
- (void)setSelectedIndex:(NSUInteger)newIndex {
// When not showing the overlay, the Bookmarks and Recent Tabs are displayed
// in modal view controllers, so the tab bar buttons should not be selected.
if (![self showOverlay])
return;
if (newIndex != self.selectedIndex) {
if (newIndex < self.items.count) {
for (NSUInteger i = 0; i < self.buttons.count; ++i) {
UIButton* button = [self.buttons objectAtIndex:i];
button.selected = (i == newIndex);
}
}
selectedIndex_ = newIndex;
}
}
- (void)buttonDidTap:(UIButton*)button {
canAnimate_ = YES;
NSUInteger buttonIndex = [self.buttons indexOfObject:button];
if (buttonIndex != NSNotFound) {
self.selectedIndex = buttonIndex;
[delegate_ newTabBarItemDidChange:[self.items objectAtIndex:buttonIndex]
changePanel:YES];
}
}
- (void)setShadowAlpha:(CGFloat)alpha {
CGFloat currentAlpha = [shadow_ alpha];
CGFloat diff = std::abs(alpha - currentAlpha);
if (diff >= 1) {
[UIView animateWithDuration:0.3
animations:^{
[shadow_ setAlpha:alpha];
}];
} else {
[shadow_ setAlpha:alpha];
}
}
- (void)updateColorsForScrollView:(UIScrollView*)scrollView {
if (![self showOverlay]) {
return;
}
UIColor* backgroundViewColorBookmarks = [UIColor whiteColor];
CGFloat viewWidth = self.bounds.size.width;
CGFloat progress = LeadingContentOffsetForScrollView(scrollView) / viewWidth;
progress = fminf(progress, 1.0f);
progress = fmaxf(progress, 0.0f);
if ([self.items count] == kNumberOfTabsIncognito) {
UIColor* overlayViewColor = UIColorFromRGB(kOverlayViewColor, 1.0);
UIColor* overlayViewColorIncognito = [UIColor whiteColor];
UIColor* updatedOverlayColor = InterpolateFromColorToColor(
overlayViewColor, overlayViewColorIncognito, progress);
[overlayColorView_ setBackgroundColor:updatedOverlayColor];
UIColor* backgroundViewColorIncognito =
[UIColor colorWithWhite:34 / 255.0 alpha:1.0];
UIColor* backgroundColor = InterpolateFromColorToColor(
backgroundViewColorBookmarks, backgroundViewColorIncognito, progress);
self.backgroundColor = backgroundColor;
scrollView.backgroundColor = backgroundColor;
for (NewTabPageBarButton* button in self.buttons) {
[button useIncognitoColorScheme:progress];
}
} else {
UIColor* backgroundColor = backgroundViewColorBookmarks;
self.backgroundColor = backgroundViewColorBookmarks;
scrollView.backgroundColor = backgroundColor;
}
}
- (BOOL)useIconsInButtons {
return !IsIPadIdiom() || IsCompactTablet();
}
- (BOOL)showOverlay {
// The bar buttons launch modal dialogs on tap on iPhone. Don't show overlay
// in this case.
return IsIPadIdiom();
}
@end