Commit c388f408 authored by Gauthier Ambard's avatar Gauthier Ambard Committed by Commit Bot

Add feature tracker to the popup menu

This CL adds the feature tracker to display the "new" badge for the
reading list in the tools menu.

Bug: 828382
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: Ifff04e7d6f1ad255759905e88a0a8faceb4d79ff
Reviewed-on: https://chromium-review.googlesource.com/997814
Commit-Queue: Gauthier Ambard <gambard@chromium.org>
Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548715}
parent 7dbab230
...@@ -13,8 +13,10 @@ source_set("popup_menu") { ...@@ -13,8 +13,10 @@ source_set("popup_menu") {
deps = [ deps = [
":popup_menu_ui", ":popup_menu_ui",
"//base", "//base",
"//components/feature_engagement/public",
"//ios/chrome/app/strings", "//ios/chrome/app/strings",
"//ios/chrome/browser/browser_state", "//ios/chrome/browser/browser_state",
"//ios/chrome/browser/feature_engagement",
"//ios/chrome/browser/find_in_page", "//ios/chrome/browser/find_in_page",
"//ios/chrome/browser/reading_list", "//ios/chrome/browser/reading_list",
"//ios/chrome/browser/ui", "//ios/chrome/browser/ui",
...@@ -98,6 +100,7 @@ source_set("unit_tests") { ...@@ -98,6 +100,7 @@ source_set("unit_tests") {
":popup_menu_ui", ":popup_menu_ui",
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//components/feature_engagement/test:test_support",
"//components/reading_list/core", "//components/reading_list/core",
"//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/browser_state:test_support",
"//ios/chrome/browser/ui/toolbar/test", "//ios/chrome/browser/ui/toolbar/test",
...@@ -108,6 +111,7 @@ source_set("unit_tests") { ...@@ -108,6 +111,7 @@ source_set("unit_tests") {
"//ios/web", "//ios/web",
"//ios/web/public/test", "//ios/web/public/test",
"//ios/web/public/test/fakes", "//ios/web/public/test/fakes",
"//testing/gmock",
"//testing/gtest", "//testing/gtest",
"//third_party/ocmock", "//third_party/ocmock",
] ]
......
...@@ -17,9 +17,10 @@ ...@@ -17,9 +17,10 @@
@property(nonatomic, strong) UIImage* image; @property(nonatomic, strong) UIImage* image;
// Whether the cell associated with this item should be enabled. // Whether the cell associated with this item should be enabled.
@property(nonatomic, assign) BOOL enabled; @property(nonatomic, assign) BOOL enabled;
// Number to be displayed in the badge. // Number to be displayed in the badge. If 0, the badge is hidden.
@property(nonatomic, assign) NSInteger badgeNumber; @property(nonatomic, assign) NSInteger badgeNumber;
// Text to be displayed in the badge. Set to nil to hide the badge. // Text to be displayed in the badge. Set to nil to hide the badge. The text
// badge is only displayed if the numbered badge is hidden.
@property(nonatomic, copy) NSString* badgeText; @property(nonatomic, copy) NSString* badgeText;
@end @end
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h" #include "base/metrics/user_metrics_action.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/feature_engagement/tracker_factory.h"
#include "ios/chrome/browser/reading_list/reading_list_model_factory.h" #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
#import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/browser_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
...@@ -140,6 +141,8 @@ PopupMenuCommandType CommandTypeFromPopupType(PopupMenuType type) { ...@@ -140,6 +141,8 @@ PopupMenuCommandType CommandTypeFromPopupType(PopupMenuType type) {
isIncognito:self.browserState->IsOffTheRecord() isIncognito:self.browserState->IsOffTheRecord()
readingListModel:ReadingListModelFactory::GetForBrowserState( readingListModel:ReadingListModelFactory::GetForBrowserState(
self.browserState)]; self.browserState)];
self.mediator.engagementTracker =
feature_engagement::TrackerFactory::GetForBrowserState(self.browserState);
self.mediator.webStateList = self.webStateList; self.mediator.webStateList = self.webStateList;
self.mediator.popupMenu = tableViewController; self.mediator.popupMenu = tableViewController;
self.mediator.dispatcher = static_cast<id<BrowserCommands>>(self.dispatcher); self.mediator.dispatcher = static_cast<id<BrowserCommands>>(self.dispatcher);
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
namespace feature_engagement {
class Tracker;
}
@protocol BrowserCommands; @protocol BrowserCommands;
@class PopupMenuTableViewController; @class PopupMenuTableViewController;
class ReadingListModel; class ReadingListModel;
...@@ -38,6 +41,10 @@ typedef NS_ENUM(NSInteger, PopupMenuType) { ...@@ -38,6 +41,10 @@ typedef NS_ENUM(NSInteger, PopupMenuType) {
@property(nonatomic, strong) PopupMenuTableViewController* popupMenu; @property(nonatomic, strong) PopupMenuTableViewController* popupMenu;
// Dispatcher. // Dispatcher.
@property(nonatomic, weak) id<BrowserCommands> dispatcher; @property(nonatomic, weak) id<BrowserCommands> dispatcher;
// Records events for the use of in-product help. The mediator does not take
// ownership of tracker. Tracker must not be destroyed during lifetime of the
// object.
@property(nonatomic, assign) feature_engagement::Tracker* engagementTracker;
// Disconnect the mediator. // Disconnect the mediator.
- (void)disconnect; - (void)disconnect;
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#import "ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h" #import "ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/feature_engagement/public/tracker.h"
#import "ios/chrome/browser/find_in_page/find_tab_helper.h" #import "ios/chrome/browser/find_in_page/find_tab_helper.h"
#import "ios/chrome/browser/ui/activity_services/canonical_url_retriever.h" #import "ios/chrome/browser/ui/activity_services/canonical_url_retriever.h"
#import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/browser_commands.h"
...@@ -97,6 +99,7 @@ PopupMenuToolsItem* CreateTableViewItem(int titleID, ...@@ -97,6 +99,7 @@ PopupMenuToolsItem* CreateTableViewItem(int titleID,
@synthesize isIncognito = _isIncognito; @synthesize isIncognito = _isIncognito;
@synthesize popupMenu = _popupMenu; @synthesize popupMenu = _popupMenu;
@synthesize dispatcher = _dispatcher; @synthesize dispatcher = _dispatcher;
@synthesize engagementTracker = _engagementTracker;
@synthesize readingListMenuNotifier = _readingListMenuNotifier; @synthesize readingListMenuNotifier = _readingListMenuNotifier;
@synthesize type = _type; @synthesize type = _type;
@synthesize webState = _webState; @synthesize webState = _webState;
...@@ -137,6 +140,16 @@ PopupMenuToolsItem* CreateTableViewItem(int titleID, ...@@ -137,6 +140,16 @@ PopupMenuToolsItem* CreateTableViewItem(int titleID,
_webStateObserver.reset(); _webStateObserver.reset();
_webState = nullptr; _webState = nullptr;
} }
if (_engagementTracker &&
_engagementTracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBadgedReadingListFeature)) {
_engagementTracker->Dismissed(
feature_engagement::kIPHBadgedReadingListFeature);
_engagementTracker = nullptr;
}
_readingListMenuNotifier = nil;
} }
#pragma mark - CRWWebStateObserver #pragma mark - CRWWebStateObserver
...@@ -247,6 +260,18 @@ PopupMenuToolsItem* CreateTableViewItem(int titleID, ...@@ -247,6 +260,18 @@ PopupMenuToolsItem* CreateTableViewItem(int titleID,
} }
} }
- (void)setEngagementTracker:(feature_engagement::Tracker*)engagementTracker {
_engagementTracker = engagementTracker;
if (self.popupMenu && self.readingList && engagementTracker &&
self.engagementTracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBadgedReadingListFeature)) {
self.readingList.badgeText = l10n_util::GetNSStringWithFixup(
IDS_IOS_READING_LIST_CELL_NEW_FEATURE_BADGE);
[self.popupMenu reconfigureCellsForItems:@[ self.readingList ]];
}
}
- (NSArray<NSArray<TableViewItem<PopupMenuItem>*>*>*)items { - (NSArray<NSArray<TableViewItem<PopupMenuItem>*>*>*)items {
if (!_items) { if (!_items) {
switch (self.type) { switch (self.type) {
...@@ -515,6 +540,13 @@ PopupMenuToolsItem* CreateTableViewItem(int titleID, ...@@ -515,6 +540,13 @@ PopupMenuToolsItem* CreateTableViewItem(int titleID,
@"popup_menu_reading_list", kToolsMenuReadingListId); @"popup_menu_reading_list", kToolsMenuReadingListId);
self.readingList.badgeNumber = self.readingList.badgeNumber =
[self.readingListMenuNotifier readingListUnreadCount]; [self.readingListMenuNotifier readingListUnreadCount];
if (self.engagementTracker &&
self.engagementTracker->ShouldTriggerHelpUI(
feature_engagement::kIPHBadgedReadingListFeature)) {
self.readingList.badgeText = l10n_util::GetNSStringWithFixup(
IDS_IOS_READING_LIST_CELL_NEW_FEATURE_BADGE);
}
// TODO(crbug.com/828367): Once the "unseen items effect" is defined, // TODO(crbug.com/828367): Once the "unseen items effect" is defined,
// implement it. // implement it.
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#import "ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h" #import "ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h"
#include "base/time/default_clock.h" #include "base/time/default_clock.h"
#include "components/feature_engagement/test/mock_tracker.h"
#include "components/reading_list/core/reading_list_model_impl.h" #include "components/reading_list/core/reading_list_model_impl.h"
#import "ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.h" #import "ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.h"
#import "ios/chrome/browser/ui/toolbar/test/toolbar_test_navigation_manager.h" #import "ios/chrome/browser/ui/toolbar/test/toolbar_test_navigation_manager.h"
...@@ -17,6 +18,7 @@ ...@@ -17,6 +18,7 @@
#import "ios/web/public/test/fakes/test_web_state.h" #import "ios/web/public/test/fakes/test_web_state.h"
#include "ios/web/public/test/test_web_thread_bundle.h" #include "ios/web/public/test/test_web_thread_bundle.h"
#import "ios/web/public/web_state/web_state_observer_bridge.h" #import "ios/web/public/web_state/web_state_observer_bridge.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/platform_test.h" #include "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h" #import "third_party/ocmock/OCMock/OCMock.h"
#include "third_party/ocmock/gtest_support.h" #include "third_party/ocmock/gtest_support.h"
...@@ -45,7 +47,7 @@ class PopupMenuMediatorTest : public PlatformTest { ...@@ -45,7 +47,7 @@ class PopupMenuMediatorTest : public PlatformTest {
[[PopupMenuMediator alloc] initWithType:PopupMenuTypeToolsMenu [[PopupMenuMediator alloc] initWithType:PopupMenuTypeToolsMenu
isIncognito:YES isIncognito:YES
readingListModel:reading_list_model_.get()]; readingListModel:reading_list_model_.get()];
mediator_non_incognito_ = mediator_ =
[[PopupMenuMediator alloc] initWithType:PopupMenuTypeToolsMenu [[PopupMenuMediator alloc] initWithType:PopupMenuTypeToolsMenu
isIncognito:NO isIncognito:NO
readingListModel:reading_list_model_.get()]; readingListModel:reading_list_model_.get()];
...@@ -61,7 +63,7 @@ class PopupMenuMediatorTest : public PlatformTest { ...@@ -61,7 +63,7 @@ class PopupMenuMediatorTest : public PlatformTest {
// observers when web_state_list_ gets dealloc. // observers when web_state_list_ gets dealloc.
~PopupMenuMediatorTest() override { ~PopupMenuMediatorTest() override {
[mediator_incognito_ disconnect]; [mediator_incognito_ disconnect];
[mediator_non_incognito_ disconnect]; [mediator_ disconnect];
} }
protected: protected:
...@@ -96,7 +98,7 @@ class PopupMenuMediatorTest : public PlatformTest { ...@@ -96,7 +98,7 @@ class PopupMenuMediatorTest : public PlatformTest {
void SetUpActiveWebState() { web_state_list_->ActivateWebStateAt(0); } void SetUpActiveWebState() { web_state_list_->ActivateWebStateAt(0); }
PopupMenuMediator* mediator_incognito_; PopupMenuMediator* mediator_incognito_;
PopupMenuMediator* mediator_non_incognito_; PopupMenuMediator* mediator_;
std::unique_ptr<ReadingListModelImpl> reading_list_model_; std::unique_ptr<ReadingListModelImpl> reading_list_model_;
ToolbarTestWebState* web_state_; ToolbarTestWebState* web_state_;
ToolbarTestNavigationManager* navigation_manager_; ToolbarTestNavigationManager* navigation_manager_;
...@@ -106,3 +108,16 @@ class PopupMenuMediatorTest : public PlatformTest { ...@@ -106,3 +108,16 @@ class PopupMenuMediatorTest : public PlatformTest {
// Mock refusing all calls except -setPopupMenuItems:. // Mock refusing all calls except -setPopupMenuItems:.
id popup_menu_strict_; id popup_menu_strict_;
}; };
// Tests that the feature engagement tracker get notified when the mediator is
// disconnected and the tracker wants the notification badge displayed.
TEST_F(PopupMenuMediatorTest, TestFeatureEngagementDisconnect) {
feature_engagement::test::MockTracker tracker;
EXPECT_CALL(tracker, ShouldTriggerHelpUI(testing::_))
.WillRepeatedly(testing::Return(true));
mediator_.popupMenu = popup_menu_;
mediator_.engagementTracker = &tracker;
EXPECT_CALL(tracker, Dismissed(testing::_));
[mediator_ disconnect];
}
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