blob: ca47ea3f5270b60b9a4ba7bb66aa52bc5fd15210 [file] [log] [blame]
// Copyright 2017 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/content_suggestions/ntp_home_mediator.h"
#include <memory>
#include "base/mac/foundation_util.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "components/ntp_snippets/content_suggestions_service.h"
#include "components/ntp_snippets/features.h"
#include "components/strings/grit/components_strings.h"
#include "ios/chrome/browser/chrome_url_constants.h"
#import "ios/chrome/browser/metrics/new_tab_page_uma.h"
#import "ios/chrome/browser/ntp/new_tab_page_tab_helper.h"
#import "ios/chrome/browser/search_engines/search_engine_observer_bridge.h"
#import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/browser_commands.h"
#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
#import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
#import "ios/chrome/browser/ui/commands/snackbar_commands.h"
#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.h"
#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_item.h"
#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_alert_factory.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller_audience.h"
#import "ios/chrome/browser/ui/content_suggestions/ntp_home_consumer.h"
#import "ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h"
#import "ios/chrome/browser/ui/location_bar_notification_names.h"
#include "ios/chrome/browser/ui/ntp/metrics.h"
#import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h"
#import "ios/chrome/browser/ui/ntp/notification_promo_whats_new.h"
#import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
#include "ios/chrome/browser/ui/ui_feature_flags.h"
#import "ios/chrome/browser/ui/url_loader.h"
#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
#import "ios/chrome/common/favicon/favicon_attributes.h"
#include "ios/chrome/grit/ios_strings.h"
#import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
#import "ios/web/public/navigation_item.h"
#import "ios/web/public/navigation_manager.h"
#include "ios/web/public/referrer.h"
#import "ios/web/public/web_state/web_state.h"
#import "ios/web/public/web_state/web_state_observer_bridge.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// URL for the page displaying help for the NTP.
const char kNTPHelpURL[] =
"https://support.google.com/chrome/?p=ios_new_tab&ios=1";
} // namespace
@interface NTPHomeMediator ()<CRWWebStateObserver,
SearchEngineObserving,
WebStateListObserving> {
std::unique_ptr<web::WebStateObserverBridge> _webStateObserver;
// Observes the WebStateList so that this mediator can update the UI when the
// active WebState changes.
std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
// Listen for default search engine changes.
std::unique_ptr<SearchEngineObserverBridge> _searchEngineObserver;
}
@property(nonatomic, strong) AlertCoordinator* alertCoordinator;
// The WebStateList that is being observed by this mediator.
@property(nonatomic, assign, readonly) WebStateList* webStateList;
// TemplateURL used to get the search engine.
@property(nonatomic, assign) TemplateURLService* templateURLService;
// Logo vendor to display the doodle on the NTP.
@property(nonatomic, strong) id<LogoVendor> logoVendor;
// The web state associated with this NTP.
@property(nonatomic, assign) web::WebState* webState;
@end
@implementation NTPHomeMediator
@synthesize webState = _webState;
@synthesize consumer = _consumer;
@synthesize dispatcher = _dispatcher;
@synthesize suggestionsService = _suggestionsService;
@synthesize NTPMetrics = _NTPMetrics;
@synthesize suggestionsViewController = _suggestionsViewController;
@synthesize suggestionsMediator = _suggestionsMediator;
@synthesize alertCoordinator = _alertCoordinator;
@synthesize metricsRecorder = _metricsRecorder;
@synthesize logoVendor = _logoVendor;
@synthesize templateURLService = _templateURLService;
@synthesize webStateList = _webStateList;
- (instancetype)initWithWebStateList:(WebStateList*)webStateList
templateURLService:(TemplateURLService*)templateURLService
logoVendor:(id<LogoVendor>)logoVendor {
self = [super init];
if (self) {
_webStateList = webStateList;
_webStateListObserver = std::make_unique<WebStateListObserverBridge>(self);
_webStateList->AddObserver(_webStateListObserver.get());
_templateURLService = templateURLService;
// Listen for default search engine changes.
_searchEngineObserver = std::make_unique<SearchEngineObserverBridge>(
self, self.templateURLService);
_logoVendor = logoVendor;
}
return self;
}
- (void)dealloc {
if (_webState && _webStateObserver) {
_webState->RemoveObserver(_webStateObserver.get());
_webStateObserver.reset();
_webState = nullptr;
}
}
- (void)setUp {
DCHECK(!_webStateObserver);
DCHECK(self.suggestionsService);
[self.consumer setTabCount:self.webStateList->count()];
self.webState = self.webStateList->GetActiveWebState();
_webStateObserver = std::make_unique<web::WebStateObserverBridge>(self);
if (self.webState) {
self.webState->AddObserver(_webStateObserver.get());
web::NavigationManager* navigationManager =
self.webState->GetNavigationManager();
[self.consumer setCanGoForward:navigationManager->CanGoForward()];
[self.consumer setCanGoBack:navigationManager->CanGoBack()];
}
[self.consumer setLogoVendor:self.logoVendor];
self.templateURLService->Load();
[self searchEngineChanged];
// Set up notifications;
NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self.consumer
selector:@selector(locationBarBecomesFirstResponder)
name:kLocationBarBecomesFirstResponderNotification
object:nil];
[defaultCenter addObserver:self.consumer
selector:@selector(locationBarResignsFirstResponder)
name:kLocationBarResignsFirstResponderNotification
object:nil];
}
- (void)shutdown {
_webStateList->RemoveObserver(_webStateListObserver.get());
[[NSNotificationCenter defaultCenter] removeObserver:self.consumer];
_searchEngineObserver.reset();
DCHECK(_webStateObserver);
if (_webState) {
[self saveContentOffsetForWebState:_webState];
_webState->RemoveObserver(_webStateObserver.get());
_webStateObserver.reset();
}
}
#pragma mark - Properties.
- (void)setWebState:(web::WebState*)webState {
if (_webState && _webStateObserver) {
_webState->RemoveObserver(_webStateObserver.get());
}
_webState = webState;
if (_webState && _webStateObserver) {
_webState->AddObserver(_webStateObserver.get());
}
}
#pragma mark - CRWWebStateObserver
- (void)webState:(web::WebState*)webState didLoadPageWithSuccess:(BOOL)success {
DCHECK_EQ(_webState, webState);
[self setContentOffsetForWebState:webState];
}
- (void)webStateDestroyed:(web::WebState*)webState {
DCHECK_EQ(self.webState, webState);
self.webState = nullptr;
}
#pragma mark - ContentSuggestionsCommands
- (void)openReadingList {
[self.dispatcher showReadingList];
}
- (void)openPageForItemAtIndexPath:(NSIndexPath*)indexPath {
NewTabPageTabHelper* NTPHelper =
NewTabPageTabHelper::FromWebState(self.webState);
if (NTPHelper && NTPHelper->IgnoreLoadRequests()) {
return;
}
CollectionViewItem* item = [self.suggestionsViewController.collectionViewModel
itemAtIndexPath:indexPath];
ContentSuggestionsItem* suggestionItem =
base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
[self.metricsRecorder
onSuggestionOpened:suggestionItem
atIndexPath:indexPath
sectionsShownAbove:[self.suggestionsViewController
numberOfSectionsAbove:indexPath.section]
suggestionsShownAbove:[self.suggestionsViewController
numberOfSuggestionsAbove:indexPath.section]
withAction:WindowOpenDisposition::CURRENT_TAB];
self.suggestionsService->user_classifier()->OnEvent(
ntp_snippets::UserClassifier::Metric::SUGGESTIONS_USED);
web::NavigationManager::WebLoadParams params(suggestionItem.URL);
// Use a referrer with a specific URL to mark this entry as coming from
// ContentSuggestions.
params.referrer =
web::Referrer(GURL(ntp_snippets::GetContentSuggestionsReferrerURL()),
web::ReferrerPolicyDefault);
params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
ChromeLoadParams chromeParams(params);
[self.dispatcher loadURLWithParams:chromeParams];
[self.NTPMetrics recordAction:new_tab_page_uma::ACTION_OPENED_SUGGESTION];
}
- (void)openMostVisitedItem:(CollectionViewItem*)item
atIndex:(NSInteger)mostVisitedIndex {
NewTabPageTabHelper* NTPHelper =
NewTabPageTabHelper::FromWebState(self.webState);
if (NTPHelper && NTPHelper->IgnoreLoadRequests())
return;
if ([item isKindOfClass:[ContentSuggestionsMostVisitedActionItem class]]) {
ContentSuggestionsMostVisitedActionItem* mostVisitedItem =
base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedActionItem>(
item);
switch (mostVisitedItem.collectionShortcutType) {
case NTPCollectionShortcutTypeBookmark:
[self.dispatcher showBookmarksManager];
base::RecordAction(base::UserMetricsAction("MobileNTPShowBookmarks"));
break;
case NTPCollectionShortcutTypeReadingList:
[self.dispatcher showReadingList];
base::RecordAction(base::UserMetricsAction("MobileNTPShowReadingList"));
break;
case NTPCollectionShortcutTypeRecentTabs:
[self.dispatcher showRecentTabs];
base::RecordAction(base::UserMetricsAction("MobileNTPShowRecentTabs"));
break;
case NTPCollectionShortcutTypeHistory:
[self.dispatcher showHistory];
base::RecordAction(base::UserMetricsAction("MobileNTPShowHistory"));
break;
}
return;
}
ContentSuggestionsMostVisitedItem* mostVisitedItem =
base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item);
[self logMostVisitedOpening:mostVisitedItem atIndex:mostVisitedIndex];
web::NavigationManager::WebLoadParams params(mostVisitedItem.URL);
params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
ChromeLoadParams chromeParams(params);
[self.dispatcher loadURLWithParams:chromeParams];
}
- (void)displayContextMenuForSuggestion:(CollectionViewItem*)item
atPoint:(CGPoint)touchLocation
atIndexPath:(NSIndexPath*)indexPath
readLaterAction:(BOOL)readLaterAction {
ContentSuggestionsItem* suggestionsItem =
base::mac::ObjCCastStrict<ContentSuggestionsItem>(item);
[self.metricsRecorder
onMenuOpenedForSuggestion:suggestionsItem
atIndexPath:indexPath
suggestionsShownAbove:[self.suggestionsViewController
numberOfSuggestionsAbove:indexPath
.section]];
self.alertCoordinator = [ContentSuggestionsAlertFactory
alertCoordinatorForSuggestionItem:suggestionsItem
onViewController:self.suggestionsViewController
atPoint:touchLocation
atIndexPath:indexPath
readLaterAction:readLaterAction
commandHandler:self];
[self.alertCoordinator start];
}
- (void)displayContextMenuForMostVisitedItem:(CollectionViewItem*)item
atPoint:(CGPoint)touchLocation
atIndexPath:(NSIndexPath*)indexPath {
// No context menu for action buttons.
if ([item isKindOfClass:[ContentSuggestionsMostVisitedActionItem class]]) {
return;
}
ContentSuggestionsMostVisitedItem* mostVisitedItem =
base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item);
self.alertCoordinator = [ContentSuggestionsAlertFactory
alertCoordinatorForMostVisitedItem:mostVisitedItem
onViewController:self.suggestionsViewController
atPoint:touchLocation
atIndexPath:indexPath
commandHandler:self];
[self.alertCoordinator start];
}
- (void)dismissModals {
[self.alertCoordinator stop];
self.alertCoordinator = nil;
}
// TODO(crbug.com/761096) : Promo handling should be tested.
- (void)handlePromoTapped {
NotificationPromoWhatsNew* notificationPromo =
[self.suggestionsMediator notificationPromo];
DCHECK(notificationPromo);
notificationPromo->HandleClosed();
[self.NTPMetrics recordAction:new_tab_page_uma::ACTION_OPENED_PROMO];
if (notificationPromo->IsURLPromo()) {
OpenNewTabCommand* command =
[[OpenNewTabCommand alloc] initWithURL:notificationPromo->url()
referrer:web::Referrer()
inIncognito:NO
inBackground:NO
appendTo:kCurrentTab];
[self.dispatcher webPageOrderedOpen:command];
return;
}
if (notificationPromo->IsChromeCommandPromo()) {
// "What's New" promo that runs a command can be added here by calling
// self.dispatcher.
DCHECK_EQ(kTestWhatsNewCommand, notificationPromo->command())
<< "Promo command is not valid.";
return;
}
NOTREACHED() << "Promo type is neither URL or command.";
}
- (void)handleLearnMoreTapped {
NewTabPageTabHelper* NTPHelper =
NewTabPageTabHelper::FromWebState(self.webState);
if (NTPHelper && NTPHelper->IgnoreLoadRequests())
return;
GURL URL(kNTPHelpURL);
ChromeLoadParams params(URL);
[self.dispatcher loadURLWithParams:params];
[self.NTPMetrics recordAction:new_tab_page_uma::ACTION_OPENED_LEARN_MORE];
}
#pragma mark - ContentSuggestionsGestureCommands
- (void)openNewTabWithSuggestionsItem:(ContentSuggestionsItem*)item
incognito:(BOOL)incognito {
[self.NTPMetrics recordAction:new_tab_page_uma::ACTION_OPENED_SUGGESTION];
self.suggestionsService->user_classifier()->OnEvent(
ntp_snippets::UserClassifier::Metric::SUGGESTIONS_USED);
NSIndexPath* indexPath = [self.suggestionsViewController.collectionViewModel
indexPathForItem:item];
if (indexPath) {
WindowOpenDisposition disposition =
incognito ? WindowOpenDisposition::OFF_THE_RECORD
: WindowOpenDisposition::NEW_BACKGROUND_TAB;
[self.metricsRecorder
onSuggestionOpened:item
atIndexPath:indexPath
sectionsShownAbove:[self.suggestionsViewController
numberOfSectionsAbove:indexPath.section]
suggestionsShownAbove:[self.suggestionsViewController
numberOfSuggestionsAbove:indexPath.section]
withAction:disposition];
}
CGPoint cellCenter = [self cellCenterForItem:item];
[self openNewTabWithURL:item.URL incognito:incognito originPoint:cellCenter];
}
- (void)addItemToReadingList:(ContentSuggestionsItem*)item {
NSIndexPath* indexPath = [self.suggestionsViewController.collectionViewModel
indexPathForItem:item];
if (indexPath) {
[self.metricsRecorder
onSuggestionOpened:item
atIndexPath:indexPath
sectionsShownAbove:[self.suggestionsViewController
numberOfSectionsAbove:indexPath.section]
suggestionsShownAbove:[self.suggestionsViewController
numberOfSuggestionsAbove:indexPath.section]
withAction:WindowOpenDisposition::SAVE_TO_DISK];
}
self.suggestionsMediator.readingListNeedsReload = YES;
ReadingListAddCommand* command =
[[ReadingListAddCommand alloc] initWithURL:item.URL title:item.title];
[self.dispatcher addToReadingList:command];
}
- (void)dismissSuggestion:(ContentSuggestionsItem*)item
atIndexPath:(NSIndexPath*)indexPath {
NSIndexPath* itemIndexPath = indexPath;
if (!itemIndexPath) {
// If the caller uses a nil |indexPath|, find it from the model.
itemIndexPath = [self.suggestionsViewController.collectionViewModel
indexPathForItem:item];
}
[self.suggestionsMediator dismissSuggestion:item.suggestionIdentifier];
[self.suggestionsViewController dismissEntryAtIndexPath:itemIndexPath];
}
- (void)openNewTabWithMostVisitedItem:(ContentSuggestionsMostVisitedItem*)item
incognito:(BOOL)incognito
atIndex:(NSInteger)index {
[self logMostVisitedOpening:item atIndex:index];
CGPoint cellCenter = [self cellCenterForItem:item];
[self openNewTabWithURL:item.URL incognito:incognito originPoint:cellCenter];
}
- (void)openNewTabWithMostVisitedItem:(ContentSuggestionsMostVisitedItem*)item
incognito:(BOOL)incognito {
NSInteger index =
[self.suggestionsViewController.collectionViewModel indexPathForItem:item]
.item;
[self openNewTabWithMostVisitedItem:item incognito:incognito atIndex:index];
}
- (void)removeMostVisited:(ContentSuggestionsMostVisitedItem*)item {
base::RecordAction(base::UserMetricsAction("MostVisited_UrlBlacklisted"));
[self.suggestionsMediator blacklistMostVisitedURL:item.URL];
[self showMostVisitedUndoForURL:item.URL];
}
#pragma mark - ContentSuggestionsHeaderViewControllerDelegate
- (BOOL)isContextMenuVisible {
return self.alertCoordinator.isVisible;
}
- (BOOL)isScrolledToTop {
return self.suggestionsViewController.scrolledToTop;
}
- (BOOL)ignoreLoadRequests {
NewTabPageTabHelper* NTPHelper =
NewTabPageTabHelper::FromWebState(self.webState);
if (NTPHelper && NTPHelper->IgnoreLoadRequests()) {
return YES;
}
return NO;
}
#pragma mark - WebStateListObserving
- (void)webStateList:(WebStateList*)webStateList
didInsertWebState:(web::WebState*)webState
atIndex:(int)index
activating:(BOOL)activating {
[self.consumer setTabCount:self.webStateList->count()];
}
- (void)webStateList:(WebStateList*)webStateList
didDetachWebState:(web::WebState*)webState
atIndex:(int)atIndex {
[self.consumer setTabCount:self.webStateList->count()];
}
// If the actual webState associated with this mediator were passed in, this
// would not be necessary. However, since the active webstate can change when
// the new tab page is created (and animated in), listen for changes here and
// always display what's active.
- (void)webStateList:(WebStateList*)webStateList
didChangeActiveWebState:(web::WebState*)newWebState
oldWebState:(web::WebState*)oldWebState
atIndex:(int)atIndex
reason:(int)reason {
if (newWebState) {
self.webState = newWebState;
web::NavigationManager* navigationManager =
newWebState->GetNavigationManager();
[self.consumer setCanGoForward:navigationManager->CanGoForward()];
[self.consumer setCanGoBack:navigationManager->CanGoBack()];
}
}
#pragma mark - SearchEngineObserving
- (void)searchEngineChanged {
BOOL showLogo = NO;
const TemplateURL* defaultURL =
self.templateURLService->GetDefaultSearchProvider();
if (defaultURL) {
showLogo = defaultURL->GetEngineType(
self.templateURLService->search_terms_data()) ==
SEARCH_ENGINE_GOOGLE;
}
[self.consumer setLogoIsShowing:showLogo];
}
#pragma mark - Private
// Returns the center of the cell associated with |item| in the window
// coordinates. Returns CGPointZero is the cell isn't visible.
- (CGPoint)cellCenterForItem:(CollectionViewItem<SuggestedContent>*)item {
NSIndexPath* indexPath = [self.suggestionsViewController.collectionViewModel
indexPathForItem:item];
if (!indexPath)
return CGPointZero;
UIView* cell = [self.suggestionsViewController.collectionView
cellForItemAtIndexPath:indexPath];
return [cell.superview convertPoint:cell.center toView:nil];
}
// Opens the |URL| in a new tab |incognito| or not. |originPoint| is the origin
// of the new tab animation if the tab is opened in background, in window
// coordinates.
- (void)openNewTabWithURL:(const GURL&)URL
incognito:(BOOL)incognito
originPoint:(CGPoint)originPoint {
// Open the tab in background if it is non-incognito only.
OpenNewTabCommand* command =
[[OpenNewTabCommand alloc] initWithURL:URL
referrer:web::Referrer()
inIncognito:incognito
inBackground:!incognito
appendTo:kCurrentTab];
command.originPoint = originPoint;
if (incognito) {
// Unfocus the omnibox if the new page should be opened in incognito to
// prevent staying stuck.
[self.dispatcher cancelOmniboxEdit];
}
[self.dispatcher webPageOrderedOpen:command];
}
// Logs a histogram due to a Most Visited item being opened.
- (void)logMostVisitedOpening:(ContentSuggestionsMostVisitedItem*)item
atIndex:(NSInteger)mostVisitedIndex {
[self.NTPMetrics
recordAction:new_tab_page_uma::ACTION_OPENED_MOST_VISITED_ENTRY];
base::RecordAction(base::UserMetricsAction("MobileNTPMostVisited"));
// TODO(crbug.com/763946): Plumb generation time.
RecordNTPTileClick(mostVisitedIndex, item.source, item.titleSource,
item.attributes, base::Time(), GURL());
}
// Shows a snackbar with an action to undo the removal of the most visited item
// with a |URL|.
- (void)showMostVisitedUndoForURL:(GURL)URL {
GURL copiedURL = URL;
MDCSnackbarMessageAction* action = [[MDCSnackbarMessageAction alloc] init];
__weak NTPHomeMediator* weakSelf = self;
action.handler = ^{
NTPHomeMediator* strongSelf = weakSelf;
if (!strongSelf)
return;
[strongSelf.suggestionsMediator whitelistMostVisitedURL:copiedURL];
};
action.title = l10n_util::GetNSString(IDS_NEW_TAB_UNDO_THUMBNAIL_REMOVE);
action.accessibilityIdentifier = @"Undo";
TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess);
MDCSnackbarMessage* message = [MDCSnackbarMessage
messageWithText:l10n_util::GetNSString(
IDS_IOS_NEW_TAB_MOST_VISITED_ITEM_REMOVED)];
message.action = action;
message.category = @"MostVisitedUndo";
[self.dispatcher showSnackbarMessage:message];
}
// Save the NTP scroll offset into the last committed navigation item for the
// before we navigate away.
- (void)saveContentOffsetForWebState:(web::WebState*)webState {
if (webState->GetLastCommittedURL().GetOrigin() != kChromeUINewTabURL)
return;
if (!base::FeatureList::IsEnabled(kBrowserContainerContainsNTP))
return;
web::NavigationManager* manager = webState->GetNavigationManager();
web::NavigationItem* item = manager->GetLastCommittedItem();
web::PageDisplayState displayState;
UIEdgeInsets contentInset =
self.suggestionsViewController.collectionView.contentInset;
CGPoint contentOffset =
self.suggestionsViewController.collectionView.contentOffset;
contentOffset.y -=
self.headerCollectionInteractionHandler.collectionShiftingOffset;
displayState.scroll_state() =
web::PageScrollState(contentOffset, contentInset);
item->SetPageDisplayState(displayState);
}
// Set the NTP scroll offset for the current navigation item.
- (void)setContentOffsetForWebState:(web::WebState*)webState {
if (webState->GetVisibleURL().GetOrigin() != kChromeUINewTabURL) {
return;
}
web::NavigationManager* navigationManager = webState->GetNavigationManager();
web::NavigationItem* item = navigationManager->GetVisibleItem();
CGFloat offset =
item ? item->GetPageDisplayState().scroll_state().content_offset().y : 0;
if (offset > 0)
[self.suggestionsViewController setContentOffset:offset];
}
@end