Index: ios/chrome/browser/ui/ntp/new_tab_page_controller.mm |
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ec65f615c8b837fb8ab11f21d5b4546ceeee4546 |
--- /dev/null |
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm |
@@ -0,0 +1,685 @@ |
+// 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> |
+ |
+#import "base/ios/weak_nsobject.h" |
+#include "base/logging.h" |
+#include "base/mac/objc_property_releaser.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/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_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" |
+ |
+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. |
+ id<UrlLoader> loader_; // Weak. |
+ id<CRWSwipeRecognizerProvider> swipeRecognizerProvider_; // Weak. |
+ id<NewTabPageControllerObserver> newTabPageObserver_; // Weak. |
+ |
+ NewTabPageView* newTabPageView_; |
+ |
+ base::scoped_nsobject<RecentTabsPanelController> openTabsController_; |
+ // Has the scrollView been initialized. |
+ BOOL scrollInitialized_; |
+ |
+ // Dominant color cache. Key: (NSString*)url, val: (UIColor*)dominantColor. |
+ NSMutableDictionary* dominantColorCache_; // Weak, owned by bvc. |
+ |
+ // Delegate to focus and blur the omnibox. |
+ base::WeakNSProtocol<id<OmniboxFocuser>> focuser_; |
+ |
+ // Delegate to fetch the ToolbarModel and current web state from. |
+ base::WeakNSProtocol<id<WebToolbarDelegate>> webToolbarDelegate_; |
+ |
+ base::scoped_nsobject<TabModel> tabModel_; |
+ |
+ base::mac::ObjCPropertyReleaser propertyReleaser_NewTabPageController_; |
+} |
+ |
+// 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, retain) NewTabPageView* ntpView; |
+@end |
+ |
+@implementation NewTabPageController |
+ |
+@synthesize ntpView = newTabPageView_; |
+@synthesize swipeRecognizerProvider = swipeRecognizerProvider_; |
+ |
+- (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 { |
+ self = [super initWithNibName:nil url:url]; |
+ if (self) { |
+ DCHECK(browserState); |
+ propertyReleaser_NewTabPageController_.Init(self, |
+ [NewTabPageController class]); |
+ browserState_ = browserState; |
+ loader_ = loader; |
+ newTabPageObserver_ = ntpObserver; |
+ focuser_.reset(focuser); |
+ webToolbarDelegate_.reset(webToolbarDelegate); |
+ tabModel_.reset([tabModel retain]); |
+ dominantColorCache_ = colorCache; |
+ self.title = l10n_util::GetNSString(IDS_NEW_TAB_TITLE); |
+ scrollInitialized_ = NO; |
+ |
+ base::scoped_nsobject<UIScrollView> scrollView( |
+ [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 412)]); |
+ [scrollView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | |
+ UIViewAutoresizingFlexibleHeight)]; |
+ base::scoped_nsobject<NewTabPageBar> tabBar( |
+ [[NewTabPageBar alloc] initWithFrame:CGRectMake(0, 412, 320, 48)]); |
+ newTabPageView_ = |
+ [[NewTabPageView alloc] initWithFrame:CGRectMake(0, 0, 320, 460) |
+ andScrollView:scrollView |
+ andTabBar:tabBar]; |
+ // TODO(crbug.com/607113): Merge view and ntpView. |
+ self.view = newTabPageView_; |
+ [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; |
+ [googleLandingController_ setDelegate:nil]; |
+ [bookmarkController_ setDelegate:nil]; |
+ [openTabsController_ setDelegate:nil]; |
+ [[NSNotificationCenter defaultCenter] removeObserver:self]; |
+ [super dealloc]; |
+} |
+ |
+#pragma mark - CRWNativeContent |
+ |
+// Note: No point implementing -handleLowMemory because all native content |
+// views but the selected one are dropped, and the selected view doesn't |
+// need to do anything. |
+ |
+- (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) { |
+ 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 { |
+ UIView* view; |
+ BOOL created = NO; |
+ // Only load the controllers once. |
+ if (item.identifier == NewTabPage::kBookmarksPanel) { |
+ if (!bookmarkController_) { |
+ base::scoped_nsobject<BookmarkControllerFactory> factory( |
+ [[BookmarkControllerFactory alloc] init]); |
+ bookmarkController_.reset([[factory |
+ bookmarkPanelControllerForBrowserState:browserState_ |
+ loader:loader_ |
+ colorCache:dominantColorCache_] retain]); |
+ } |
+ view = [bookmarkController_ view]; |
+ [bookmarkController_ setDelegate:self]; |
+ } else if (item.identifier == NewTabPage::kMostVisitedPanel) { |
+ if (!googleLandingController_) { |
+ googleLandingController_.reset([[GoogleLandingController alloc] |
+ initWithLoader:loader_ |
+ browserState:browserState_ |
+ focuser:focuser_ |
+ webToolbarDelegate:webToolbarDelegate_ |
+ tabModel:tabModel_]); |
+ } |
+ view = [googleLandingController_ view]; |
+ [googleLandingController_ setDelegate:self]; |
+ } else if (item.identifier == NewTabPage::kOpenTabsPanel) { |
+ if (!openTabsController_) |
+ openTabsController_.reset([[RecentTabsPanelController alloc] |
+ initWithLoader:loader_ |
+ browserState:browserState_]); |
+ view = [openTabsController_ view]; |
+ [openTabsController_ setDelegate:self]; |
+ } else if (item.identifier == NewTabPage::kIncognitoPanel) { |
+ if (!incognitoController_) |
+ incognitoController_.reset([[IncognitoPanelController alloc] |
+ initWithLoader:loader_ |
+ browserState:browserState_ |
+ webToolbarDelegate:webToolbarDelegate_]); |
+ 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; |
+ [self.ntpView.scrollView addSubview:view]; |
+ } |
+ 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) { |
+ base::scoped_nsobject<GenericChromeCommand> command( |
+ [[GenericChromeCommand alloc] initWithTag:IDC_SHOW_BOOKMARK_MANAGER]); |
+ [self.ntpView chromeExecuteCommand:command]; |
+ } else if (item.identifier == NewTabPage::kOpenTabsPanel) { |
+ base::scoped_nsobject<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_.get(); |
+ else if (item.identifier == NewTabPage::kMostVisitedPanel) |
+ currentController_ = googleLandingController_.get(); |
+ else if (item.identifier == NewTabPage::kOpenTabsPanel) |
+ currentController_ = openTabsController_.get(); |
+ else if (item.identifier == NewTabPage::kIncognitoPanel) |
+ currentController_ = incognitoController_.get(); |
+ |
+ [bookmarkController_ |
+ setScrollsToTop:(currentController_ == bookmarkController_.get())]; |
+ [googleLandingController_ |
+ setScrollsToTop:(currentController_ == googleLandingController_.get())]; |
+ [openTabsController_ |
+ setScrollsToTop:(currentController_ == openTabsController_.get())]; |
+ [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 |