| Index: ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
|
| diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..95c9cbfa4802ba1d4f16a313de4d6178aea5e217
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
|
| @@ -0,0 +1,313 @@
|
| +// Copyright 2013 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/bookmarks/bookmark_interaction_controller.h"
|
| +
|
| +#include <stdint.h>
|
| +
|
| +#import "base/ios/weak_nsobject.h"
|
| +#include "base/logging.h"
|
| +#include "base/mac/bind_objc_block.h"
|
| +#include "base/mac/objc_property_releaser.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| +#include "base/metrics/user_metrics.h"
|
| +#include "base/metrics/user_metrics_action.h"
|
| +#include "base/strings/sys_string_conversions.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "base/time/time.h"
|
| +#include "components/bookmarks/browser/bookmark_model.h"
|
| +#include "components/bookmarks/browser/bookmark_utils.h"
|
| +#include "components/pref_registry/pref_registry_syncable.h"
|
| +#include "components/prefs/pref_service.h"
|
| +#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
|
| +#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
|
| +#import "ios/chrome/browser/metrics/new_tab_page_uma.h"
|
| +#include "ios/chrome/browser/pref_names.h"
|
| +#import "ios/chrome/browser/tabs/tab.h"
|
| +#import "ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.h"
|
| +#import "ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h"
|
| +#import "ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h"
|
| +#import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
|
| +#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
|
| +#include "ios/chrome/browser/ui/ui_util.h"
|
| +#include "ios/chrome/browser/ui/url_loader.h"
|
| +#include "ios/chrome/grit/ios_strings.h"
|
| +#import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
|
| +#include "ios/web/public/referrer.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +
|
| +using bookmarks::BookmarkModel;
|
| +using bookmarks::BookmarkNode;
|
| +
|
| +namespace {
|
| +const int64_t kLastUsedFolderNone = -1;
|
| +} // namespace
|
| +
|
| +@interface BookmarkInteractionController ()<
|
| + BookmarkEditViewControllerDelegate,
|
| + BookmarkHomeViewControllerDelegate> {
|
| + // The browser state of the current user.
|
| + ios::ChromeBrowserState* _currentBrowserState; // weak
|
| +
|
| + // The browser state to use, might be different from _currentBrowserState if
|
| + // it is incognito.
|
| + ios::ChromeBrowserState* _browserState; // weak
|
| +
|
| + // The designated url loader.
|
| + base::WeakNSProtocol<id<UrlLoader>> _loader;
|
| +
|
| + // The parent controller on top of which the UI needs to be presented.
|
| + base::WeakNSObject<UIViewController> _parentController;
|
| +
|
| + base::mac::ObjCPropertyReleaser
|
| + _propertyReleaser_BookmarkInteractionController;
|
| +}
|
| +
|
| +// The bookmark model in use.
|
| +@property(nonatomic, assign) BookmarkModel* bookmarkModel;
|
| +
|
| +// A reference to the potentially presented bookmark browser.
|
| +@property(nonatomic, retain) BookmarkHomeViewController* bookmarkBrowser;
|
| +
|
| +// A reference to the potentially presented single bookmark editor.
|
| +@property(nonatomic, retain) BookmarkEditViewController* bookmarkEditor;
|
| +
|
| +// The user wants to bookmark the current tab.
|
| +- (void)addBookmarkForTab:(Tab*)tab;
|
| +
|
| +// Builds a controller and brings it on screen.
|
| +- (void)presentBookmarkForTab:(Tab*)tab;
|
| +
|
| +// Dismisses the bookmark browser.
|
| +- (void)dismissBookmarkBrowserAnimated:(BOOL)animated;
|
| +
|
| +// Dismisses the bookmark editor.
|
| +- (void)dismissBookmarkEditorAnimated:(BOOL)animated;
|
| +
|
| +@end
|
| +
|
| +@implementation BookmarkInteractionController
|
| +
|
| +@synthesize bookmarkBrowser = _bookmarkBrowser;
|
| +@synthesize bookmarkEditor = _bookmarkEditor;
|
| +@synthesize bookmarkModel = _bookmarkModel;
|
| +
|
| ++ (void)registerBrowserStatePrefs:(user_prefs::PrefRegistrySyncable*)registry {
|
| + registry->RegisterInt64Pref(prefs::kIosBookmarkFolderDefault,
|
| + kLastUsedFolderNone);
|
| +}
|
| +
|
| ++ (const BookmarkNode*)folderForNewBookmarksInBrowserState:
|
| + (ios::ChromeBrowserState*)browserState {
|
| + bookmarks::BookmarkModel* bookmarks =
|
| + ios::BookmarkModelFactory::GetForBrowserState(browserState);
|
| + const BookmarkNode* defaultFolder = bookmarks->mobile_node();
|
| +
|
| + PrefService* prefs = browserState->GetPrefs();
|
| + int64_t node_id = prefs->GetInt64(prefs::kIosBookmarkFolderDefault);
|
| + if (node_id == kLastUsedFolderNone)
|
| + node_id = defaultFolder->id();
|
| + const BookmarkNode* result =
|
| + bookmarks::GetBookmarkNodeByID(bookmarks, node_id);
|
| +
|
| + if (result)
|
| + return result;
|
| +
|
| + return defaultFolder;
|
| +}
|
| +
|
| ++ (void)setFolderForNewBookmarks:(const BookmarkNode*)folder
|
| + inBrowserState:(ios::ChromeBrowserState*)browserState {
|
| + DCHECK(folder && folder->is_folder());
|
| + browserState->GetPrefs()->SetInt64(prefs::kIosBookmarkFolderDefault,
|
| + folder->id());
|
| +}
|
| +
|
| +- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
|
| + loader:(id<UrlLoader>)loader
|
| + parentController:(UIViewController*)parentController {
|
| + self = [super init];
|
| + if (self) {
|
| + _propertyReleaser_BookmarkInteractionController.Init(
|
| + self, [BookmarkInteractionController class]);
|
| + // Bookmarks are always opened with the main browser state, even in
|
| + // incognito mode.
|
| + _currentBrowserState = browserState;
|
| + _browserState = browserState->GetOriginalChromeBrowserState();
|
| + _loader.reset(loader);
|
| + _parentController.reset(parentController);
|
| + _bookmarkModel =
|
| + ios::BookmarkModelFactory::GetForBrowserState(_browserState);
|
| + DCHECK(_bookmarkModel);
|
| + DCHECK(_parentController);
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (void)dealloc {
|
| + _bookmarkBrowser.delegate = nil;
|
| + _bookmarkEditor.delegate = nil;
|
| + [super dealloc];
|
| +}
|
| +
|
| +- (void)addBookmarkForTab:(Tab*)tab {
|
| + base::RecordAction(base::UserMetricsAction("BookmarkAdded"));
|
| + const BookmarkNode* defaultFolder =
|
| + [[self class] folderForNewBookmarksInBrowserState:_browserState];
|
| + self.bookmarkModel->AddURL(defaultFolder, defaultFolder->child_count(),
|
| + base::SysNSStringToUTF16(tab.title), tab.url);
|
| +
|
| + MDCSnackbarMessageAction* action =
|
| + [[[MDCSnackbarMessageAction alloc] init] autorelease];
|
| + base::WeakNSObject<BookmarkInteractionController> weakSelf(self);
|
| + base::WeakNSObject<Tab> weakTab(tab);
|
| + action.handler = ^{
|
| + base::scoped_nsobject<BookmarkInteractionController> strongSelf(
|
| + [weakSelf retain]);
|
| + if (!strongSelf || !weakTab)
|
| + return;
|
| + [strongSelf presentBookmarkForTab:weakTab];
|
| + };
|
| + action.title = l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_EDIT_BUTTON);
|
| + action.accessibilityIdentifier = @"Edit";
|
| +
|
| + NSString* folderTitle =
|
| + bookmark_utils_ios::TitleForBookmarkNode(defaultFolder);
|
| + NSString* text =
|
| + _browserState->GetPrefs()->GetInt64(prefs::kIosBookmarkFolderDefault) !=
|
| + kLastUsedFolderNone
|
| + ? l10n_util::GetNSStringF(IDS_IOS_BOOKMARK_PAGE_SAVED_FOLDER,
|
| + base::SysNSStringToUTF16(folderTitle))
|
| + : l10n_util::GetNSString(IDS_IOS_BOOKMARK_PAGE_SAVED);
|
| + MDCSnackbarMessage* message = [MDCSnackbarMessage messageWithText:text];
|
| + message.action = action;
|
| + message.category = bookmark_utils_ios::kBookmarksSnackbarCategory;
|
| + [MDCSnackbarManager showMessage:message];
|
| +}
|
| +
|
| +- (void)presentBookmarkForTab:(Tab*)tab {
|
| + DCHECK(!self.bookmarkBrowser && !self.bookmarkEditor);
|
| + DCHECK(tab);
|
| +
|
| + const BookmarkNode* bookmark =
|
| + self.bookmarkModel->GetMostRecentlyAddedUserNodeForURL(tab.url);
|
| + if (!bookmark)
|
| + return;
|
| +
|
| + [self dismissSnackbar];
|
| +
|
| + base::scoped_nsobject<BookmarkEditViewController> bookmarkEditor(
|
| + [[BookmarkEditViewController alloc] initWithBookmark:bookmark
|
| + browserState:_browserState]);
|
| + self.bookmarkEditor = bookmarkEditor;
|
| + self.bookmarkEditor.delegate = self;
|
| + base::scoped_nsobject<UINavigationController> navController(
|
| + [[BookmarkNavigationController alloc]
|
| + initWithRootViewController:self.bookmarkEditor]);
|
| + navController.get().modalPresentationStyle = UIModalPresentationFormSheet;
|
| + [_parentController presentViewController:navController
|
| + animated:YES
|
| + completion:nil];
|
| +}
|
| +
|
| +- (void)presentBookmarkForTab:(Tab*)tab
|
| + currentlyBookmarked:(BOOL)bookmarked
|
| + inView:(UIView*)parentView
|
| + originRect:(CGRect)origin {
|
| + if (!self.bookmarkModel->loaded())
|
| + return;
|
| + if (!tab)
|
| + return;
|
| +
|
| + if (bookmarked)
|
| + [self presentBookmarkForTab:tab];
|
| + else
|
| + [self addBookmarkForTab:tab];
|
| +}
|
| +
|
| +- (void)presentBookmarks {
|
| + DCHECK(!self.bookmarkBrowser && !self.bookmarkEditor);
|
| + base::scoped_nsobject<BookmarkControllerFactory> bookmarkControllerFactory(
|
| + [[BookmarkControllerFactory alloc] init]);
|
| + self.bookmarkBrowser = [bookmarkControllerFactory
|
| + bookmarkControllerWithBrowserState:_currentBrowserState
|
| + loader:_loader];
|
| + self.bookmarkBrowser.delegate = self;
|
| + self.bookmarkBrowser.modalPresentationStyle = UIModalPresentationFormSheet;
|
| + [_parentController presentViewController:self.bookmarkBrowser
|
| + animated:YES
|
| + completion:nil];
|
| +}
|
| +
|
| +- (void)dismissBookmarkBrowserAnimated:(BOOL)animated {
|
| + if (!self.bookmarkBrowser)
|
| + return;
|
| +
|
| + [self.bookmarkBrowser dismissModals:animated];
|
| + [_parentController dismissViewControllerAnimated:animated
|
| + completion:^{
|
| + self.bookmarkBrowser.delegate = nil;
|
| + self.bookmarkBrowser = nil;
|
| + }];
|
| +}
|
| +
|
| +- (void)dismissBookmarkEditorAnimated:(BOOL)animated {
|
| + if (!self.bookmarkEditor)
|
| + return;
|
| +
|
| + [_parentController dismissViewControllerAnimated:animated
|
| + completion:^{
|
| + self.bookmarkEditor.delegate = nil;
|
| + self.bookmarkEditor = nil;
|
| + }];
|
| +}
|
| +
|
| +- (void)dismissBookmarkModalControllerAnimated:(BOOL)animated {
|
| + [self dismissBookmarkBrowserAnimated:animated];
|
| + [self dismissBookmarkEditorAnimated:animated];
|
| +}
|
| +
|
| +- (void)dismissSnackbar {
|
| + // Dismiss any bookmark related snackbar this controller could have presented.
|
| + [MDCSnackbarManager 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];
|
| +}
|
| +
|
| +#pragma mark - BookmarkHomeViewControllerDelegate
|
| +
|
| +- (void)bookmarkHomeViewControllerWantsDismissal:
|
| + (BookmarkHomeViewController*)controller
|
| + navigationToUrl:(const GURL&)url {
|
| + [self dismissBookmarkBrowserAnimated:YES];
|
| +
|
| + if (url != GURL()) {
|
| + new_tab_page_uma::RecordAction(_browserState,
|
| + new_tab_page_uma::ACTION_OPENED_BOOKMARK);
|
| + base::RecordAction(base::UserMetricsAction("MobileNTPBookmark"));
|
| +
|
| + if (url.SchemeIs(url::kJavaScriptScheme)) { // bookmarklet
|
| + NSString* jsToEval = [base::SysUTF8ToNSString(url.GetContent())
|
| + stringByRemovingPercentEncoding];
|
| + [_loader loadJavaScriptFromLocationBar:jsToEval];
|
| + } else {
|
| + [_loader loadURL:url
|
| + referrer:web::Referrer()
|
| + transition:ui::PAGE_TRANSITION_AUTO_BOOKMARK
|
| + rendererInitiated:NO];
|
| + }
|
| + }
|
| +}
|
| +
|
| +@end
|
|
|