Commit 4155b2ea authored by adamta's avatar adamta Committed by Commit Bot

[iOS] Add metrics for the Discover infinite feed

Refactors infinite feed triggering by moving the conditional logic in
the VC. Logs an action when user reached the bottom of the current feed,
requesting a new set of articles.

Bug: 1085419, 1122409
Change-Id: I99c734aaa5912e1d82e2330ec200593648fa8153
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2363219Reviewed-by: default avatarSergio Collazos <sczs@chromium.org>
Commit-Queue: Adam Trudeau-Arcaro <adamta@google.com>
Cr-Commit-Position: refs/heads/master@{#803117}
parent ae937956
......@@ -23,6 +23,8 @@ source_set("content_suggestions") {
"content_suggestions_service_bridge_observer.h",
"content_suggestions_service_bridge_observer.mm",
"discover_feed_delegate.h",
"discover_feed_metrics_recorder.h",
"discover_feed_metrics_recorder.mm",
"mediator_util.h",
"mediator_util.mm",
"ntp_home_mediator.h",
......
......@@ -52,6 +52,7 @@
#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/discover_feed_metrics_recorder.h"
#import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h"
#import "ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h"
#import "ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h"
......@@ -100,6 +101,8 @@
@property(nonatomic, strong)
ContentSuggestionsHeaderSynchronizer* headerCollectionInteractionHandler;
@property(nonatomic, strong) ContentSuggestionsMetricsRecorder* metricsRecorder;
@property(nonatomic, strong)
DiscoverFeedMetricsRecorder* discoverFeedMetricsRecorder;
@property(nonatomic, strong) NTPHomeMediator* NTPMediator;
@property(nonatomic, strong) UIViewController* discoverFeedViewController;
@property(nonatomic, strong) URLDragDropHandler* dragDropHandler;
......@@ -111,7 +114,6 @@
// Delegate for handling Discover feed header UI changes.
@property(nonatomic, weak) id<DiscoverFeedHeaderChanging>
discoverFeedHeaderDelegate;
@property(nonatomic) CGFloat discoverFeedHeight;
// Authentication Service for the user's signed-in state.
@property(nonatomic, assign) AuthenticationService* authService;
// Coordinator in charge of handling sharing use cases.
......@@ -234,6 +236,8 @@
self.metricsRecorder = [[ContentSuggestionsMetricsRecorder alloc] init];
self.metricsRecorder.delegate = self.contentSuggestionsMediator;
self.discoverFeedMetricsRecorder = [[DiscoverFeedMetricsRecorder alloc] init];
// Offset to maintain Discover feed scroll position.
CGFloat offset = 0;
if (IsDiscoverFeedEnabled() && contentSuggestionsEnabled) {
......@@ -433,10 +437,7 @@
addItemWithTitle:l10n_util::GetNSString(
IDS_IOS_DISCOVER_FEED_MENU_TURN_OFF_ITEM)
action:^{
[weakSelf.contentSuggestionsVisible setValue:NO];
[weakSelf.discoverFeedHeaderDelegate
changeDiscoverFeedHeaderVisibility:NO];
[weakSelf.contentSuggestionsMediator reloadAllData];
[weakSelf setDiscoverFeedVisible:NO];
}
style:UIAlertActionStyleDestructive];
} else {
......@@ -444,10 +445,7 @@
addItemWithTitle:l10n_util::GetNSString(
IDS_IOS_DISCOVER_FEED_MENU_TURN_ON_ITEM)
action:^{
[weakSelf.contentSuggestionsVisible setValue:YES];
[weakSelf.discoverFeedHeaderDelegate
changeDiscoverFeedHeaderVisibility:YES];
[weakSelf.contentSuggestionsMediator reloadAllData];
[weakSelf setDiscoverFeedVisible:YES];
}
style:UIAlertActionStyleDefault];
}
......@@ -495,21 +493,10 @@
#pragma mark - ContentSuggestionsActionHandler
- (void)loadMoreFeedArticles {
CGFloat currentHeight = 0;
for (UIView* view in self.discoverFeedViewController.view.subviews) {
if ([view isKindOfClass:[UICollectionView class]]) {
UICollectionView* feedView = static_cast<UICollectionView*>(view);
currentHeight = feedView.contentSize.height;
}
}
// TODO(crbug.com/1085419): Track number of cards from protocol instead of
// height to determine whether or not we should fetch more cards.
if (currentHeight != self.discoverFeedHeight) {
ios::GetChromeBrowserProvider()
->GetDiscoverFeedProvider()
->LoadMoreFeedArticles();
self.discoverFeedHeight = currentHeight;
}
ios::GetChromeBrowserProvider()
->GetDiscoverFeedProvider()
->LoadMoreFeedArticles();
[self.discoverFeedMetricsRecorder recordInfiniteFeedTriggered];
}
#pragma mark - Public methods
......@@ -667,4 +654,11 @@
[self.sharingCoordinator start];
}
// Toggles Discover feed visibility between hidden or expanded.
- (void)setDiscoverFeedVisible:(BOOL)visible {
[self.contentSuggestionsVisible setValue:visible];
[self.discoverFeedHeaderDelegate changeDiscoverFeedHeaderVisibility:visible];
[self.contentSuggestionsMediator reloadAllData];
}
@end
......@@ -80,6 +80,10 @@ NSString* const kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix =
// position, since the feed height is dynamic.
@property(nonatomic) CGFloat offset;
// Represents the last recorded height of the Discover feed for tracking when to
// trigger the infinite feed.
@property(nonatomic, assign) CGFloat discoverFeedHeight;
@end
@implementation ContentSuggestionsViewController
......@@ -708,18 +712,12 @@ NSString* const kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix =
scrollView.contentOffset.y >= [self.headerSynchronizer pinnedOffsetY];
if (IsDiscoverFeedEnabled() && self.contentSuggestionsEnabled) {
float scrollPosition =
scrollView.contentOffset.y + scrollView.frame.size.height;
// Check if view is bouncing to ignore overscoll positions for infinite feed
// triggering.
BOOL isBouncing =
(scrollView.contentOffset.y >=
(scrollView.contentSize.height - scrollView.bounds.size.height));
ContentSuggestionsLayout* layout = static_cast<ContentSuggestionsLayout*>(
self.collectionView.collectionViewLayout);
if (scrollPosition > scrollView.contentSize.height - kPaginationOffset &&
scrollPosition > layout.ntpHeight && !isBouncing) {
[self.handler loadMoreFeedArticles];
if ([self shouldTriggerInfiniteFeed:scrollView]) {
CGFloat currentHeight = self.feedView.contentSize.height;
if (currentHeight != self.discoverFeedHeight) {
self.discoverFeedHeight = currentHeight;
[self.handler loadMoreFeedArticles];
}
}
}
}
......@@ -908,4 +906,20 @@ NSString* const kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix =
[self.discoverFeedMenuHandler openDiscoverFeedMenu:menuButton];
}
// Evaluates whether or not another set of Discover feed articles should be
// fetched when scrolling.
- (BOOL)shouldTriggerInfiniteFeed:(UIScrollView*)scrollView {
float scrollPosition =
scrollView.contentOffset.y + scrollView.frame.size.height;
// Check if view is bouncing to ignore overscoll positions for infinite feed
// triggering.
BOOL isBouncing =
(scrollView.contentOffset.y >=
(scrollView.contentSize.height - scrollView.bounds.size.height));
ContentSuggestionsLayout* layout = static_cast<ContentSuggestionsLayout*>(
self.collectionView.collectionViewLayout);
return (scrollPosition > scrollView.contentSize.height - kPaginationOffset &&
scrollPosition > layout.ntpHeight && !isBouncing);
}
@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_METRICS_RECORDER_H_
#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_DISCOVER_FEED_METRICS_RECORDER_H_
#import <UIKit/UIKit.h>
// Records different metrics for the NTP's Discover feed.
@interface DiscoverFeedMetricsRecorder : NSObject
// Record metrics for when the user has reached the bottom of their current
// feed.
- (void)recordInfiniteFeedTriggered;
@end
#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_DISCOVER_FEED_METRICS_RECORDER_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/chrome/browser/ui/content_suggestions/discover_feed_metrics_recorder.h"
#import "base/metrics/histogram_macros.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Values for the UMA ContentSuggestions.Feed.LoadStreamStatus.LoadMore
// histogram. These values are persisted to logs. Entries should not be
// renumbered and numeric values should never be reused. This must be kept
// in sync with FeedLoadStreamStatus in enums.xml.
enum class FeedLoadStreamStatus {
kNoStatus = 0,
kLoadedFromStore = 1,
// Bottom of feed was reached, triggering infinite feed.
kLoadedFromNetwork = 2,
kFailedWithStoreError = 3,
kNoStreamDataInStore = 4,
kModelAlreadyLoaded = 5,
kNoResponseBody = 6,
kProtoTranslationFailed = 7,
kDataInStoreIsStale = 8,
kDataInStoreIsStaleTimestampInFuture = 9,
kCannotLoadFromNetworkSupressedForHistoryDelete_DEPRECATED = 10,
kCannotLoadFromNetworkOffline = 11,
kCannotLoadFromNetworkThrottled = 12,
kLoadNotAllowedEulaNotAccepted = 13,
kLoadNotAllowedArticlesListHidden = 14,
kCannotParseNetworkResponseBody = 15,
kLoadMoreModelIsNotLoaded = 16,
kLoadNotAllowedDisabledByEnterprisePolicy = 17,
kNetworkFetchFailed = 18,
kCannotLoadMoreNoNextPageToken = 19,
// Highest enumerator. Recommended by Histogram metrics best practices.
kMaxValue = kCannotLoadMoreNoNextPageToken,
};
namespace {
// Histogram name for the infinite feed trigger.
const char kDiscoverFeedInfiniteFeedTriggered[] =
"ContentSuggestions.Feed.LoadStreamStatus.LoadMore";
} // namespace
@implementation DiscoverFeedMetricsRecorder
- (void)recordInfiniteFeedTriggered {
UMA_HISTOGRAM_ENUMERATION(kDiscoverFeedInfiniteFeedTriggered,
FeedLoadStreamStatus::kLoadedFromNetwork);
}
@end
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