blob: 83d84ca2df0fe0c1e12d4c52136e81aff65e1f37 [file] [log] [blame]
// Copyright 2021 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/menu/browser_action_factory.h"
#include "base/strings/sys_string_conversions.h"
#include "components/open_from_clipboard/clipboard_recent_content.h"
#include "components/prefs/pref_service.h"
#include "components/search_engines/template_url_service.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/policy/policy_util.h"
#import "ios/chrome/browser/prefs/pref_names.h"
#import "ios/chrome/browser/search_engines/template_url_service_factory.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/browser_coordinator_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/commands/load_query_commands.h"
#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
#import "ios/chrome/browser/ui/commands/qr_scanner_commands.h"
#import "ios/chrome/browser/ui/icons/action_icon.h"
#import "ios/chrome/browser/ui/icons/chrome_symbol.h"
#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h"
#import "ios/chrome/browser/ui/main/scene_state_browser_agent.h"
#include "ios/chrome/browser/ui/ui_feature_flags.h"
#import "ios/chrome/browser/ui/util/pasteboard_util.h"
#import "ios/chrome/browser/url_loading/image_search_param_generator.h"
#import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
#import "ios/chrome/browser/url_loading/url_loading_params.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util_mac.h"
#import "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface BrowserActionFactory ()
// Current browser instance.
@property(nonatomic, assign) Browser* browser;
@end
@implementation BrowserActionFactory
- (instancetype)initWithBrowser:(Browser*)browser
scenario:(MenuScenario)scenario {
DCHECK(browser);
if (self = [super initWithScenario:scenario]) {
_browser = browser;
}
return self;
}
- (UIAction*)actionToOpenInNewTabWithURL:(const GURL)URL
completion:(ProceduralBlock)completion {
UrlLoadParams params = UrlLoadParams::InNewTab(URL);
UrlLoadingBrowserAgent* loadingAgent =
UrlLoadingBrowserAgent::FromBrowser(self.browser);
return [self actionToOpenInNewTabWithBlock:^{
loadingAgent->Load(params);
if (completion) {
completion();
}
}];
}
- (UIAction*)actionToOpenInNewIncognitoTabWithURL:(const GURL)URL
completion:(ProceduralBlock)completion {
if (!_browser)
return nil;
UrlLoadParams params = UrlLoadParams::InNewTab(URL);
params.in_incognito = YES;
UrlLoadingBrowserAgent* loadingAgent =
UrlLoadingBrowserAgent::FromBrowser(self.browser);
return [self actionToOpenInNewIncognitoTabWithBlock:^{
loadingAgent->Load(params);
if (completion) {
completion();
}
}];
}
- (UIAction*)actionToOpenInNewIncognitoTabWithBlock:(ProceduralBlock)block {
// Wrap the block with the incognito auth check, if necessary.
IncognitoReauthSceneAgent* reauthAgent = [IncognitoReauthSceneAgent
agentFromScene:SceneStateBrowserAgent::FromBrowser(self.browser)
->GetSceneState()];
if (reauthAgent.authenticationRequired) {
block = ^{
[reauthAgent
authenticateIncognitoContentWithCompletionBlock:^(BOOL success) {
if (success && block != nullptr) {
block();
}
}];
};
}
UIImage* image = UseSymbols() ? CustomSymbolWithPointSize(
kIncognitoSymbol, kSymbolActionPointSize)
: [UIImage imageNamed:@"open_in_incognito"];
return [self actionWithTitle:l10n_util::GetNSString(
IDS_IOS_OPEN_IN_INCOGNITO_ACTION_TITLE)
image:image
type:MenuActionType::OpenInNewIncognitoTab
block:block];
}
- (UIAction*)actionToOpenInNewWindowWithURL:(const GURL)URL
activityOrigin:
(WindowActivityOrigin)activityOrigin {
id<ApplicationCommands> windowOpener = HandlerForProtocol(
self.browser->GetCommandDispatcher(), ApplicationCommands);
UIImage* image = UseSymbols()
? DefaultSymbolWithPointSize(kNewWindowActionSymbol,
kSymbolActionPointSize)
: [UIImage imageNamed:@"open_new_window"];
NSUserActivity* activity = ActivityToLoadURL(activityOrigin, URL);
return [self actionWithTitle:l10n_util::GetNSString(
IDS_IOS_CONTENT_CONTEXT_OPENINNEWWINDOW)
image:image
type:MenuActionType::OpenInNewWindow
block:^{
[windowOpener openNewWindowWithActivity:activity];
}];
}
- (UIAction*)actionToOpenInNewWindowWithActivity:(NSUserActivity*)activity {
id<ApplicationCommands> windowOpener = HandlerForProtocol(
self.browser->GetCommandDispatcher(), ApplicationCommands);
UIImage* image = UseSymbols()
? DefaultSymbolWithPointSize(kNewWindowActionSymbol,
kSymbolActionPointSize)
: [UIImage imageNamed:@"open_new_window"];
return [self actionWithTitle:l10n_util::GetNSString(
IDS_IOS_CONTENT_CONTEXT_OPENINNEWWINDOW)
image:image
type:MenuActionType::OpenInNewWindow
block:^{
[windowOpener openNewWindowWithActivity:activity];
}];
}
- (UIAction*)actionOpenImageWithURL:(const GURL)URL
completion:(ProceduralBlock)completion {
UrlLoadingBrowserAgent* loadingAgent =
UrlLoadingBrowserAgent::FromBrowser(self.browser);
UIImage* image = UseSymbols()
? DefaultSymbolWithPointSize(kOpenImageActionSymbol,
kSymbolActionPointSize)
: [UIImage imageNamed:@"open"];
UIAction* action = [self
actionWithTitle:l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENIMAGE)
image:image
type:MenuActionType::OpenImageInCurrentTab
block:^{
loadingAgent->Load(UrlLoadParams::InCurrentTab(URL));
if (completion) {
completion();
}
}];
return action;
}
- (UIAction*)actionOpenImageInNewTabWithUrlLoadParams:(UrlLoadParams)params
completion:
(ProceduralBlock)completion {
UrlLoadingBrowserAgent* loadingAgent =
UrlLoadingBrowserAgent::FromBrowser(self.browser);
UIImage* image = UseSymbols()
? CustomSymbolWithPointSize(kPhotoBadgePlusSymbol,
kSymbolActionPointSize)
: [UIImage imageNamed:@"open_image_in_new_tab"];
UIAction* action =
[self actionWithTitle:l10n_util::GetNSString(
IDS_IOS_CONTENT_CONTEXT_OPENIMAGENEWTAB)
image:image
type:MenuActionType::OpenImageInNewTab
block:^{
loadingAgent->Load(params);
if (completion) {
completion();
}
}];
return action;
}
- (UIAction*)actionToOpenNewTab {
id<ApplicationCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), ApplicationCommands);
UIAction* action =
[self actionWithTitle:l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_NEW_TAB)
image:DefaultSymbolWithPointSize(kNewTabActionSymbol,
kSymbolActionPointSize)
type:MenuActionType::OpenNewTab
block:^{
[handler openURLInNewTab:[OpenNewTabCommand
commandWithIncognito:NO]];
}];
if (IsIncognitoModeForced(self.browser->GetBrowserState()->GetPrefs())) {
action.attributes = UIMenuElementAttributesDisabled;
}
return action;
}
- (UIAction*)actionToOpenNewIncognitoTab {
id<ApplicationCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), ApplicationCommands);
// TODO(crbug.com/1285015): Add the image.
UIAction* action =
[self actionWithTitle:l10n_util::GetNSString(
IDS_IOS_TOOLS_MENU_NEW_INCOGNITO_TAB)
image:nil
type:MenuActionType::OpenNewIncognitoTab
block:^{
[handler openURLInNewTab:[OpenNewTabCommand
commandWithIncognito:YES]];
}];
if (IsIncognitoModeDisabled(self.browser->GetBrowserState()->GetPrefs())) {
action.attributes = UIMenuElementAttributesDisabled;
}
return action;
}
- (UIAction*)actionToCloseCurrentTab {
__weak id<BrowserCoordinatorCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), BrowserCoordinatorCommands);
UIAction* action =
[self actionWithTitle:l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_CLOSE_TAB)
image:DefaultSymbolWithPointSize(kXMarkSymbol,
kSymbolActionPointSize)
type:MenuActionType::CloseCurrentTabs
block:^{
[handler closeCurrentTab];
}];
action.attributes = UIMenuElementAttributesDestructive;
return action;
}
- (UIAction*)actionToShowQRScanner {
id<QRScannerCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), QRScannerCommands);
return [self
actionWithTitle:l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_QR_SCANNER)
image:DefaultSymbolWithPointSize(kQRCodeFinderActionSymbol,
kSymbolActionPointSize)
type:MenuActionType::ShowQRScanner
block:^{
[handler showQRScanner];
}];
}
- (UIAction*)actionToStartVoiceSearch {
id<ApplicationCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), ApplicationCommands);
return [self
actionWithTitle:l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_VOICE_SEARCH)
image:DefaultSymbolWithPointSize(kMicrophoneSymbol,
kSymbolActionPointSize)
type:MenuActionType::StartVoiceSearch
block:^{
[handler startVoiceSearch];
}];
}
- (UIAction*)actionToStartNewSearch {
id<ApplicationCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), ApplicationCommands);
UIAction* action = [self
actionWithTitle:l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_NEW_SEARCH)
image:DefaultSymbolWithPointSize(kSearchSymbol,
kSymbolActionPointSize)
type:MenuActionType::StartNewSearch
block:^{
OpenNewTabCommand* command =
[OpenNewTabCommand commandWithIncognito:NO];
command.shouldFocusOmnibox = YES;
[handler openURLInNewTab:command];
}];
if (IsIncognitoModeForced(self.browser->GetBrowserState()->GetPrefs())) {
action.attributes = UIMenuElementAttributesDisabled;
}
return action;
}
- (UIAction*)actionToStartNewIncognitoSearch {
id<ApplicationCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), ApplicationCommands);
// TODO(crbug.com/1285015): Add the image.
UIAction* action =
[self actionWithTitle:l10n_util::GetNSString(
IDS_IOS_TOOLS_MENU_NEW_INCOGNITO_SEARCH)
image:nil
type:MenuActionType::StartNewIcognitoSearch
block:^{
OpenNewTabCommand* command =
[OpenNewTabCommand commandWithIncognito:NO];
command.shouldFocusOmnibox = YES;
[handler openURLInNewTab:command];
}];
if (IsIncognitoModeDisabled(self.browser->GetBrowserState()->GetPrefs())) {
action.attributes = UIMenuElementAttributesDisabled;
}
return action;
}
- (UIAction*)actionToSearchCopiedImage {
__weak __typeof(self) weakSelf = self;
void (^clipboardAction)(absl::optional<gfx::Image>) =
^(absl::optional<gfx::Image> optionalImage) {
if (!optionalImage || !weakSelf) {
return;
}
__typeof(weakSelf) strongSelf = weakSelf;
TemplateURLService* templateURLService =
ios::TemplateURLServiceFactory::GetForBrowserState(
strongSelf.browser->GetBrowserState());
UIImage* image = [optionalImage.value().ToUIImage() copy];
web::NavigationManager::WebLoadParams webParams =
ImageSearchParamGenerator::LoadParamsForImage(image,
templateURLService);
UrlLoadParams params = UrlLoadParams::InCurrentTab(webParams);
UrlLoadingBrowserAgent::FromBrowser(strongSelf.browser)->Load(params);
};
return [self actionWithTitle:l10n_util::GetNSString(
IDS_IOS_TOOLS_MENU_SEARCH_COPIED_IMAGE)
image:DefaultSymbolWithPointSize(
kClipboardActionSymbol,
kSymbolActionPointSize)
type:MenuActionType::SearchCopiedImage
block:^{
ClipboardRecentContent::GetInstance()
->GetRecentImageFromClipboard(
base::BindOnce(clipboardAction));
}];
}
- (UIAction*)actionToSearchCopiedURL {
id<LoadQueryCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), LoadQueryCommands);
void (^clipboardAction)(absl::optional<GURL>) =
^(absl::optional<GURL> optionalURL) {
if (!optionalURL) {
return;
}
NSString* URL = base::SysUTF8ToNSString(optionalURL.value().spec());
dispatch_async(dispatch_get_main_queue(), ^{
[handler loadQuery:URL immediately:YES];
});
};
return [self actionWithTitle:l10n_util::GetNSString(
IDS_IOS_TOOLS_MENU_VISIT_COPIED_LINK)
image:DefaultSymbolWithPointSize(
kClipboardActionSymbol,
kSymbolActionPointSize)
type:MenuActionType::VisitCopiedLink
block:^{
ClipboardRecentContent::GetInstance()
->GetRecentURLFromClipboard(
base::BindOnce(clipboardAction));
}];
}
- (UIAction*)actionToSearchCopiedText {
id<LoadQueryCommands> handler = HandlerForProtocol(
self.browser->GetCommandDispatcher(), LoadQueryCommands);
void (^clipboardAction)(absl::optional<std::u16string>) =
^(absl::optional<std::u16string> optionalText) {
if (!optionalText) {
return;
}
NSString* query = base::SysUTF16ToNSString(optionalText.value());
dispatch_async(dispatch_get_main_queue(), ^{
[handler loadQuery:query immediately:YES];
});
};
return [self actionWithTitle:l10n_util::GetNSString(
IDS_IOS_TOOLS_MENU_SEARCH_COPIED_TEXT)
image:DefaultSymbolWithPointSize(
kClipboardActionSymbol,
kSymbolActionPointSize)
type:MenuActionType::SearchCopiedText
block:^{
ClipboardRecentContent::GetInstance()
->GetRecentTextFromClipboard(
base::BindOnce(clipboardAction));
}];
}
@end