Commit bfb28321 authored by Kurt Horimoto's avatar Kurt Horimoto Committed by Commit Bot

[iOS] Created ReadingListContextMenuCoordinator.

This encapsulates the context menu functionality that will be shared
across the legacy and new implementation of the reading list UI.

Bug: 805209
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: Ie17832216d81a1b243ea45ba0cb7cb98c6805115
Reviewed-on: https://chromium-review.googlesource.com/1101914
Commit-Queue: Kurt Horimoto <kkhorimoto@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Reviewed-by: default avatarSergio Collazos <sczs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569777}
parent d71ce763
...@@ -41,6 +41,7 @@ source_set("reading_list") { ...@@ -41,6 +41,7 @@ source_set("reading_list") {
"//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/favicon:favicon_ui", "//ios/chrome/browser/ui/favicon:favicon_ui",
"//ios/chrome/browser/ui/reading_list/context_menu",
"//ios/chrome/browser/ui/side_swipe", "//ios/chrome/browser/ui/side_swipe",
"//ios/chrome/browser/ui/static_content", "//ios/chrome/browser/ui/static_content",
"//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util",
......
# Copyright 2018 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.
source_set("context_menu") {
sources = [
"reading_list_context_menu_commands.h",
"reading_list_context_menu_coordinator.h",
"reading_list_context_menu_coordinator.mm",
"reading_list_context_menu_params.h",
"reading_list_context_menu_params.mm",
]
deps = [
"//base",
"//components/feature_engagement/public",
"//ios/chrome/app/strings:ios_strings_grit",
"//ios/chrome/browser/ui/alert_coordinator",
"//ui/base",
"//ui/strings:ui_strings_grit",
"//url",
]
configs += [ "//build/config/compiler:enable_arc" ]
}
// Copyright 2018 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_READING_LIST_CONTEXT_MENU_READING_LIST_CONTEXT_MENU_COMMANDS_H_
#define IOS_CHROME_BROWSER_UI_READING_LIST_CONTEXT_MENU_READING_LIST_CONTEXT_MENU_COMMANDS_H_
@class ReadingListContextMenuParams;
// Commands issued from the context menu shown for reading list items.
@protocol ReadingListContextMenuCommands
// Opens |param|'s online URL in a new tab.
- (void)openURLInNewTabForContextMenuWithParams:
(ReadingListContextMenuParams*)params;
// Opens |param|'s online in a new incognito tab.
- (void)openURLInNewIncognitoTabForContextMenuWithParams:
(ReadingListContextMenuParams*)params;
// Copies |param|'s online URL to the pasteboard.
- (void)copyURLForContextMenuWithParams:(ReadingListContextMenuParams*)params;
// Opens the offline page at |offlineURL| in a new tab.
- (void)openOfflineURLInNewTabForContextMenuWithParams:
(ReadingListContextMenuParams*)params;
// Cancels the context menu created with |params|.
- (void)cancelReadingListContextMenuWithParams:
(ReadingListContextMenuParams*)params;
@end
#endif // IOS_CHROME_BROWSER_UI_READING_LIST_CONTEXT_MENU_READING_LIST_CONTEXT_MENU_COMMANDS_H_
// Copyright 2018 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_READING_LIST_CONTEXT_MENU_READING_LIST_CONTEXT_MENU_COORDINATOR_H_
#define IOS_CHROME_BROWSER_UI_READING_LIST_CONTEXT_MENU_READING_LIST_CONTEXT_MENU_COORDINATOR_H_
#import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
@protocol ReadingListContextMenuCommands;
@class ReadingListContextMenuParams;
// Coordinator used for the Reading List context menu.
@interface ReadingListContextMenuCoordinator : ActionSheetCoordinator
// The parameters passed on initialization.
@property(nonatomic, strong, readonly) ReadingListContextMenuParams* params;
// The handler for commands originating from the context menu.
@property(nonatomic, weak) id<ReadingListContextMenuCommands> commandHandler;
// Designated initializer.
- (instancetype)initWithBaseViewController:(UIViewController*)viewController
params:(ReadingListContextMenuParams*)params
NS_DESIGNATED_INITIALIZER;
// ReadingListContextMenuCoordinator must be created using
// ReadingListContextMenuParams.
- (instancetype)initWithBaseViewController:(UIViewController*)viewController
title:(NSString*)title
message:(NSString*)message
rect:(CGRect)rect
view:(UIView*)view NS_UNAVAILABLE;
- (instancetype)initWithBaseViewController:(UIViewController*)viewController
title:(NSString*)title
message:(NSString*)message
barButtonItem:(UIBarButtonItem*)barButtonItem
NS_UNAVAILABLE;
- (instancetype)initWithBaseViewController:(UIViewController*)viewController
title:(NSString*)title
message:(NSString*)message NS_UNAVAILABLE;
@end
#endif // IOS_CHROME_BROWSER_UI_READING_LIST_CONTEXT_MENU_READING_LIST_CONTEXT_MENU_COORDINATOR_H_
// Copyright 2018 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/reading_list/context_menu/reading_list_context_menu_coordinator.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "components/feature_engagement/public/event_constants.h"
#include "components/feature_engagement/public/tracker.h"
#import "ios/chrome/browser/ui/reading_list/context_menu/reading_list_context_menu_commands.h"
#import "ios/chrome/browser/ui/reading_list/context_menu/reading_list_context_menu_params.h"
#include "ios/chrome/grit/ios_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/strings/grit/ui_strings.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Action chosen by the user in the context menu, for UMA report.
// These match tools/metrics/histograms/histograms.xml.
enum UMAContextMenuAction {
// The user opened the entry in a new tab.
NEW_TAB = 0,
// The user opened the entry in a new incognito tab.
NEW_INCOGNITO_TAB = 1,
// The user copied the url of the entry.
COPY_LINK = 2,
// The user chose to view the offline version of the entry.
VIEW_OFFLINE = 3,
// The user cancelled the context menu.
CANCEL = 4,
// Add new enum above ENUM_MAX.
ENUM_MAX
};
} // namespace
@interface ReadingListContextMenuCoordinator ()
// Whether the coordinator has been started.
@property(nonatomic, assign, getter=isStarted) BOOL started;
@end
@implementation ReadingListContextMenuCoordinator
@synthesize commandHandler = _commandHandler;
@synthesize params = _params;
@synthesize started = _started;
- (instancetype)initWithBaseViewController:(UIViewController*)viewController
params:
(ReadingListContextMenuParams*)params {
self = [super initWithBaseViewController:viewController
title:params.title
message:params.message
rect:params.rect
view:params.view];
if (self) {
DCHECK(params);
_params = params;
}
return self;
}
#pragma mark - ChromeCoordinator
- (void)start {
if (self.started)
return;
__weak id<ReadingListContextMenuCommands> weakCommandHandler =
self.commandHandler;
__weak ReadingListContextMenuParams* weakParams = self.params;
// Add "Open In New Tab" option.
NSString* openInNewTabTitle =
l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB);
[self addItemWithTitle:openInNewTabTitle
action:^{
[weakCommandHandler
openURLInNewTabForContextMenuWithParams:weakParams];
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu",
NEW_TAB, ENUM_MAX);
}
style:UIAlertActionStyleDefault];
// Add "Open In New Incognito Tab" option;
NSString* openInNewTabIncognitoTitle =
l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB);
[self addItemWithTitle:openInNewTabIncognitoTitle
action:^{
[weakCommandHandler
openURLInNewIncognitoTabForContextMenuWithParams:
weakParams];
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu",
NEW_INCOGNITO_TAB, ENUM_MAX);
}
style:UIAlertActionStyleDefault];
// Add "Copy Link URL" option.
NSString* copyLinkTitle =
l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_COPY);
[self addItemWithTitle:copyLinkTitle
action:^{
[weakCommandHandler
copyURLForContextMenuWithParams:weakParams];
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu",
COPY_LINK, ENUM_MAX);
}
style:UIAlertActionStyleDefault];
// Add "View Offline Version In New Tab" option if there is an offline URL.
if (self.params.offlineURL.is_valid()) {
NSString* viewOfflineVersionTitle =
l10n_util::GetNSString(IDS_IOS_READING_LIST_CONTENT_CONTEXT_OFFLINE);
[self addItemWithTitle:viewOfflineVersionTitle
action:^{
[weakCommandHandler
openOfflineURLInNewTabForContextMenuWithParams:
weakParams];
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu",
VIEW_OFFLINE, ENUM_MAX);
}
style:UIAlertActionStyleDefault];
}
// Add "Cancel" option.
[self addItemWithTitle:l10n_util::GetNSString(IDS_APP_CANCEL)
action:^{
[weakCommandHandler
cancelReadingListContextMenuWithParams:weakParams];
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu", CANCEL,
ENUM_MAX);
}
style:UIAlertActionStyleCancel];
[super start];
self.started = YES;
}
@end
// Copyright 2018 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_READING_LIST_CONTEXT_MENU_READING_LIST_CONTEXT_MENU_PARAMS_H_
#define IOS_CHROME_BROWSER_UI_READING_LIST_CONTEXT_MENU_READING_LIST_CONTEXT_MENU_PARAMS_H_
#import <UIKit/UIKit.h>
class GURL;
// Parameter object used to construct ReadingListContextMenuCoordinators.
@interface ReadingListContextMenuParams : NSObject
// The context menu title.
@property(nonatomic, copy) NSString* title;
// The context menu message.
@property(nonatomic, copy) NSString* message;
// The location within |view| from which to display the context menu.
@property(nonatomic, assign) CGRect rect;
// The view from which the context menu should be displayed.
@property(nonatomic, weak) UIView* view;
// The URL of the reading list entry.
@property(nonatomic, assign) GURL entryURL;
// The offline URL of the reading list entry.
@property(nonatomic, assign) GURL offlineURL;
@end
#endif // IOS_CHROME_BROWSER_UI_READING_LIST_CONTEXT_MENU_READING_LIST_CONTEXT_MENU_PARAMS_H_
// Copyright 2018 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/reading_list/context_menu/reading_list_context_menu_params.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation ReadingListContextMenuParams
@synthesize title = _title;
@synthesize message = _message;
@synthesize rect = _rect;
@synthesize view = _view;
@synthesize entryURL = _entryURL;
@synthesize offlineURL = _offlineURL;
@end
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
#include "ios/chrome/browser/reading_list/reading_list_download_service.h" #include "ios/chrome/browser/reading_list/reading_list_download_service.h"
#include "ios/chrome/browser/reading_list/reading_list_download_service_factory.h" #include "ios/chrome/browser/reading_list/reading_list_download_service_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/alert_coordinator/action_sheet_coordinator.h" #import "ios/chrome/browser/ui/reading_list/context_menu/reading_list_context_menu_commands.h"
#import "ios/chrome/browser/ui/reading_list/context_menu/reading_list_context_menu_coordinator.h"
#import "ios/chrome/browser/ui/reading_list/context_menu/reading_list_context_menu_params.h"
#import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h" #import "ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.h"
#import "ios/chrome/browser/ui/reading_list/reading_list_mediator.h" #import "ios/chrome/browser/ui/reading_list/reading_list_mediator.h"
#import "ios/chrome/browser/ui/reading_list/reading_list_toolbar.h" #import "ios/chrome/browser/ui/reading_list/reading_list_toolbar.h"
...@@ -38,39 +40,28 @@ ...@@ -38,39 +40,28 @@
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
namespace { @interface ReadingListCoordinator ()<ReadingListContextMenuCommands>
// Action chosen by the user in the context menu, for UMA report.
// These match tools/metrics/histograms/histograms.xml.
enum UMAContextMenuAction {
// The user opened the entry in a new tab.
NEW_TAB = 0,
// The user opened the entry in a new incognito tab.
NEW_INCOGNITO_TAB = 1,
// The user copied the url of the entry.
COPY_LINK = 2,
// The user chose to view the offline version of the entry.
VIEW_OFFLINE = 3,
// The user cancelled the context menu.
CANCEL = 4,
// Add new enum above ENUM_MAX.
ENUM_MAX
};
}
@interface ReadingListCoordinator ()
@property(nonatomic, assign) ios::ChromeBrowserState* browserState; @property(nonatomic, assign) ios::ChromeBrowserState* browserState;
// Used to load the Reading List pages. // Used to load the Reading List pages.
@property(nonatomic, weak) id<UrlLoader> URLLoader; @property(nonatomic, weak) id<UrlLoader> URLLoader;
// The container view containing both the collection view and the toolbar.
@property(nonatomic, strong) ReadingListViewController* containerViewController; @property(nonatomic, strong) ReadingListViewController* containerViewController;
@property(nonatomic, strong) AlertCoordinator* alertCoordinator; // The collection view controller that displays the reading list items (owned by
// |containerViewController|).
@property(nonatomic, weak)
ReadingListCollectionViewController* collectionViewController;
// The context menu displayed for long-presses on reading list items.
@property(nonatomic, strong)
ReadingListContextMenuCoordinator* contextMenuCoordinator;
@end @end
@implementation ReadingListCoordinator @implementation ReadingListCoordinator
@synthesize alertCoordinator = _alertCoordinator;
@synthesize containerViewController = _containerViewController; @synthesize containerViewController = _containerViewController;
@synthesize collectionViewController = _collectionViewController;
@synthesize contextMenuCoordinator = _contextMenuCoordinator;
@synthesize URLLoader = _URLLoader; @synthesize URLLoader = _URLLoader;
@synthesize browserState = _browserState; @synthesize browserState = _browserState;
@synthesize mediator = _mediator; @synthesize mediator = _mediator;
...@@ -108,6 +99,7 @@ enum UMAContextMenuAction { ...@@ -108,6 +99,7 @@ enum UMAContextMenuAction {
toolbar:toolbar]; toolbar:toolbar];
collectionViewController.delegate = self; collectionViewController.delegate = self;
self.collectionViewController = collectionViewController;
self.containerViewController = [[ReadingListViewController alloc] self.containerViewController = [[ReadingListViewController alloc]
initWithCollectionViewController:collectionViewController initWithCollectionViewController:collectionViewController
...@@ -161,83 +153,26 @@ enum UMAContextMenuAction { ...@@ -161,83 +153,26 @@ enum UMAContextMenuAction {
} }
const GURL entryURL = entry->URL(); const GURL entryURL = entry->URL();
__weak ReadingListCoordinator* weakSelf = self; GURL offlineURL;
__weak ReadingListCollectionViewController* weakCollection =
readingListCollectionViewController;
_alertCoordinator = [[ActionSheetCoordinator alloc]
initWithBaseViewController:self.containerViewController
title:readingListItem.title
message:readingListItem.subtitle
rect:CGRectMake(menuLocation.x, menuLocation.y, 0,
0)
view:readingListCollectionViewController
.collectionView];
NSString* openInNewTabTitle =
l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB);
[_alertCoordinator
addItemWithTitle:openInNewTabTitle
action:^{
[weakSelf readingListCollectionViewController:weakCollection
openNewTabWithURL:entryURL
incognito:NO];
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu", NEW_TAB,
ENUM_MAX);
}
style:UIAlertActionStyleDefault];
NSString* openInNewTabIncognitoTitle =
l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB);
[_alertCoordinator
addItemWithTitle:openInNewTabIncognitoTitle
action:^{
[weakSelf readingListCollectionViewController:weakCollection
openNewTabWithURL:entryURL
incognito:YES];
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu",
NEW_INCOGNITO_TAB, ENUM_MAX);
}
style:UIAlertActionStyleDefault];
NSString* copyLinkTitle =
l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_COPY);
[_alertCoordinator
addItemWithTitle:copyLinkTitle
action:^{
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu",
COPY_LINK, ENUM_MAX);
StoreURLInPasteboard(entryURL);
}
style:UIAlertActionStyleDefault];
if (entry->DistilledState() == ReadingListEntry::PROCESSED) { if (entry->DistilledState() == ReadingListEntry::PROCESSED) {
GURL offlineURL = reading_list::OfflineURLForPath( offlineURL = reading_list::OfflineURLForPath(
entry->DistilledPath(), entryURL, entry->DistilledURL()); entry->DistilledPath(), entryURL, entry->DistilledURL());
NSString* viewOfflineVersionTitle =
l10n_util::GetNSString(IDS_IOS_READING_LIST_CONTENT_CONTEXT_OFFLINE);
[_alertCoordinator
addItemWithTitle:viewOfflineVersionTitle
action:^{
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu",
VIEW_OFFLINE, ENUM_MAX);
[weakSelf readingListCollectionViewController:weakCollection
openOfflineURL:offlineURL
correspondingEntryURL:entryURL];
}
style:UIAlertActionStyleDefault];
} }
[_alertCoordinator ReadingListContextMenuParams* params =
addItemWithTitle:l10n_util::GetNSString(IDS_APP_CANCEL) [[ReadingListContextMenuParams alloc] init];
action:^{ params.title = readingListItem.title;
UMA_HISTOGRAM_ENUMERATION("ReadingList.ContextMenu", CANCEL, params.message = readingListItem.subtitle;
ENUM_MAX); params.rect = CGRectMake(menuLocation.x, menuLocation.y, 0, 0);
} params.view = readingListCollectionViewController.collectionView;
style:UIAlertActionStyleCancel]; params.entryURL = entryURL;
params.offlineURL = offlineURL;
[_alertCoordinator start]; self.contextMenuCoordinator = [[ReadingListContextMenuCoordinator alloc]
initWithBaseViewController:self.containerViewController
params:params];
self.contextMenuCoordinator.commandHandler = self;
[self.contextMenuCoordinator start];
} }
- (void) - (void)
...@@ -302,6 +237,50 @@ readingListCollectionViewController: ...@@ -302,6 +237,50 @@ readingListCollectionViewController:
} }
} }
#pragma mark - ReadingListContextMenuCommands
- (void)openURLInNewTabForContextMenuWithParams:
(ReadingListContextMenuParams*)params {
[self readingListCollectionViewController:self.collectionViewController
openNewTabWithURL:params.entryURL
incognito:NO];
[self cleanUpContextMenu];
}
- (void)openURLInNewIncognitoTabForContextMenuWithParams:
(ReadingListContextMenuParams*)params {
[self readingListCollectionViewController:self.collectionViewController
openNewTabWithURL:params.entryURL
incognito:YES];
[self cleanUpContextMenu];
}
- (void)copyURLForContextMenuWithParams:(ReadingListContextMenuParams*)params {
StoreURLInPasteboard(params.entryURL);
[self cleanUpContextMenu];
}
- (void)openOfflineURLInNewTabForContextMenuWithParams:
(ReadingListContextMenuParams*)params {
[self readingListCollectionViewController:self.collectionViewController
openOfflineURL:params.offlineURL
correspondingEntryURL:params.entryURL];
[self cleanUpContextMenu];
}
- (void)cancelReadingListContextMenuWithParams:
(ReadingListContextMenuParams*)params {
[self cleanUpContextMenu];
}
#pragma mark - Context Menu Helpers
// Stops the context menu coordinator and resets the property.
- (void)cleanUpContextMenu {
[self.contextMenuCoordinator stop];
self.contextMenuCoordinator = nil;
}
#pragma mark - Private #pragma mark - Private
// Opens the offline url |offlineURL| of the entry saved in the reading list // Opens the offline url |offlineURL| of the entry saved in the reading list
......
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