blob: a84eeede175ba9f30cf6be95835bce6ed0bed407 [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_controller.h"
#import <QuartzCore/QuartzCore.h>
#include "base/logging.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "components/prefs/pref_service.h"
#include "components/search_engines/template_url_service.h"
#include "components/strings/grit/components_strings.h"
#include "components/sync_sessions/synced_session.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/pref_names.h"
#include "ios/chrome/browser/search_engines/template_url_service_factory.h"
#include "ios/chrome/browser/sync/sync_setup_service.h"
#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
#import "ios/chrome/browser/tabs/tab_model.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.h"
#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
#import "ios/chrome/browser/ui/ntp/google_landing_mediator.h"
#import "ios/chrome/browser/ui/ntp/google_landing_view_controller.h"
#import "ios/chrome/browser/ui/ntp/incognito_panel_controller.h"
#import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
#import "ios/chrome/browser/ui/ntp/new_tab_page_view.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_panel_controller.h"
#import "ios/chrome/browser/ui/rtl_geometry.h"
#include "ios/chrome/browser/ui/toolbar/toolbar_model_ios.h"
#include "ios/chrome/browser/ui/ui_util.h"
#include "ios/chrome/grit/ios_strings.h"
#import "ios/web/web_state/ui/crw_swipe_recognizer_provider.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using base::UserMetricsAction;
namespace {
const char* kMostVisitedFragment = "most_visited";
const char* kBookmarksFragment = "bookmarks";
const char* kOpenTabsFragment = "open_tabs";
const char* kIncognitoFragment = "incognito";
const CGFloat kToolbarHeight = 56;
}
namespace NewTabPage {
// Converts from a URL #fragment string to an identifier.
// Defaults to NewTabPage::kNone if the fragment is nil or not recognized.
// The strings checked by this function matches the set of fragments
// supported by chrome://newtab/# on Android.
// See chrome/browser/resources/mobile_ntp/mobile_ntp.js
PanelIdentifier IdentifierFromFragment(const std::string& fragment) {
if (fragment == kMostVisitedFragment)
return NewTabPage::kMostVisitedPanel;
else if (fragment == kBookmarksFragment)
return NewTabPage::kBookmarksPanel;
else if (fragment == kOpenTabsFragment)
return NewTabPage::kOpenTabsPanel;
else if (fragment == kIncognitoFragment)
return NewTabPage::kIncognitoPanel;
else
return NewTabPage::kNone;
}
// Converts from a NewTabPage::PanelIdentifier to a URL #fragment string.
// Defaults to nil if the fragment is kNone or not recognized.
std::string FragmentFromIdentifier(PanelIdentifier panel) {
switch (panel) {
case NewTabPage::kNone:
return "";
case NewTabPage::kMostVisitedPanel:
return kMostVisitedFragment;
case NewTabPage::kBookmarksPanel:
return kBookmarksFragment;
case NewTabPage::kOpenTabsPanel:
return kOpenTabsFragment;
case NewTabPage::kIncognitoPanel:
return kIncognitoFragment;
default:
NOTREACHED();
return "";
}
}
} // namespace NewTabPage
namespace {
// TODO(pkl): These are private constants and enums from
// ui/webui/ntp/new_tab_page_handler.h. At some point these should be
// refactored out so they can be included instead of redefined here.
const int kPageIdOffset = 10;
enum {
INDEX_MASK = (1 << kPageIdOffset) - 1,
MOST_VISITED_PAGE_ID = 1 << kPageIdOffset,
BOOKMARKS_PAGE_ID = 3 << kPageIdOffset,
OPEN_TABS_PAGE_ID = 4 << kPageIdOffset,
};
} // anonymous namespace
@interface NewTabPageController () {
ios::ChromeBrowserState* browserState_; // weak.
__weak id<UrlLoader> loader_;
__weak id<NewTabPageControllerObserver> newTabPageObserver_;
BookmarkHomeTabletNTPController* bookmarkController_;
GoogleLandingViewController* googleLandingController_;
id<NewTabPagePanelProtocol> incognitoController_;
// The currently visible controller, one of the above.
__weak id<NewTabPagePanelProtocol> currentController_;
GoogleLandingMediator* googleLandingMediator_;
RecentTabsPanelController* openTabsController_;
// Has the scrollView been initialized.
BOOL scrollInitialized_;
// Dominant color cache. Key: (NSString*)url, val: (UIColor*)dominantColor.
__weak NSMutableDictionary* dominantColorCache_; // Owned by bvc.
// Delegate to focus and blur the omnibox.
__weak id<OmniboxFocuser> focuser_;
// Delegate to fetch the ToolbarModel and current web state from.
__weak id<WebToolbarDelegate> webToolbarDelegate_;
TabModel* tabModel_;
}
// Load and bring panel into view.
- (void)showPanel:(NewTabPageBarItem*)item;
// Load panel on demand.
- (BOOL)loadPanel:(NewTabPageBarItem*)item;
// After a panel changes, update metrics and prefs information.
- (void)panelChanged:(NewTabPageBarItem*)item;
// Update current controller and tab bar index. Used to call reload.
- (void)updateCurrentController:(NewTabPageBarItem*)item
index:(NSUInteger)index;
// Bring panel into scroll view.
- (void)scrollToPanel:(NewTabPageBarItem*)item animate:(BOOL)animate;
// Returns index of item in tab bar.
- (NSUInteger)tabBarItemIndex:(NewTabPageBarItem*)item;
// Call loadPanel by item index.
- (void)loadControllerWithIndex:(NSUInteger)index;
// Initialize scroll view.
- (void)setUpScrollView;
// Update overlay scroll view value.
- (void)updateOverlayScrollPosition;
// Disable the horizontal scroll view.
- (void)disableScroll;
// Enable the horizontal scroll view.
- (void)enableScroll;
// Returns the ID for the currently selected panel.
- (NewTabPage::PanelIdentifier)selectedPanelID;
@property(nonatomic, strong) NewTabPageView* ntpView;
// To ease modernizing the NTP only the internal panels are being converted
// to UIViewControllers. This means all the plumbing between the
// BrowserViewController and the internal NTP panels (WebController, NTP)
// hierarchy is skipped. While normally the logic to push and pop a view
// controller would be owned by a coordinator, in this case the old NTP
// controller adds and removes child view controllers itself when a load
// is initiated, and when WebController calls -willBeDismissed.
@property(nonatomic, weak) UIViewController* parentViewController;
// To ease modernizing the NTP a non-descript CommandDispatcher is passed thru
// to be used by the reuabled NTP panels.
@property(nonatomic, weak) id dispatcher;
@end
@implementation NewTabPageController
@synthesize ntpView = ntpView_;
@synthesize swipeRecognizerProvider = swipeRecognizerProvider_;
@synthesize parentViewController = parentViewController_;
@synthesize dispatcher = dispatcher_;
- (id)initWithUrl:(const GURL&)url
loader:(id<UrlLoader>)loader
focuser:(id<OmniboxFocuser>)focuser
ntpObserver:(id<NewTabPageControllerObserver>)ntpObserver
browserState:(ios::ChromeBrowserState*)browserState
colorCache:(NSMutableDictionary*)colorCache
webToolbarDelegate:(id<WebToolbarDelegate>)webToolbarDelegate
tabModel:(TabModel*)tabModel
parentViewController:(UIViewController*)parentViewController
dispatcher:(id)dispatcher {
self = [super initWithNibName:nil url:url];
if (self) {
DCHECK(browserState);
browserState_ = browserState;
loader_ = loader;
newTabPageObserver_ = ntpObserver;
parentViewController_ = parentViewController;
dispatcher_ = dispatcher;
focuser_ = focuser;
webToolbarDelegate_ = webToolbarDelegate;
tabModel_ = tabModel;
dominantColorCache_ = colorCache;
self.title = l10n_util::GetNSString(IDS_NEW_TAB_TITLE);
scrollInitialized_ = NO;
UIScrollView* scrollView =
[[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 412)];
[scrollView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight)];
NewTabPageBar* tabBar =
[[NewTabPageBar alloc] initWithFrame:CGRectMake(0, 412, 320, 48)];
ntpView_ = [[NewTabPageView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)
andScrollView:scrollView
andTabBar:tabBar];
// TODO(crbug.com/607113): Merge view and ntpView.
self.view = ntpView_;
[tabBar setDelegate:self];
bool isIncognito = browserState_->IsOffTheRecord();
NSString* incognito = l10n_util::GetNSString(IDS_IOS_NEW_TAB_INCOGNITO);
NSString* mostVisited =
l10n_util::GetNSString(IDS_IOS_NEW_TAB_MOST_VISITED);
NSString* bookmarks =
l10n_util::GetNSString(IDS_IOS_NEW_TAB_BOOKMARKS_PAGE_TITLE_MOBILE);
NSString* openTabs = l10n_util::GetNSString(IDS_IOS_NEW_TAB_RECENT_TABS);
NSMutableArray* tabBarItems = [NSMutableArray array];
NewTabPageBarItem* itemToDisplay = nil;
if (isIncognito) {
NewTabPageBarItem* incognitoItem = [NewTabPageBarItem
newTabPageBarItemWithTitle:incognito
identifier:NewTabPage::kIncognitoPanel
image:[UIImage imageNamed:@"ntp_incognito"]];
if (IsIPadIdiom()) {
// Only add the bookmarks tab item for Incognito.
NewTabPageBarItem* bookmarksItem = [NewTabPageBarItem
newTabPageBarItemWithTitle:bookmarks
identifier:NewTabPage::kBookmarksPanel
image:[UIImage imageNamed:@"ntp_bookmarks"]];
[tabBarItems addObject:bookmarksItem];
[tabBarItems addObject:incognitoItem];
self.ntpView.tabBar.items = tabBarItems;
}
itemToDisplay = incognitoItem;
} else {
NewTabPageBarItem* mostVisitedItem = [NewTabPageBarItem
newTabPageBarItemWithTitle:mostVisited
identifier:NewTabPage::kMostVisitedPanel
image:[UIImage imageNamed:@"ntp_mv_search"]];
NewTabPageBarItem* bookmarksItem = [NewTabPageBarItem
newTabPageBarItemWithTitle:bookmarks
identifier:NewTabPage::kBookmarksPanel
image:[UIImage imageNamed:@"ntp_bookmarks"]];
[tabBarItems addObject:bookmarksItem];
if (IsIPadIdiom()) {
[tabBarItems addObject:mostVisitedItem];
}
NewTabPageBarItem* openTabsItem = [NewTabPageBarItem
newTabPageBarItemWithTitle:openTabs
identifier:NewTabPage::kOpenTabsPanel
image:[UIImage imageNamed:@"ntp_opentabs"]];
[tabBarItems addObject:openTabsItem];
self.ntpView.tabBar.items = tabBarItems;
if (!IsIPadIdiom()) {
itemToDisplay = mostVisitedItem;
} else {
PrefService* prefs = browserState_->GetPrefs();
int shownPage = prefs->GetInteger(prefs::kNtpShownPage);
shownPage = shownPage & ~INDEX_MASK;
if (shownPage == BOOKMARKS_PAGE_ID) {
itemToDisplay = bookmarksItem;
} else if (shownPage == OPEN_TABS_PAGE_ID) {
itemToDisplay = openTabsItem;
} else {
itemToDisplay = mostVisitedItem;
}
}
}
DCHECK(itemToDisplay);
[self setUpScrollView];
[self showPanel:itemToDisplay];
[self updateOverlayScrollPosition];
}
return self;
}
- (void)dealloc {
// Animations can last past the life of the NTP controller, nil out the
// delegate.
self.ntpView.scrollView.delegate = nil;
[googleLandingMediator_ shutdown];
// This is not an ideal place to put view controller contaimnent, rather a
// //web -wasDismissed method on CRWNativeContent would be more accurate. If
// CRWNativeContent leaks, this will not be called.
// TODO(crbug.com/708319): Also call -removeFromParentViewController for
// open tabs and incognito here.
[googleLandingController_ removeFromParentViewController];
[bookmarkController_ removeFromParentViewController];
[googleLandingController_ setDelegate:nil];
[bookmarkController_ setDelegate:nil];
[openTabsController_ setDelegate:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - CRWNativeContent
- (void)willBeDismissed {
// This methods is called by //web immediately before |self|'s view is removed
// from the view hierarchy, making it an ideal spot to intiate view controller
// containment methods.
// TODO(crbug.com/708319): Also call -willMoveToParentViewController:nil for
// open tabs and incognito here.
[googleLandingController_ willMoveToParentViewController:nil];
[bookmarkController_ willMoveToParentViewController:nil];
}
- (void)reload {
[currentController_ reload];
[super reload];
}
- (void)wasShown {
[currentController_ wasShown];
// Ensure that the NTP has the latest data when it is shown.
[self reload];
[self.ntpView.tabBar updateColorsForScrollView:self.ntpView.scrollView];
[self.ntpView.tabBar
setShadowAlpha:[currentController_ alphaForBottomShadow]];
}
- (void)wasHidden {
[currentController_ wasHidden];
}
- (BOOL)wantsKeyboardShield {
return [self selectedPanelID] != NewTabPage::kMostVisitedPanel;
}
- (BOOL)wantsLocationBarHintText {
// Always show hint text on iPhone.
if (!IsIPadIdiom())
return YES;
// Always show the location bar hint text if the search engine is not Google.
TemplateURLService* service =
ios::TemplateURLServiceFactory::GetForBrowserState(browserState_);
if (service) {
const TemplateURL* defaultURL = service->GetDefaultSearchProvider();
if (defaultURL &&
defaultURL->GetEngineType(service->search_terms_data()) !=
SEARCH_ENGINE_GOOGLE) {
return YES;
}
}
// Always return true when incognito.
if (browserState_->IsOffTheRecord())
return YES;
return [self selectedPanelID] != NewTabPage::kMostVisitedPanel;
}
- (void)dismissKeyboard {
[currentController_ dismissKeyboard];
}
- (void)dismissModals {
[currentController_ dismissModals];
}
- (void)willUpdateSnapshot {
if ([currentController_ respondsToSelector:@selector(willUpdateSnapshot)]) {
[currentController_ willUpdateSnapshot];
}
}
#pragma mark -
- (void)setSwipeRecognizerProvider:(id<CRWSwipeRecognizerProvider>)provider {
swipeRecognizerProvider_ = provider;
NSSet* recognizers = [swipeRecognizerProvider_ swipeRecognizers];
for (UISwipeGestureRecognizer* swipeRecognizer in recognizers) {
[self.ntpView.scrollView.panGestureRecognizer
requireGestureRecognizerToFail:swipeRecognizer];
}
}
- (void)setUpScrollView {
NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self
selector:@selector(disableScroll)
name:UIKeyboardWillShowNotification
object:nil];
[defaultCenter addObserver:self
selector:@selector(enableScroll)
name:UIKeyboardWillHideNotification
object:nil];
UIScrollView* scrollView = self.ntpView.scrollView;
scrollView.pagingEnabled = YES;
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.contentMode = UIViewContentModeScaleAspectFit;
scrollView.bounces = YES;
scrollView.delegate = self;
scrollView.scrollsToTop = NO;
[self.ntpView updateScrollViewContentSize];
[self.ntpView.tabBar updateColorsForScrollView:scrollView];
scrollInitialized_ = YES;
}
- (void)disableScroll {
[self.ntpView.scrollView setScrollEnabled:NO];
}
- (void)enableScroll {
[self.ntpView.scrollView setScrollEnabled:YES];
}
// Update selectedIndex and scroll position as the scroll view moves.
- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
if (!scrollInitialized_)
return;
// Position is used to track the exact X position of the scroll view, whereas
// index is rounded to the panel that is most visible.
CGFloat panelWidth =
scrollView.contentSize.width / self.ntpView.tabBar.items.count;
LayoutOffset position =
LeadingContentOffsetForScrollView(scrollView) / panelWidth;
NSUInteger index = round(position);
// |scrollView| can be out of range when the frame changes.
if (index >= self.ntpView.tabBar.items.count)
return;
// Only create views when they need to be visible. This will create a slight
// jank on first creation, but it doesn't seem very noticable. The trade off
// is loading the adjacent panels, and a longer initial NTP startup.
if (position - index > 0)
[self loadControllerWithIndex:index + 1];
[self loadControllerWithIndex:index];
if (position - index < 0)
[self loadControllerWithIndex:index - 1];
// If index changed, follow same path as if a tab bar item was pressed. When
// |index| == |position|, the panel is completely in view.
if (index == position && self.ntpView.tabBar.selectedIndex != index) {
NewTabPageBarItem* item = [self.ntpView.tabBar.items objectAtIndex:index];
DCHECK(item);
self.ntpView.tabBar.selectedIndex = index;
[self updateCurrentController:item index:index];
[self newTabBarItemDidChange:item changePanel:NO];
}
[self.ntpView.tabBar updateColorsForScrollView:scrollView];
[self updateOverlayScrollPosition];
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView*)scrollView {
NSUInteger index = self.ntpView.tabBar.selectedIndex;
NewTabPageBarItem* item = [self.ntpView.tabBar.items objectAtIndex:index];
DCHECK(item);
[self updateCurrentController:item index:index];
}
// Called when the user presses a segment that's not currently selected.
// Pressing a segment that's already selected does not trigger this action.
- (void)newTabBarItemDidChange:(NewTabPageBarItem*)selectedItem
changePanel:(BOOL)changePanel {
[self panelChanged:selectedItem];
if (changePanel) {
[self scrollToPanel:selectedItem animate:YES];
}
[newTabPageObserver_ selectedPanelDidChange];
}
- (void)selectPanel:(NewTabPage::PanelIdentifier)panelType {
for (NewTabPageBarItem* item in self.ntpView.tabBar.items) {
if (item.identifier == panelType) {
[self showPanel:item];
return; // Early return after finding the first match.
}
}
}
- (void)showPanel:(NewTabPageBarItem*)item {
if ([self loadPanel:item]) {
// Intentionally omitting a metric for the Incognito panel.
if (item.identifier == NewTabPage::kBookmarksPanel)
base::RecordAction(UserMetricsAction("MobileNTPShowBookmarks"));
else if (item.identifier == NewTabPage::kMostVisitedPanel)
base::RecordAction(UserMetricsAction("MobileNTPShowMostVisited"));
else if (item.identifier == NewTabPage::kOpenTabsPanel)
base::RecordAction(UserMetricsAction("MobileNTPShowOpenTabs"));
}
[self scrollToPanel:item animate:NO];
}
- (void)loadControllerWithIndex:(NSUInteger)index {
if (index >= self.ntpView.tabBar.items.count)
return;
NewTabPageBarItem* item = [self.ntpView.tabBar.items objectAtIndex:index];
[self loadPanel:item];
}
- (BOOL)loadPanel:(NewTabPageBarItem*)item {
DCHECK(self.parentViewController);
UIView* view = nil;
UIViewController* panelController = nil;
BOOL created = NO;
// Only load the controllers once.
if (item.identifier == NewTabPage::kBookmarksPanel) {
if (!bookmarkController_) {
BookmarkControllerFactory* factory =
[[BookmarkControllerFactory alloc] init];
bookmarkController_ =
[factory bookmarkPanelControllerForBrowserState:browserState_
loader:loader_
colorCache:dominantColorCache_];
}
panelController = bookmarkController_;
view = [bookmarkController_ view];
[bookmarkController_ setDelegate:self];
} else if (item.identifier == NewTabPage::kMostVisitedPanel) {
if (!googleLandingController_) {
googleLandingController_ = [[GoogleLandingViewController alloc] init];
[googleLandingController_ setDispatcher:self.dispatcher];
googleLandingMediator_ = [[GoogleLandingMediator alloc]
initWithConsumer:googleLandingController_
browserState:browserState_
dispatcher:self.dispatcher
webStateList:[tabModel_ webStateList]];
[googleLandingController_ setDataSource:googleLandingMediator_];
}
panelController = googleLandingController_;
view = [googleLandingController_ view];
[googleLandingController_ setDelegate:self];
} else if (item.identifier == NewTabPage::kOpenTabsPanel) {
if (!openTabsController_)
openTabsController_ =
[[RecentTabsPanelController alloc] initWithLoader:loader_
browserState:browserState_];
// TODO(crbug.com/708319): Also set panelController for opentabs here.
view = [openTabsController_ view];
[openTabsController_ setDelegate:self];
} else if (item.identifier == NewTabPage::kIncognitoPanel) {
if (!incognitoController_)
incognitoController_ =
[[IncognitoPanelController alloc] initWithLoader:loader_
browserState:browserState_
webToolbarDelegate:webToolbarDelegate_];
// TODO(crbug.com/708319): Also set panelController for incognito here.
view = [incognitoController_ view];
} else {
NOTREACHED();
return NO;
}
// Add the panel views to the scroll view in the proper location.
NSUInteger index = [self tabBarItemIndex:item];
if (view.superview == nil) {
created = YES;
view.frame = [self.ntpView panelFrameForItemAtIndex:index];
item.view = view;
// To ease modernizing the NTP only the internal panels are being converted
// to UIViewControllers. This means all the plumbing between the
// BrowserViewController and the internal NTP panels (WebController, NTP)
// hierarchy is skipped. While normally the logic to push and pop a view
// controller would be owned by a coordinator, in this case the old NTP
// controller adds and removes child view controllers itself when a load
// is initiated, and when WebController calls -willBeDismissed.
// TODO(crbug.com/708319):This 'if' can become a DCHECK once all panels move
// to panelControllers.
if (panelController)
[self.parentViewController addChildViewController:panelController];
[self.ntpView.scrollView addSubview:view];
if (panelController)
[panelController didMoveToParentViewController:self.parentViewController];
}
return created;
}
- (void)scrollToPanel:(NewTabPageBarItem*)item animate:(BOOL)animate {
NSUInteger index = [self tabBarItemIndex:item];
if (IsIPadIdiom()) {
CGRect itemFrame = [self.ntpView panelFrameForItemAtIndex:index];
CGPoint point = CGPointMake(CGRectGetMinX(itemFrame), 0);
[self.ntpView.scrollView setContentOffset:point animated:animate];
} else {
if (item.identifier == NewTabPage::kBookmarksPanel) {
GenericChromeCommand* command =
[[GenericChromeCommand alloc] initWithTag:IDC_SHOW_BOOKMARK_MANAGER];
[self.ntpView chromeExecuteCommand:command];
} else if (item.identifier == NewTabPage::kOpenTabsPanel) {
GenericChromeCommand* command =
[[GenericChromeCommand alloc] initWithTag:IDC_SHOW_OTHER_DEVICES];
[self.ntpView chromeExecuteCommand:command];
}
}
if (currentController_ == nil) {
[self updateCurrentController:item index:index];
}
}
// Return the index of the tab item. For iPhone always return 0 since the
// returned index is used to update the visible controller and scroll the NTP
// scroll view. None of this is applicable for iPhone.
- (NSUInteger)tabBarItemIndex:(NewTabPageBarItem*)item {
NSUInteger index = 0;
if (IsIPadIdiom()) {
index = [self.ntpView.tabBar.items indexOfObject:item];
DCHECK(index != NSNotFound);
}
return index;
}
- (NewTabPage::PanelIdentifier)selectedPanelID {
if (IsIPadIdiom()) {
// |selectedIndex| isn't meaningful here with modal buttons on iPhone.
NSUInteger index = self.ntpView.tabBar.selectedIndex;
DCHECK(index != NSNotFound);
NewTabPageBarItem* item = self.ntpView.tabBar.items[index];
return static_cast<NewTabPage::PanelIdentifier>(item.identifier);
}
return NewTabPage::kMostVisitedPanel;
}
- (void)updateCurrentController:(NewTabPageBarItem*)item
index:(NSUInteger)index {
if (!IsIPadIdiom() && (item.identifier == NewTabPage::kBookmarksPanel ||
item.identifier == NewTabPage::kOpenTabsPanel)) {
// Don't update |currentController_| for iPhone since Bookmarks and Recent
// Tabs are presented in a modal view controller.
return;
}
id<NewTabPagePanelProtocol> oldController = currentController_;
self.ntpView.tabBar.selectedIndex = index;
if (item.identifier == NewTabPage::kBookmarksPanel)
currentController_ = bookmarkController_;
else if (item.identifier == NewTabPage::kMostVisitedPanel)
currentController_ = googleLandingController_;
else if (item.identifier == NewTabPage::kOpenTabsPanel)
currentController_ = openTabsController_;
else if (item.identifier == NewTabPage::kIncognitoPanel)
currentController_ = incognitoController_;
[bookmarkController_
setScrollsToTop:(currentController_ == bookmarkController_)];
[googleLandingController_
setScrollsToTop:(currentController_ == googleLandingController_)];
[openTabsController_
setScrollsToTop:(currentController_ == openTabsController_)];
[self.ntpView.tabBar
setShadowAlpha:[currentController_ alphaForBottomShadow]];
if (oldController != currentController_) {
[currentController_ wasShown];
[oldController wasHidden];
}
}
- (void)panelChanged:(NewTabPageBarItem*)item {
if (browserState_->IsOffTheRecord())
return;
// Save state and update metrics. Intentionally omitting a metric for the
// Incognito panel.
PrefService* prefs = browserState_->GetPrefs();
if (item.identifier == NewTabPage::kBookmarksPanel) {
base::RecordAction(UserMetricsAction("MobileNTPSwitchToBookmarks"));
prefs->SetInteger(prefs::kNtpShownPage, BOOKMARKS_PAGE_ID);
} else if (item.identifier == NewTabPage::kMostVisitedPanel) {
base::RecordAction(UserMetricsAction("MobileNTPSwitchToMostVisited"));
prefs->SetInteger(prefs::kNtpShownPage, MOST_VISITED_PAGE_ID);
} else if (item.identifier == NewTabPage::kOpenTabsPanel) {
base::RecordAction(UserMetricsAction("MobileNTPSwitchToOpenTabs"));
prefs->SetInteger(prefs::kNtpShownPage, OPEN_TABS_PAGE_ID);
}
}
- (void)updateOverlayScrollPosition {
// Update overlay position. This moves the overlay animation on the tab bar.
UIScrollView* scrollView = self.ntpView.scrollView;
if (!scrollView || scrollView.contentSize.width == 0.0)
return;
self.ntpView.tabBar.overlayPercentage =
scrollView.contentOffset.x / scrollView.contentSize.width;
}
#pragma mark - LogoAnimationControllerOwnerOwner
- (id<LogoAnimationControllerOwner>)logoAnimationControllerOwner {
return [googleLandingController_ logoAnimationControllerOwner];
}
#pragma mark -
#pragma mark ToolbarOwner
- (ToolbarController*)relinquishedToolbarController {
return [googleLandingController_ relinquishedToolbarController];
}
- (void)reparentToolbarController {
[googleLandingController_ reparentToolbarController];
}
- (CGFloat)toolbarHeight {
// If the google landing controller is nil, there is no toolbar visible in the
// native content view, finally there is no toolbar on iPad.
return googleLandingController_ && !IsIPadIdiom() ? kToolbarHeight : 0.0;
}
#pragma mark - NewTabPagePanelControllerDelegate
- (void)updateNtpBarShadowForPanelController:
(id<NewTabPagePanelProtocol>)ntpPanelController {
if (currentController_ != ntpPanelController)
return;
[self.ntpView.tabBar
setShadowAlpha:[ntpPanelController alphaForBottomShadow]];
}
@end
@implementation NewTabPageController (TestSupport)
- (id<NewTabPagePanelProtocol>)currentController {
return currentController_;
}
- (BookmarkHomeTabletNTPController*)bookmarkController {
return bookmarkController_;
}
- (GoogleLandingViewController*)googleLandingController {
return googleLandingController_;
}
- (id<NewTabPagePanelProtocol>)incognitoController {
return incognitoController_;
}
@end