Commit 459a6e05 authored by sczs's avatar sczs Committed by Commit Bot

[ios]Creates DiscoverFeed Observer and Updates the Discover Feed

- ContentSuggestionsMediator uses DiscoverFeedDelegate to notify
its Coordinator of Discover Feed Changes.
- ContentSuggestionsCoordinator refreshes the Feed and sets a new
ViewController (Created with the refreshed model) via its mediator.
- Creates a DiscoverFeed Observer and its bridge in DiscoverFeedProvider.

Bug: 1085419
Change-Id: If5b91d1cf9c99e164f4d9a50b5071ae65816350b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2327846
Commit-Queue: Sergio Collazos <sczs@chromium.org>
Reviewed-by: default avatarGanggui Tang <gogerald@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795324}
parent 1491c7b3
......@@ -20,6 +20,7 @@ source_set("content_suggestions") {
"content_suggestions_metrics_recorder.mm",
"content_suggestions_service_bridge_observer.h",
"content_suggestions_service_bridge_observer.mm",
"discover_feed_delegate.h",
"mediator_util.h",
"mediator_util.mm",
"ntp_home_mediator.h",
......
......@@ -43,6 +43,7 @@
#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/discover_feed_delegate.h"
#import "ios/chrome/browser/ui/content_suggestions/discover_feed_header_changing.h"
#import "ios/chrome/browser/ui/content_suggestions/discover_feed_menu_commands.h"
#import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h"
......@@ -71,6 +72,7 @@
@interface ContentSuggestionsCoordinator () <
ContentSuggestionsMenuProvider,
ContentSuggestionsViewControllerAudience,
DiscoverFeedDelegate,
DiscoverFeedMenuCommands,
OverscrollActionsControllerDelegate,
ThemeChangeDelegate,
......@@ -178,19 +180,7 @@
ReadingListModelFactory::GetForBrowserState(
self.browser->GetBrowserState());
self.discoverFeedViewController = ios::GetChromeBrowserProvider()
->GetDiscoverFeedProvider()
->NewFeedViewController(self.browser);
// TODO(crbug.com/1085419): Once the CollectionView is cleanly exposed, remove
// this loop.
for (UIView* view in self.discoverFeedViewController.view.subviews) {
if ([view isKindOfClass:[UICollectionView class]]) {
UICollectionView* feedView = static_cast<UICollectionView*>(view);
feedView.bounces = false;
feedView.alwaysBounceVertical = false;
}
}
self.discoverFeedViewController = [self discoverFeed];
self.contentSuggestionsMediator = [[ContentSuggestionsMediator alloc]
initWithContentService:contentSuggestionsService
......@@ -204,6 +194,7 @@
self.contentSuggestionsMediator.headerProvider = self.headerController;
self.contentSuggestionsMediator.contentArticlesExpanded =
self.contentSuggestionsVisible;
self.contentSuggestionsMediator.discoverFeedDelegate = self;
self.headerController.promoCanShow =
[self.contentSuggestionsMediator notificationPromo]->CanShow();
......@@ -429,6 +420,17 @@
[self.alertCoordinator start];
}
#pragma mark - DiscoverFeedDelegate
- (void)recreateDiscoverFeedViewController {
DCHECK(IsDiscoverFeedEnabled());
// Create and set a new DiscoverFeed since that its model has changed.
self.discoverFeedViewController = [self discoverFeed];
self.contentSuggestionsMediator.discoverFeed =
self.discoverFeedViewController;
}
#pragma mark - Public methods
- (UIView*)view {
......@@ -499,4 +501,27 @@
actionProvider:actionProvider];
}
#pragma mark - Helpers
// Creates, configures and returns a DiscoverFeed ViewController.
- (UIViewController*)discoverFeed {
if (!IsDiscoverFeedEnabled())
return nil;
UIViewController* discoverFeed = ios::GetChromeBrowserProvider()
->GetDiscoverFeedProvider()
->NewFeedViewController(self.browser);
// TODO(crbug.com/1085419): Once the CollectionView is cleanly exposed, remove
// this loop.
for (UIView* view in discoverFeed.view.subviews) {
if ([view isKindOfClass:[UICollectionView class]]) {
UICollectionView* feedView = static_cast<UICollectionView*>(view);
feedView.bounces = NO;
feedView.alwaysBounceVertical = NO;
feedView.scrollEnabled = NO;
}
}
return discoverFeed;
}
@end
......@@ -31,6 +31,7 @@ class MostVisitedSites;
@protocol ContentSuggestionsGestureCommands;
@protocol ContentSuggestionsHeaderProvider;
@class ContentSuggestionIdentifier;
@protocol DiscoverFeedDelegate;
class GURL;
class LargeIconCache;
class NotificationPromoWhatsNew;
......@@ -73,7 +74,10 @@ class ReadingListModel;
@property(nonatomic, assign) BOOL readingListNeedsReload;
// ViewController created by the Discover provider containing the Discover feed.
@property(nonatomic, strong) UIViewController* discoverFeed;
@property(nonatomic, weak) UIViewController* discoverFeed;
// Delegate used to communicate to communicate events to the DiscoverFeed.
@property(nonatomic, weak) id<DiscoverFeedDelegate> discoverFeedDelegate;
// Disconnects the mediator.
- (void)disconnect;
......
......@@ -35,6 +35,7 @@
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_provider.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_service_bridge_observer.h"
#import "ios/chrome/browser/ui/content_suggestions/discover_feed_delegate.h"
#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestion_identifier.h"
#import "ios/chrome/browser/ui/content_suggestions/identifier/content_suggestions_section_information.h"
#import "ios/chrome/browser/ui/content_suggestions/mediator_util.h"
......@@ -43,6 +44,7 @@
#include "ios/chrome/browser/ui/util/ui_util.h"
#include "ios/chrome/common/app_group/app_group_constants.h"
#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
#import "ios/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.h"
#include "ios/public/provider/chrome/browser/images/branded_image_provider.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
......@@ -59,6 +61,7 @@ const NSInteger kMaxNumMostVisitedTiles = 4;
} // namespace
@interface ContentSuggestionsMediator () <BooleanObserver,
DiscoverFeedObserverBridgeDelegate,
ContentSuggestionsItemDelegate,
ContentSuggestionsServiceObserver,
MostVisitedSitesObserving,
......@@ -74,6 +77,9 @@ const NSInteger kMaxNumMostVisitedTiles = 4;
std::unique_ptr<PrefObserverBridge> _prefObserverBridge;
// Registrar for pref changes notifications.
std::unique_ptr<PrefChangeRegistrar> _prefChangeRegistrar;
// Observes changes in the DiscoverFeed.
std::unique_ptr<DiscoverFeedObserverBridge>
_discoverFeedProviderObserverBridge;
}
// Whether the contents section should be hidden completely.
......@@ -168,9 +174,10 @@ const NSInteger kMaxNumMostVisitedTiles = 4;
_learnMoreItem = [[ContentSuggestionsLearnMoreItem alloc] init];
_discoverFeed = discoverFeed;
_discoverSectionInfo = DiscoverSectionInformation();
_discoverItem = [[ContentSuggestionsDiscoverItem alloc] init];
_discoverItem.discoverFeed = discoverFeed;
_discoverItem.discoverFeed = _discoverFeed;
_notificationPromo = std::make_unique<NotificationPromoWhatsNew>(
GetApplicationContext()->GetLocalState());
......@@ -190,6 +197,11 @@ const NSInteger kMaxNumMostVisitedTiles = 4;
_readingListModelBridge =
std::make_unique<ReadingListModelBridge>(self, readingListModel);
if (IsDiscoverFeedEnabled()) {
_discoverFeedProviderObserverBridge =
std::make_unique<DiscoverFeedObserverBridge>(self);
}
}
return self;
}
......@@ -197,6 +209,7 @@ const NSInteger kMaxNumMostVisitedTiles = 4;
- (void)disconnect {
_prefChangeRegistrar.reset();
_prefObserverBridge.reset();
_discoverFeedProviderObserverBridge.reset();
}
- (void)reloadAllData {
......@@ -747,6 +760,13 @@ const NSInteger kMaxNumMostVisitedTiles = 4;
[contentArticlesExpanded setObserver:self];
}
- (void)setDiscoverFeed:(UIViewController*)discoverFeed {
DCHECK(_discoverFeed != discoverFeed);
_discoverFeed = discoverFeed;
_discoverItem.discoverFeed = _discoverFeed;
[self.dataSink reloadAllData];
}
#pragma mark - PrefObserverDelegate
- (void)onPreferenceChanged:(const std::string&)preferenceName {
......@@ -769,4 +789,10 @@ const NSInteger kMaxNumMostVisitedTiles = 4;
}
}
#pragma mark - DiscoverFeedObserverBridge
- (void)onDiscoverFeedModelRecreated {
[self.discoverFeedDelegate recreateDiscoverFeedViewController];
}
@end
// Copyright 2020 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.
#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_DISCOVER_FEED_DELEGATE_H_
#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_DISCOVER_FEED_DELEGATE_H_
// Protocol for events related to the Discover Feed.
@protocol DiscoverFeedDelegate
// Informs the DiscoverFeedDelegate that the FeedViewController needs to be
// re-created.
- (void)recreateDiscoverFeedViewController;
@end
#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_DISCOVER_FEED_DELEGATE_H_
......@@ -5,8 +5,13 @@
source_set("discover_feed") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
"discover_feed_observer_bridge.h",
"discover_feed_observer_bridge.mm",
"discover_feed_provider.h",
"discover_feed_provider.mm",
]
deps = [ "//base" ]
deps = [
"//base",
"//ios/public/provider/chrome/browser",
]
}
// Copyright 2020 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.
#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_DISCOVER_FEED_DISCOVER_FEED_OBSERVER_BRIDGE_H_
#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_DISCOVER_FEED_DISCOVER_FEED_OBSERVER_BRIDGE_H_
#import <Foundation/Foundation.h>
#import "ios/public/provider/chrome/browser/discover_feed/discover_feed_provider.h"
#include "base/scoped_observer.h"
// Implement this protocol and pass your implementation into an
// DiscoveFeedObserverBridge object to receive DiscoverFeed observer
// callbacks in Objective-C.
@protocol DiscoverFeedObserverBridgeDelegate <NSObject>
@optional
// These callbacks follow the semantics of the corresponding
// DiscoverFeedProviderImpl::Observer callbacks. See the comments on
// DiscoverFeedProviderImpl::Observer in discover_feed_provider_impl.h for the
// specification of these semantics.
- (void)onDiscoverFeedModelRecreated;
@end
// Bridge class that listens for |DiscoverFeedProvider| notifications and
// passes them to its Objective-C delegate.
class DiscoverFeedObserverBridge : public DiscoverFeedProvider::Observer {
public:
explicit DiscoverFeedObserverBridge(
id<DiscoverFeedObserverBridgeDelegate> observer);
~DiscoverFeedObserverBridge() override;
DiscoverFeedObserverBridge(const DiscoverFeedObserverBridge&) = delete;
DiscoverFeedObserverBridge& operator=(const DiscoverFeedObserverBridge&) =
delete;
private:
// DiscoverFeedProvider::Observer implementation.
void OnDiscoverFeedModelRecreated() override;
__weak id<DiscoverFeedObserverBridgeDelegate> observer_;
ScopedObserver<DiscoverFeedProvider, DiscoverFeedProvider::Observer>
scoped_observer_{this};
};
#endif // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_DISCOVER_FEED_DISCOVER_FEED_OBSERVER_BRIDGE_H_
// Copyright 2020 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/public/provider/chrome/browser/discover_feed/discover_feed_observer_bridge.h"
#import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
DiscoverFeedObserverBridge::DiscoverFeedObserverBridge(
id<DiscoverFeedObserverBridgeDelegate> observer)
: observer_(observer) {
scoped_observer_.Add(
ios::GetChromeBrowserProvider()->GetDiscoverFeedProvider());
}
DiscoverFeedObserverBridge::~DiscoverFeedObserverBridge() {}
void DiscoverFeedObserverBridge::OnDiscoverFeedModelRecreated() {
if ([observer_ respondsToSelector:@selector(onDiscoverFeedModelRecreated)])
[observer_ onDiscoverFeedModelRecreated];
}
......@@ -16,6 +16,19 @@ class Browser;
// Feed.
class DiscoverFeedProvider {
public:
// Observer class for discover feed events.
class Observer {
public:
Observer() {}
virtual ~Observer() {}
Observer(const Observer&) = delete;
Observer& operator=(const Observer&) = delete;
// Called whenever the FeedProvider Model has changed. At this point all
// existing Feed ViewControllers are stale and need to be refreshed.
virtual void OnDiscoverFeedModelRecreated() = 0;
};
DiscoverFeedProvider() = default;
virtual ~DiscoverFeedProvider() = default;
......@@ -25,18 +38,15 @@ class DiscoverFeedProvider {
// Returns true if the Discover Feed is enabled.
virtual bool IsDiscoverFeedEnabled();
// Returns the Discover Feed ViewController.
// Deprecated - use the below NewFeedViewController(Browser* browser) instead.
// TODO(crbug.com/1085419): Remove this interface after rolling the downstream
// change.
virtual UIViewController* NewFeedViewController(
id<ApplicationCommands> handler) NS_RETURNS_RETAINED;
// Returns the Discover Feed ViewController.
virtual UIViewController* NewFeedViewController(Browser* browser)
NS_RETURNS_RETAINED;
// Updates the feed's theme to match the user's theme (light/dark).
virtual void UpdateTheme();
// Refreshes the Discover Feed with completion.
virtual void RefreshFeedWithCompletion(ProceduralBlock completion);
// Methods to register or remove observers.
virtual void AddObserver(Observer* observer);
virtual void RemoveObserver(Observer* observer);
};
#endif // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_DISCOVER_FEED_DISCOVER_FEED_PROVIDER_H_
......@@ -12,11 +12,6 @@ bool DiscoverFeedProvider::IsDiscoverFeedEnabled() {
return false;
}
UIViewController* DiscoverFeedProvider::NewFeedViewController(
id<ApplicationCommands> handler) {
return nil;
}
UIViewController* DiscoverFeedProvider::NewFeedViewController(
Browser* browser) {
return nil;
......@@ -26,3 +21,6 @@ void DiscoverFeedProvider::UpdateTheme() {}
void DiscoverFeedProvider::RefreshFeedWithCompletion(
ProceduralBlock completion) {}
void DiscoverFeedProvider::AddObserver(Observer* observer) {}
void DiscoverFeedProvider::RemoveObserver(Observer* observer) {}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment