Commit 76d7d8ce authored by Ewann's avatar Ewann Committed by Commit Bot

[iOS] Basic ContentSuggestions Entry Context Menu

 - Adds a new Context Menu with a "Copy" action.
 - Wraps the old implementation with a feature flag check.
 - Adds metrics for the new context menu and its action.

Bug: 1093302
Change-Id: Ib814b1c16b18f2855a6cc8ad6d9f425a230ce8be
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2325172
Commit-Queue: Ewann Pellé <ewannpv@chromium.org>
Reviewed-by: default avatarSebastien Lalancette <seblalancette@chromium.org>
Reviewed-by: default avatarSylvain Defresne <sdefresne@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#793174}
parent 4d2068e0
...@@ -68,6 +68,7 @@ source_set("content_suggestions") { ...@@ -68,6 +68,7 @@ source_set("content_suggestions") {
"//ios/chrome/browser/ui/content_suggestions/identifier", "//ios/chrome/browser/ui/content_suggestions/identifier",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
"//ios/chrome/browser/ui/favicon", "//ios/chrome/browser/ui/favicon",
"//ios/chrome/browser/ui/menu",
"//ios/chrome/browser/ui/ntp", "//ios/chrome/browser/ui/ntp",
"//ios/chrome/browser/ui/ntp:ntp_internal", "//ios/chrome/browser/ui/ntp:ntp_internal",
"//ios/chrome/browser/ui/overscroll_actions", "//ios/chrome/browser/ui/overscroll_actions",
...@@ -120,6 +121,7 @@ source_set("content_suggestions_ui") { ...@@ -120,6 +121,7 @@ source_set("content_suggestions_ui") {
"content_suggestions_header_view_controller_delegate.h", "content_suggestions_header_view_controller_delegate.h",
"content_suggestions_layout.h", "content_suggestions_layout.h",
"content_suggestions_layout.mm", "content_suggestions_layout.mm",
"content_suggestions_menu_provider.h",
"content_suggestions_metrics_recording.h", "content_suggestions_metrics_recording.h",
"content_suggestions_view_controller.h", "content_suggestions_view_controller.h",
"content_suggestions_view_controller.mm", "content_suggestions_view_controller.mm",
...@@ -142,6 +144,7 @@ source_set("content_suggestions_ui") { ...@@ -142,6 +144,7 @@ source_set("content_suggestions_ui") {
"//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui:feature_flags",
"//ios/chrome/browser/ui/collection_view", "//ios/chrome/browser/ui/collection_view",
"//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/ui/content_suggestions/cells",
"//ios/chrome/browser/ui/content_suggestions/cells:cells_ui", "//ios/chrome/browser/ui/content_suggestions/cells:cells_ui",
"//ios/chrome/browser/ui/content_suggestions/identifier", "//ios/chrome/browser/ui/content_suggestions/identifier",
"//ios/chrome/browser/ui/elements", "//ios/chrome/browser/ui/elements",
......
...@@ -33,11 +33,13 @@ ...@@ -33,11 +33,13 @@
#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"
#import "ios/chrome/browser/ui/commands/open_new_tab_command.h" #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_data_sink.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_menu_provider.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.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.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller_audience.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller_audience.h"
...@@ -46,6 +48,8 @@ ...@@ -46,6 +48,8 @@
#import "ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h" #import "ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h"
#import "ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h" #import "ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h"
#import "ios/chrome/browser/ui/content_suggestions/theme_change_delegate.h" #import "ios/chrome/browser/ui/content_suggestions/theme_change_delegate.h"
#import "ios/chrome/browser/ui/menu/action_factory.h"
#import "ios/chrome/browser/ui/menu/menu_histograms.h"
#import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.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/ntp/notification_promo_whats_new.h"
#import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h" #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
...@@ -64,6 +68,7 @@ ...@@ -64,6 +68,7 @@
#endif #endif
@interface ContentSuggestionsCoordinator () < @interface ContentSuggestionsCoordinator () <
ContentSuggestionsMenuProvider,
ContentSuggestionsViewControllerAudience, ContentSuggestionsViewControllerAudience,
DiscoverFeedMenuCommands, DiscoverFeedMenuCommands,
OverscrollActionsControllerDelegate, OverscrollActionsControllerDelegate,
...@@ -216,6 +221,10 @@ ...@@ -216,6 +221,10 @@
self.suggestionsViewController.dispatcher = dispatcher; self.suggestionsViewController.dispatcher = dispatcher;
self.suggestionsViewController.discoverFeedMenuHandler = self; self.suggestionsViewController.discoverFeedMenuHandler = self;
if (@available(iOS 13.0, *)) {
self.suggestionsViewController.menuProvider = self;
}
self.NTPMediator.consumer = self.headerController; self.NTPMediator.consumer = self.headerController;
// TODO(crbug.com/1045047): Use HandlerForProtocol after commands protocol // TODO(crbug.com/1045047): Use HandlerForProtocol after commands protocol
// clean up. // clean up.
...@@ -419,4 +428,26 @@ ...@@ -419,4 +428,26 @@
[self.NTPMediator locationBarDidResignFirstResponder]; [self.NTPMediator locationBarDidResignFirstResponder];
} }
#pragma mark - ThemeChangeDelegate
- (UIContextMenuConfiguration*)contextMenuConfigurationForItem:
(ContentSuggestionsMostVisitedItem*)item API_AVAILABLE(ios(13.0)) {
return [UIContextMenuConfiguration
configurationWithIdentifier:nil
previewProvider:nil
actionProvider:^(NSArray<UIMenuElement*>* suggestedActions) {
// Record that this context menu was shown to the user.
RecordMenuShown(MenuScenario::kContentSuggestionsEntry);
ActionFactory* actionFactory = [[ActionFactory alloc]
initWithScenario:MenuScenario::
kContentSuggestionsEntry];
UIAction* copyAction =
[actionFactory actionToCopyURL:item.URL];
return [UIMenu menuWithTitle:@"" children:@[ copyAction ]];
}];
}
@end @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_CONTENT_SUGGESTIONS_MENU_PROVIDER_H_
#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_MENU_PROVIDER_H_
@class ContentSuggestionsMostVisitedItem;
// Protocol for instances that will provide menus to ContentSuggestions
// components.
@protocol ContentSuggestionsMenuProvider
// Creates a context menu configuration instance for the given |item|, which is
// represented on the UI by |view|.
- (UIContextMenuConfiguration*)contextMenuConfigurationForItem:
(ContentSuggestionsMostVisitedItem*)item API_AVAILABLE(ios(13.0));
@end
#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_MENU_PROVIDER_H_
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
@protocol ContentSuggestionsCommands; @protocol ContentSuggestionsCommands;
@protocol ContentSuggestionsDataSource; @protocol ContentSuggestionsDataSource;
@protocol ContentSuggestionsHeaderSynchronizing; @protocol ContentSuggestionsHeaderSynchronizing;
@protocol ContentSuggestionsMenuProvider;
@protocol ContentSuggestionsMetricsRecording; @protocol ContentSuggestionsMetricsRecording;
@protocol ContentSuggestionsViewControllerAudience; @protocol ContentSuggestionsViewControllerAudience;
@protocol DiscoverFeedMenuCommands; @protocol DiscoverFeedMenuCommands;
...@@ -54,6 +55,10 @@ extern NSString* const ...@@ -54,6 +55,10 @@ extern NSString* const
@property(nonatomic, weak) id<ContentSuggestionsMetricsRecording> @property(nonatomic, weak) id<ContentSuggestionsMetricsRecording>
metricsRecorder; metricsRecorder;
// Provider of menu configurations for the contentSuggestions component.
@property(nonatomic, weak) id<ContentSuggestionsMenuProvider> menuProvider
API_AVAILABLE(ios(13.0));
- (void)setDataSource:(id<ContentSuggestionsDataSource>)dataSource; - (void)setDataSource:(id<ContentSuggestionsDataSource>)dataSource;
- (void)setDispatcher:(id<SnackbarCommands>)dispatcher; - (void)setDispatcher:(id<SnackbarCommands>)dispatcher;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_discover_header_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_discover_header_item.h"
#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_discover_item.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_discover_item.h"
#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h" #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h"
#import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
#import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h" #import "ios/chrome/browser/ui/content_suggestions/cells/suggested_content.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizing.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_menu_provider.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recording.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recording.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller_audience.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller_audience.h"
#import "ios/chrome/browser/ui/content_suggestions/discover_feed_menu_commands.h" #import "ios/chrome/browser/ui/content_suggestions/discover_feed_menu_commands.h"
...@@ -31,10 +33,12 @@ ...@@ -31,10 +33,12 @@
#import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h" #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
#import "ios/chrome/browser/ui/toolbar/public/toolbar_utils.h" #import "ios/chrome/browser/ui/toolbar/public/toolbar_utils.h"
#import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/ui_feature_flags.h"
#import "ios/chrome/browser/ui/util/menu_util.h"
#import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
#import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h" #import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h"
#import "ios/chrome/common/ui/colors/semantic_color_names.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h"
#import "ios/chrome/common/ui/util/constraints_ui_util.h" #import "ios/chrome/common/ui/util/constraints_ui_util.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support." #error "This file requires ARC support."
...@@ -236,12 +240,14 @@ NSString* const kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix = ...@@ -236,12 +240,14 @@ NSString* const kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix =
ApplyVisualConstraints(@[ @"V:|[collection]|", @"H:|[collection]|" ], ApplyVisualConstraints(@[ @"V:|[collection]|", @"H:|[collection]|" ],
@{@"collection" : self.collectionView}); @{@"collection" : self.collectionView});
if (!IsNativeContextMenuEnabled()) {
UILongPressGestureRecognizer* longPressRecognizer = UILongPressGestureRecognizer* longPressRecognizer =
[[UILongPressGestureRecognizer alloc] [[UILongPressGestureRecognizer alloc]
initWithTarget:self initWithTarget:self
action:@selector(handleLongPress:)]; action:@selector(handleLongPress:)];
longPressRecognizer.delegate = self; longPressRecognizer.delegate = self;
[self.collectionView addGestureRecognizer:longPressRecognizer]; [self.collectionView addGestureRecognizer:longPressRecognizer];
}
self.overscrollActionsController = [[OverscrollActionsController alloc] self.overscrollActionsController = [[OverscrollActionsController alloc]
initWithScrollView:self.collectionView]; initWithScrollView:self.collectionView];
...@@ -424,6 +430,29 @@ NSString* const kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix = ...@@ -424,6 +430,29 @@ NSString* const kContentSuggestionsMostVisitedAccessibilityIdentifierPrefix =
return cell; return cell;
} }
- (UIContextMenuConfiguration*)collectionView:(UICollectionView*)collectionView
contextMenuConfigurationForItemAtIndexPath:(NSIndexPath*)indexPath
point:(CGPoint)point
API_AVAILABLE(ios(13.0)) {
if (!IsNativeContextMenuEnabled()) {
// Returning nil will allow the gesture to be captured and show the old
// context menus.
return nil;
}
CollectionViewItem* item =
[self.collectionViewModel itemAtIndexPath:indexPath];
if (![item isKindOfClass:[ContentSuggestionsMostVisitedItem class]])
return nil;
ContentSuggestionsMostVisitedItem* contentSuggestionsItem =
base::mac::ObjCCastStrict<ContentSuggestionsMostVisitedItem>(item);
return [self.menuProvider
contextMenuConfigurationForItem:contentSuggestionsItem];
}
#pragma mark - UICollectionViewDataSource #pragma mark - UICollectionViewDataSource
- (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView - (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView
......
...@@ -13,7 +13,8 @@ enum class MenuScenario { ...@@ -13,7 +13,8 @@ enum class MenuScenario {
kBookmarkEntry = 1, kBookmarkEntry = 1,
kReadingListEntry = 2, kReadingListEntry = 2,
kRecentTabsEntry = 3, kRecentTabsEntry = 3,
kMaxValue = kRecentTabsEntry kContentSuggestionsEntry = 4,
kMaxValue = kContentSuggestionsEntry
}; };
// Records a menu shown histogram metric for the |scenario|. // Records a menu shown histogram metric for the |scenario|.
......
...@@ -23,6 +23,8 @@ const char ReadingListEntryActionsHistogram[] = ...@@ -23,6 +23,8 @@ const char ReadingListEntryActionsHistogram[] =
"Mobile.ContextMenu.ReadingListEntry.Actions"; "Mobile.ContextMenu.ReadingListEntry.Actions";
const char RecentTabsEntryActionsHistogram[] = const char RecentTabsEntryActionsHistogram[] =
"Mobile.ContextMenu.RecentTabsEntry.Actions"; "Mobile.ContextMenu.RecentTabsEntry.Actions";
const char ContentSuggestionsEntryActionsHistogram[] =
"Mobile.ContextMenu.ContentSuggestionsEntry.Actions";
} // namespace } // namespace
void RecordMenuShown(MenuScenario scenario) { void RecordMenuShown(MenuScenario scenario) {
...@@ -39,5 +41,7 @@ const char* GetActionsHistogramName(MenuScenario scenario) { ...@@ -39,5 +41,7 @@ const char* GetActionsHistogramName(MenuScenario scenario) {
return ReadingListEntryActionsHistogram; return ReadingListEntryActionsHistogram;
case MenuScenario::kRecentTabsEntry: case MenuScenario::kRecentTabsEntry:
return RecentTabsEntryActionsHistogram; return RecentTabsEntryActionsHistogram;
case MenuScenario::kContentSuggestionsEntry:
return ContentSuggestionsEntryActionsHistogram;
} }
} }
...@@ -37118,6 +37118,7 @@ Called by update_gpu_driver_bug_workaround_entries.py.--> ...@@ -37118,6 +37118,7 @@ Called by update_gpu_driver_bug_workaround_entries.py.-->
<int value="1" label="Bookmark Entry"/> <int value="1" label="Bookmark Entry"/>
<int value="2" label="ReadingList Entry"/> <int value="2" label="ReadingList Entry"/>
<int value="3" label="RecentTabs Entry"/> <int value="3" label="RecentTabs Entry"/>
<int value="4" label="ContentSuggestions Entry"/>
</enum> </enum>
<enum name="IOSNTPImpression"> <enum name="IOSNTPImpression">
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