blob: 2a644b53512b282dec802b640721103a0f38de40 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// 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/bookmarks/bookmark_interaction_controller.h"
#import <stdint.h>
#import <MaterialComponents/MaterialSnackbar.h>
#import "base/check_op.h"
#import "base/mac/foundation_util.h"
#import "base/metrics/user_metrics.h"
#import "base/metrics/user_metrics_action.h"
#import "base/notreached.h"
#import "base/strings/utf_string_conversions.h"
#import "base/time/time.h"
#import "components/bookmarks/browser/bookmark_model.h"
#import "components/bookmarks/browser/bookmark_utils.h"
#import "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/main/browser.h"
#import "ios/chrome/browser/metrics/new_tab_page_uma.h"
#import "ios/chrome/browser/tabs/tab_title_util.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller_delegate.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_mediator.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller_delegate.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_path_cache.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_transitioning_delegate.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
#import "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
#import "ios/chrome/browser/ui/commands/snackbar_commands.h"
#import "ios/chrome/browser/ui/default_promo/default_browser_utils.h"
#import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
#import "ios/chrome/browser/ui/table_view/table_view_presentation_controller.h"
#import "ios/chrome/browser/ui/table_view/table_view_presentation_controller_delegate.h"
#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
#import "ios/chrome/browser/ui/util/url_with_title.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/browser/url_loading/url_loading_util.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ios/web/public/navigation/navigation_manager.h"
#import "ios/web/public/navigation/referrer.h"
#import "ios/web/public/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using bookmarks::BookmarkModel;
using bookmarks::BookmarkNode;
namespace {
// Tracks the type of UI that is currently being presented.
enum class PresentedState {
NONE,
BOOKMARK_BROWSER,
BOOKMARK_EDITOR,
FOLDER_EDITOR,
FOLDER_SELECTION,
};
} // namespace
@interface BookmarkInteractionController () <
BookmarkEditViewControllerDelegate,
BookmarkFolderEditorViewControllerDelegate,
BookmarkFolderViewControllerDelegate,
BookmarkHomeViewControllerDelegate,
TableViewPresentationControllerDelegate> {
// The browser bookmarks are presented in.
Browser* _browser; // weak
// The browser state of the current user.
ChromeBrowserState* _currentBrowserState; // weak
// The browser state to use, might be different from _currentBrowserState if
// it is incognito.
ChromeBrowserState* _browserState; // weak
// The web state list currently in use.
WebStateList* _webStateList;
}
// The type of view controller that is being presented.
@property(nonatomic, assign) PresentedState currentPresentedState;
// The navigation controller that is being presented, if any.
// `self.bookmarkBrowser`, `self.bookmarkEditor`, and `self.folderEditor` are
// children of this navigation controller.
@property(nonatomic, strong)
UINavigationController* bookmarkNavigationController;
// The delegate provided to `self.bookmarkNavigationController`.
@property(nonatomic, strong)
BookmarkNavigationControllerDelegate* bookmarkNavigationControllerDelegate;
// The bookmark model in use.
@property(nonatomic, assign) BookmarkModel* bookmarkModel;
// A reference to the potentially presented bookmark browser. This will be
// non-nil when `currentPresentedState` is BOOKMARK_BROWSER.
@property(nonatomic, strong) BookmarkHomeViewController* bookmarkBrowser;
// A reference to the potentially presented single bookmark editor. This will be
// non-nil when `currentPresentedState` is BOOKMARK_EDITOR.
@property(nonatomic, strong) BookmarkEditViewController* bookmarkEditor;
// A reference to the potentially presented folder editor. This will be non-nil
// when `currentPresentedState` is FOLDER_EDITOR.
@property(nonatomic, strong) BookmarkFolderEditorViewController* folderEditor;
// A reference to the potentially presented folder selector. This will be
// non-nil when `currentPresentedState` is FOLDER_SELECTION.
@property(nonatomic, strong) BookmarkFolderViewController* folderSelector;
@property(nonatomic, copy) void (^folderSelectionCompletionBlock)
(const bookmarks::BookmarkNode*);
@property(nonatomic, strong) BookmarkMediator* mediator;
// The transitioning delegate that is used when presenting
// `self.bookmarkBrowser`.
@property(nonatomic, strong)
BookmarkTransitioningDelegate* bookmarkTransitioningDelegate;
// Handler for Application Commands.
@property(nonatomic, readonly, weak) id<ApplicationCommands>
applicationCommandsHandler;
// Handler for Snackbar Commands.
@property(nonatomic, readonly, weak) id<SnackbarCommands>
snackbarCommandsHandler;
// Dismisses the bookmark browser. If `urlsToOpen` is not empty, then the user
// has selected to navigate to those URLs with specified tab mode.
- (void)dismissBookmarkBrowserAnimated:(BOOL)animated
urlsToOpen:(const std::vector<GURL>&)urlsToOpen
inIncognito:(BOOL)inIncognito
newTab:(BOOL)newTab;
// Dismisses the bookmark editor.
- (void)dismissBookmarkEditorAnimated:(BOOL)animated;
// Dismisses the folder editor.
- (void)dismissFolderEditorAnimated:(BOOL)animated;
@end
@implementation BookmarkInteractionController
@synthesize applicationCommandsHandler = _applicationCommandsHandler;
@synthesize snackbarCommandsHandler = _snackbarCommandsHandler;
@synthesize bookmarkBrowser = _bookmarkBrowser;
@synthesize bookmarkEditor = _bookmarkEditor;
@synthesize bookmarkModel = _bookmarkModel;
@synthesize bookmarkNavigationController = _bookmarkNavigationController;
@synthesize bookmarkNavigationControllerDelegate =
_bookmarkNavigationControllerDelegate;
@synthesize bookmarkTransitioningDelegate = _bookmarkTransitioningDelegate;
@synthesize currentPresentedState = _currentPresentedState;
@synthesize delegate = _delegate;
@synthesize folderEditor = _folderEditor;
@synthesize mediator = _mediator;
- (instancetype)initWithBrowser:(Browser*)browser {
self = [super init];
if (self) {
_browser = browser;
// Bookmarks are always opened with the main browser state, even in
// incognito mode.
_currentBrowserState = browser->GetBrowserState();
_browserState = _currentBrowserState->GetOriginalChromeBrowserState();
_webStateList = browser->GetWebStateList();
_bookmarkModel =
ios::BookmarkModelFactory::GetForBrowserState(_browserState);
_mediator = [[BookmarkMediator alloc]
initWithWithBookmarkModel:self.bookmarkModel
prefs:_browserState->GetPrefs()];
_currentPresentedState = PresentedState::NONE;
DCHECK(_bookmarkModel);
}
return self;
}
- (void)dealloc {
[self shutdown];
}
- (void)shutdown {
[self bookmarkBrowserDismissed];
_bookmarkBrowser.homeDelegate = nil;
[_bookmarkBrowser shutdown];
_bookmarkBrowser = nil;
_bookmarkEditor.delegate = nil;
[_bookmarkEditor shutdown];
_bookmarkEditor = nil;
}
- (id<ApplicationCommands>)applicationCommandsHandler {
// Using lazy loading here to avoid potential crashes with ApplicationCommands
// not being yet dispatched.
if (!_applicationCommandsHandler) {
_applicationCommandsHandler = HandlerForProtocol(
_browser->GetCommandDispatcher(), ApplicationCommands);
}
return _applicationCommandsHandler;
}
- (id<SnackbarCommands>)snackbarCommandsHandler {
// Using lazy loading here to avoid potential crashes with SnackbarCommands
// not being yet dispatched.
if (!_snackbarCommandsHandler) {
_snackbarCommandsHandler =
HandlerForProtocol(_browser->GetCommandDispatcher(), SnackbarCommands);
}
return _snackbarCommandsHandler;
}
- (void)bookmarkURL:(const GURL&)URL title:(NSString*)title {
if (!self.bookmarkModel->loaded()) {
return;
}
__weak BookmarkInteractionController* weakSelf = self;
// Copy of `URL` to be captured in block.
GURL bookmarkedURL(URL);
void (^editAction)() = ^{
[weakSelf presentBookmarkEditorForURL:bookmarkedURL];
};
[self.snackbarCommandsHandler
showSnackbarMessage:[self.mediator addBookmarkWithTitle:title
URL:bookmarkedURL
editAction:editAction]];
}
- (void)presentBookmarkEditorForURL:(const GURL&)URL {
if (!self.bookmarkModel->loaded()) {
return;
}
const BookmarkNode* bookmark =
self.bookmarkModel->GetMostRecentlyAddedUserNodeForURL(URL);
if (!bookmark) {
return;
}
[self presentEditorForNode:bookmark];
}
- (void)presentBookmarks {
DCHECK_EQ(PresentedState::NONE, self.currentPresentedState);
DCHECK(!self.bookmarkNavigationController);
self.bookmarkBrowser =
[[BookmarkHomeViewController alloc] initWithBrowser:_browser];
self.bookmarkBrowser.homeDelegate = self;
self.bookmarkBrowser.applicationCommandsHandler =
self.applicationCommandsHandler;
self.bookmarkBrowser.snackbarCommandsHandler = self.snackbarCommandsHandler;
NSArray<BookmarkHomeViewController*>* replacementViewControllers = nil;
if (self.bookmarkModel->loaded()) {
// Set the root node if the model has been loaded. If the model has not been
// loaded yet, the root node will be set in BookmarkHomeViewController after
// the model is finished loading.
[self.bookmarkBrowser setRootNode:self.bookmarkModel->root_node()];
replacementViewControllers =
[self.bookmarkBrowser cachedViewControllerStack];
}
[self presentTableViewController:self.bookmarkBrowser
withReplacementViewControllers:replacementViewControllers];
self.currentPresentedState = PresentedState::BOOKMARK_BROWSER;
}
- (void)presentFolderPickerWithCompletion:
(void (^)(const bookmarks::BookmarkNode*))block {
DCHECK_EQ(PresentedState::NONE, self.currentPresentedState);
DCHECK(block);
[self dismissSnackbar];
self.currentPresentedState = PresentedState::FOLDER_SELECTION;
self.folderSelectionCompletionBlock = [block copy];
std::set<const BookmarkNode*> editedNodes;
self.folderSelector = [[BookmarkFolderViewController alloc]
initWithBookmarkModel:self.bookmarkModel
allowsNewFolders:YES
editedNodes:editedNodes
allowsCancel:YES
selectedFolder:nil
browser:_browser];
self.folderSelector.delegate = self;
self.folderSelector.snackbarCommandsHandler = self.snackbarCommandsHandler;
[self presentTableViewController:self.folderSelector
withReplacementViewControllers:nil];
}
- (void)presentEditorForNode:(const bookmarks::BookmarkNode*)node {
DCHECK_EQ(PresentedState::NONE, self.currentPresentedState);
[self dismissSnackbar];
if (!node) {
return;
}
if (!(node->type() == BookmarkNode::URL ||
node->type() == BookmarkNode::FOLDER)) {
return;
}
ChromeTableViewController<UIAdaptivePresentationControllerDelegate>*
editorController = nil;
if (node->type() == BookmarkNode::URL) {
self.currentPresentedState = PresentedState::BOOKMARK_EDITOR;
BookmarkEditViewController* bookmarkEditor =
[[BookmarkEditViewController alloc] initWithBookmark:node
browser:_browser];
bookmarkEditor.delegate = self;
bookmarkEditor.snackbarCommandsHandler = self.snackbarCommandsHandler;
self.bookmarkEditor = bookmarkEditor;
editorController = bookmarkEditor;
} else if (node->type() == BookmarkNode::FOLDER) {
self.currentPresentedState = PresentedState::FOLDER_EDITOR;
BookmarkFolderEditorViewController* folderEditor =
[BookmarkFolderEditorViewController
folderEditorWithBookmarkModel:self.bookmarkModel
folder:node
browser:_browser];
folderEditor.delegate = self;
folderEditor.snackbarCommandsHandler = self.snackbarCommandsHandler;
self.folderEditor = folderEditor;
editorController = folderEditor;
} else {
NOTREACHED();
}
[self presentTableViewController:editorController
withReplacementViewControllers:nil];
}
- (void)dismissBookmarkBrowserAnimated:(BOOL)animated
urlsToOpen:(const std::vector<GURL>&)urlsToOpen
inIncognito:(BOOL)inIncognito
newTab:(BOOL)newTab {
if (self.currentPresentedState != PresentedState::BOOKMARK_BROWSER) {
return;
}
DCHECK(self.bookmarkNavigationController);
// If trying to open urls with tab mode changed, we need to postpone openUrls
// until the dismissal of Bookmarks is done. This is to prevent the race
// condition between the dismissal of bookmarks and switch of BVC.
const BOOL openUrlsAfterDismissal =
!urlsToOpen.empty() &&
((!!inIncognito) != _currentBrowserState->IsOffTheRecord());
// A copy of the urls vector for the completion block.
std::vector<GURL> urlsToOpenAfterDismissal;
if (openUrlsAfterDismissal) {
// open urls in the completion block after dismissal.
urlsToOpenAfterDismissal = urlsToOpen;
} else if (!urlsToOpen.empty()) {
// open urls now.
[self openUrls:urlsToOpen inIncognito:inIncognito newTab:newTab];
}
ProceduralBlock completion = ^{
[self bookmarkBrowserDismissed];
if (!openUrlsAfterDismissal) {
return;
}
[self openUrls:urlsToOpenAfterDismissal
inIncognito:inIncognito
newTab:newTab];
};
if (_parentController.presentedViewController) {
[_parentController dismissViewControllerAnimated:animated
completion:completion];
} else {
completion();
}
self.currentPresentedState = PresentedState::NONE;
}
- (void)bookmarkBrowserDismissed {
// TODO(crbug.com/940856): Make sure navigaton
// controller doesn't keep any controllers. Without
// this there's a memory leak of (almost) every BHVC
// the user visits.
[self.bookmarkNavigationController setViewControllers:@[] animated:NO];
self.bookmarkBrowser.homeDelegate = nil;
self.bookmarkBrowser = nil;
self.bookmarkTransitioningDelegate = nil;
self.bookmarkNavigationController = nil;
self.bookmarkNavigationControllerDelegate = nil;
}
- (void)dismissBookmarkEditorAnimated:(BOOL)animated {
if (self.currentPresentedState != PresentedState::BOOKMARK_EDITOR) {
return;
}
DCHECK(self.bookmarkNavigationController);
self.bookmarkEditor.delegate = nil;
self.bookmarkEditor = nil;
[self.bookmarkNavigationController
dismissViewControllerAnimated:animated
completion:^{
self.bookmarkNavigationController = nil;
self.bookmarkTransitioningDelegate = nil;
}];
self.currentPresentedState = PresentedState::NONE;
}
- (void)dismissFolderEditorAnimated:(BOOL)animated {
if (self.currentPresentedState != PresentedState::FOLDER_EDITOR) {
return;
}
DCHECK(self.bookmarkNavigationController);
[self.bookmarkNavigationController
dismissViewControllerAnimated:animated
completion:^{
self.folderEditor.delegate = nil;
self.folderEditor = nil;
self.bookmarkNavigationController = nil;
self.bookmarkTransitioningDelegate = nil;
}];
self.currentPresentedState = PresentedState::NONE;
}
- (void)dismissFolderSelectionAnimated:(BOOL)animated {
if (self.currentPresentedState != PresentedState::FOLDER_SELECTION) {
return;
}
DCHECK(self.bookmarkNavigationController);
[self.bookmarkNavigationController
dismissViewControllerAnimated:animated
completion:^{
self.folderSelector.delegate = nil;
self.folderSelector = nil;
self.bookmarkNavigationController = nil;
self.bookmarkTransitioningDelegate = nil;
}];
self.currentPresentedState = PresentedState::NONE;
}
- (void)dismissBookmarkModalControllerAnimated:(BOOL)animated {
// No urls to open. So it does not care about inIncognito and newTab.
[self dismissBookmarkBrowserAnimated:animated
urlsToOpen:std::vector<GURL>()
inIncognito:NO
newTab:NO];
[self dismissBookmarkEditorAnimated:animated];
}
- (void)dismissSnackbar {
// Dismiss any bookmark related snackbar this controller could have presented.
[MDCSnackbarManager.defaultManager
dismissAndCallCompletionBlocksWithCategory:
bookmark_utils_ios::kBookmarksSnackbarCategory];
}
#pragma mark - BookmarkEditViewControllerDelegate
- (BOOL)bookmarkEditor:(BookmarkEditViewController*)controller
shoudDeleteAllOccurencesOfBookmark:(const BookmarkNode*)bookmark {
return YES;
}
- (void)bookmarkEditorWantsDismissal:(BookmarkEditViewController*)controller {
[self dismissBookmarkEditorAnimated:YES];
}
- (void)bookmarkEditorWillCommitTitleOrUrlChange:
(BookmarkEditViewController*)controller {
[self.delegate bookmarkInteractionControllerWillCommitTitleOrUrlChange:self];
}
#pragma mark - BookmarkFolderEditorViewControllerDelegate
- (void)bookmarkFolderEditor:(BookmarkFolderEditorViewController*)folderEditor
didFinishEditingFolder:(const BookmarkNode*)folder {
DCHECK(folder);
[self dismissFolderEditorAnimated:YES];
}
- (void)bookmarkFolderEditorDidDeleteEditedFolder:
(BookmarkFolderEditorViewController*)folderEditor {
[self dismissFolderEditorAnimated:YES];
}
- (void)bookmarkFolderEditorDidCancel:
(BookmarkFolderEditorViewController*)folderEditor {
[self dismissFolderEditorAnimated:YES];
}
- (void)bookmarkFolderEditorWillCommitTitleChange:
(BookmarkFolderEditorViewController*)controller {
[self.delegate bookmarkInteractionControllerWillCommitTitleOrUrlChange:self];
}
#pragma mark - BookmarkFolderViewControllerDelegate
- (void)folderPicker:(BookmarkFolderViewController*)folderPicker
didFinishWithFolder:(const bookmarks::BookmarkNode*)folder {
[self dismissFolderSelectionAnimated:YES];
if (self.folderSelectionCompletionBlock) {
self.folderSelectionCompletionBlock(folder);
}
}
- (void)folderPickerDidCancel:(BookmarkFolderViewController*)folderPicker {
[self dismissFolderSelectionAnimated:YES];
}
- (void)folderPickerDidDismiss:(BookmarkFolderViewController*)folderPicker {
[self dismissFolderSelectionAnimated:YES];
}
#pragma mark - BookmarkHomeViewControllerDelegate
- (void)bookmarkHomeViewControllerWantsDismissal:
(BookmarkHomeViewController*)controller
navigationToUrls:
(const std::vector<GURL>&)urls {
[self bookmarkHomeViewControllerWantsDismissal:controller
navigationToUrls:urls
inIncognito:_currentBrowserState
->IsOffTheRecord()
newTab:NO];
}
- (void)bookmarkHomeViewControllerWantsDismissal:
(BookmarkHomeViewController*)controller
navigationToUrls:(const std::vector<GURL>&)urls
inIncognito:(BOOL)inIncognito
newTab:(BOOL)newTab {
[self dismissBookmarkBrowserAnimated:YES
urlsToOpen:urls
inIncognito:inIncognito
newTab:newTab];
}
- (void)openUrls:(const std::vector<GURL>&)urls
inIncognito:(BOOL)inIncognito
newTab:(BOOL)newTab {
BOOL openInForegroundTab = YES;
for (const GURL& url : urls) {
DCHECK(url.is_valid());
// TODO(crbug.com/695749): Force url to open in non-incognito mode. if
// !IsURLAllowedInIncognito(url).
if (openInForegroundTab) {
// Only open the first URL in foreground tab.
openInForegroundTab = NO;
// TODO(crbug.com/695749): See if we need different metrics for 'Open
// all', 'Open all in incognito' and 'Open in incognito'.
new_tab_page_uma::RecordAction(_browserState,
_webStateList->GetActiveWebState(),
new_tab_page_uma::ACTION_OPENED_BOOKMARK);
base::RecordAction(
base::UserMetricsAction("MobileBookmarkManagerEntryOpened"));
LogLikelyInterestedDefaultBrowserUserActivity(DefaultPromoTypeAllTabs);
if (newTab ||
((!!inIncognito) != _currentBrowserState->IsOffTheRecord())) {
// Open in new tab if it is specified or target tab mode is different
// from current tab mode.
[self openURLInNewTab:url inIncognito:inIncognito inBackground:NO];
} else {
// Open in current tab otherwise.
[self openURLInCurrentTab:url];
}
} else {
// Open other URLs (if any) in background tabs.
[self openURLInNewTab:url inIncognito:inIncognito inBackground:YES];
}
} // end for
}
#pragma mark - TableViewPresentationControllerDelegate
- (BOOL)presentationControllerShouldDismissOnTouchOutside:
(TableViewPresentationController*)controller {
BOOL shouldDismissOnTouchOutside = YES;
ChromeTableViewController* tableViewController =
base::mac::ObjCCast<ChromeTableViewController>(
self.bookmarkNavigationController.topViewController);
if (tableViewController) {
shouldDismissOnTouchOutside =
[tableViewController shouldBeDismissedOnTouchOutside];
}
return shouldDismissOnTouchOutside;
}
- (void)presentationControllerWillDismiss:
(TableViewPresentationController*)controller {
[self dismissBookmarkModalControllerAnimated:YES];
}
#pragma mark - BookmarksCommands
- (void)bookmark:(BookmarkAddCommand*)command {
DCHECK(command.URLs.count > 0) << "URLs are missing";
if (!self.bookmarkModel->loaded()) {
return;
}
if (command.URLs.count == 1 && !command.presentFolderChooser) {
URLWithTitle* URLWithTitle = command.URLs.firstObject;
DCHECK(URLWithTitle);
const BookmarkNode* existingBookmark =
self.bookmarkModel->GetMostRecentlyAddedUserNodeForURL(
URLWithTitle.URL);
if (existingBookmark) {
[self presentBookmarkEditorForURL:URLWithTitle.URL];
} else {
[self bookmarkURL:URLWithTitle.URL title:URLWithTitle.title];
}
return;
}
__weak BookmarkInteractionController* weakSelf = self;
[self presentFolderPickerWithCompletion:^(
const bookmarks::BookmarkNode* folder) {
BookmarkInteractionController* strongSelf = weakSelf;
if (folder && strongSelf) {
[strongSelf.snackbarCommandsHandler
showSnackbarMessage:[strongSelf.mediator addBookmarks:command.URLs
toFolder:folder]];
}
}];
}
#pragma mark - Private
// Presents `viewController` using the appropriate presentation and styling,
// depending on whether the UIRefresh experiment is enabled or disabled. Sets
// `self.bookmarkNavigationController` to the UINavigationController subclass
// used, and may set `self.bookmarkNavigationControllerDelegate` or
// `self.bookmarkTransitioningDelegate` depending on whether or not the desired
// transition requires those objects. If `replacementViewControllers` is not
// nil, those controllers are swapped in to the UINavigationController instead
// of `viewController`.
- (void)presentTableViewController:
(ChromeTableViewController<
UIAdaptivePresentationControllerDelegate>*)viewController
withReplacementViewControllers:
(NSArray<ChromeTableViewController*>*)replacementViewControllers {
TableViewNavigationController* navController =
[[TableViewNavigationController alloc] initWithTable:viewController];
self.bookmarkNavigationController = navController;
if (replacementViewControllers) {
[navController setViewControllers:replacementViewControllers];
}
navController.toolbarHidden = YES;
self.bookmarkNavigationControllerDelegate =
[[BookmarkNavigationControllerDelegate alloc] init];
navController.delegate = self.bookmarkNavigationControllerDelegate;
BOOL useCustomPresentation = YES;
[navController setModalPresentationStyle:UIModalPresentationFormSheet];
useCustomPresentation = NO;
if (useCustomPresentation) {
self.bookmarkTransitioningDelegate =
[[BookmarkTransitioningDelegate alloc] init];
self.bookmarkTransitioningDelegate.presentationControllerModalDelegate =
self;
navController.transitioningDelegate = self.bookmarkTransitioningDelegate;
navController.modalPresentationStyle = UIModalPresentationCustom;
TableViewPresentationController* presentationController =
base::mac::ObjCCastStrict<TableViewPresentationController>(
navController.presentationController);
self.bookmarkNavigationControllerDelegate.modalController =
presentationController;
}
[_parentController presentViewController:navController
animated:YES
completion:nil];
}
- (void)openURLInCurrentTab:(const GURL&)url {
if (url.SchemeIs(url::kJavaScriptScheme) && _webStateList) { // bookmarklet
LoadJavaScriptURL(url, _browserState, _webStateList->GetActiveWebState());
return;
}
UrlLoadParams params = UrlLoadParams::InCurrentTab(url);
params.web_params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
UrlLoadingBrowserAgent::FromBrowser(_browser)->Load(params);
}
- (void)openURLInNewTab:(const GURL&)url
inIncognito:(BOOL)inIncognito
inBackground:(BOOL)inBackground {
// TODO(crbug.com/695749): Open bookmarklet in new tab doesn't work. See how
// to deal with this later.
UrlLoadParams params = UrlLoadParams::InNewTab(url);
params.SetInBackground(inBackground);
params.in_incognito = inIncognito;
UrlLoadingBrowserAgent::FromBrowser(_browser)->Load(params);
}
@end