Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Unified Diff: ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm

Issue 2586993002: Upstream Chrome on iOS source code [3/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..6f6de34a3300c6db95cfe840e7e2d698805452df
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
@@ -0,0 +1,526 @@
+// Copyright 2014 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_folder_editor_view_controller.h"
+
+#include <memory>
+#include <set>
+
+#include "base/auto_reset.h"
+#include "base/i18n/rtl.h"
+#import "base/ios/weak_nsobject.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/objc_property_releaser.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/bookmark_node.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_elevated_toolbar.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
+#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h"
+#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
+#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
+#import "ios/chrome/browser/ui/icons/chrome_icon.h"
+#import "ios/chrome/browser/ui/material_components/utils.h"
+#include "ios/chrome/browser/ui/rtl_geometry.h"
+#include "ios/chrome/grit/ios_strings.h"
+#import "ios/third_party/material_components_ios/src/components/NavigationBar/src/MaterialNavigationBar.h"
+#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
+#import "ios/third_party/material_components_ios/src/components/ShadowElevations/src/MaterialShadowElevations.h"
+#import "ios/third_party/material_components_ios/src/components/ShadowLayer/src/MaterialShadowLayer.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
+#include "ui/base/l10n/l10n_util.h"
+
+using bookmarks::BookmarkNode;
+
+namespace {
+
+typedef NS_ENUM(NSInteger, SectionIdentifier) {
+ SectionIdentifierInfo = kSectionIdentifierEnumZero,
+};
+
+typedef NS_ENUM(NSInteger, ItemType) {
+ ItemTypeFolderTitle = kItemTypeEnumZero,
+ ItemTypeParentFolder,
+};
+
+} // namespace
+
+@interface BookmarkFolderEditorViewController ()<
+ BookmarkFolderViewControllerDelegate,
+ BookmarkModelBridgeObserver,
+ BookmarkTextFieldItemDelegate> {
+ std::unique_ptr<bookmarks::BookmarkModelBridge> _modelBridge;
+ base::mac::ObjCPropertyReleaser
+ _propertyReleaser_BookmarkFolderEditorViewController;
+ // Flag to ignore bookmark model Move notifications when the move is performed
+ // by this class.
+ BOOL _ignoresOwnMove;
+}
+@property(nonatomic, assign) BOOL editingExistingFolder;
+@property(nonatomic, assign) bookmarks::BookmarkModel* bookmarkModel;
+@property(nonatomic, assign) ios::ChromeBrowserState* browserState;
+@property(nonatomic, assign) const BookmarkNode* folder;
+@property(nonatomic, retain) BookmarkFolderViewController* folderViewController;
+@property(nonatomic, assign) const BookmarkNode* parentFolder;
+@property(nonatomic, assign) UIBarButtonItem* doneItem;
+@property(nonatomic, retain) BookmarkTextFieldItem* titleItem;
+@property(nonatomic, retain) BookmarkParentFolderItem* parentFolderItem;
+// Bottom toolbar with DELETE button that only appears when the edited folder
+// allows deletion.
+@property(nonatomic, assign) BookmarksElevatedToolbar* toolbar;
+
+// |bookmarkModel| must not be NULL and must be loaded.
+- (instancetype)initWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel
+ NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithStyle:(CollectionViewControllerStyle)style
+ NS_UNAVAILABLE;
+
+// Enables or disables the save button depending on the state of the form.
+- (void)updateSaveButtonState;
+
+// Configures collection view model.
+- (void)setupCollectionViewModel;
+
+// Adds toolbar with DELETE button.
+- (void)addToolbar;
+
+// Removes toolbar.
+- (void)removeToolbar;
+
+@end
+
+@implementation BookmarkFolderEditorViewController
+
+@synthesize bookmarkModel = _bookmarkModel;
+@synthesize delegate = _delegate;
+@synthesize editingExistingFolder = _editingExistingFolder;
+@synthesize folder = _folder;
+@synthesize folderViewController = _folderViewController;
+@synthesize parentFolder = _parentFolder;
+@synthesize browserState = _browserState;
+@synthesize doneItem = _doneItem;
+@synthesize titleItem = _titleItem;
+@synthesize parentFolderItem = _parentFolderItem;
+@synthesize toolbar = _toolbar;
+
+#pragma mark - Class methods
+
++ (instancetype)
+folderCreatorWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel
+ parentFolder:(const BookmarkNode*)parentFolder {
+ base::scoped_nsobject<BookmarkFolderEditorViewController> folderCreator(
+ [[self alloc] initWithBookmarkModel:bookmarkModel]);
+ folderCreator.get().parentFolder = parentFolder;
+ folderCreator.get().folder = NULL;
+ folderCreator.get().editingExistingFolder = NO;
+ return folderCreator.autorelease();
+}
+
++ (instancetype)
+folderEditorWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel
+ folder:(const BookmarkNode*)folder
+ browserState:(ios::ChromeBrowserState*)browserState {
+ DCHECK(folder);
+ DCHECK(!bookmarkModel->is_permanent_node(folder));
+ DCHECK(browserState);
+ base::scoped_nsobject<BookmarkFolderEditorViewController> folderEditor(
+ [[self alloc] initWithBookmarkModel:bookmarkModel]);
+ folderEditor.get().parentFolder = folder->parent();
+ folderEditor.get().folder = folder;
+ folderEditor.get().browserState = browserState;
+ folderEditor.get().editingExistingFolder = YES;
+ return folderEditor.autorelease();
+}
+
+#pragma mark - Initialization
+
+- (instancetype)initWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel {
+ DCHECK(bookmarkModel);
+ DCHECK(bookmarkModel->loaded());
+ self = [super initWithStyle:CollectionViewControllerStyleAppBar];
+ if (self) {
+ _propertyReleaser_BookmarkFolderEditorViewController.Init(
+ self, [BookmarkFolderEditorViewController class]);
+ _bookmarkModel = bookmarkModel;
+
+ // Set up the bookmark model oberver.
+ _modelBridge.reset(
+ new bookmarks::BookmarkModelBridge(self, _bookmarkModel));
+ }
+ return self;
+}
+
+- (instancetype)initWithStyle:(CollectionViewControllerStyle)style {
+ NOTREACHED();
+ return nil;
+}
+
+- (void)dealloc {
+ _titleItem.delegate = nil;
+ _folderViewController.delegate = nil;
+ [super dealloc];
+}
+
+#pragma mark - UIViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ self.collectionView.backgroundColor = [UIColor whiteColor];
+
+ // Add Done button.
+ base::scoped_nsobject<UIBarButtonItem> doneItem([[UIBarButtonItem alloc]
+ initWithTitle:l10n_util::GetNSString(
+ IDS_IOS_BOOKMARK_EDIT_MODE_EXIT_MOBILE)
+ style:UIBarButtonItemStylePlain
+ target:self
+ action:@selector(saveFolder)]);
+ doneItem.get().accessibilityIdentifier = @"Save";
+ self.navigationItem.rightBarButtonItem = doneItem;
+ self.doneItem = doneItem;
+
+ if (self.editingExistingFolder) {
+ // Add Cancel Button.
+ UIBarButtonItem* cancelItem =
+ [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon closeIcon]
+ target:self
+ action:@selector(cancel)];
+ cancelItem.accessibilityLabel =
+ l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_CANCEL_BUTTON_LABEL);
+ cancelItem.accessibilityIdentifier = @"Cancel";
+ self.navigationItem.leftBarButtonItem = cancelItem;
+
+ [self addToolbar];
+ } else {
+ // Add Back button.
+ UIBarButtonItem* backItem =
+ [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon backIcon]
+ target:self
+ action:@selector(back)];
+ backItem.accessibilityLabel =
+ l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_BACK_LABEL);
+ backItem.accessibilityIdentifier = @"Back";
+ self.navigationItem.leftBarButtonItem = backItem;
+ }
+
+ [self updateEditingState];
+ [self setupCollectionViewModel];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+ [super viewWillAppear:animated];
+ [self updateSaveButtonState];
+}
+
+#pragma mark - Accessibility
+
+- (BOOL)accessibilityPerformEscape {
+ [self.delegate bookmarkFolderEditorDidCancel:self];
+ return YES;
+}
+
+#pragma mark - Actions
+
+- (void)back {
+ [self.delegate bookmarkFolderEditorDidCancel:self];
+}
+
+- (void)cancel {
+ [self.delegate bookmarkFolderEditorDidCancel:self];
+}
+
+- (void)deleteFolder {
+ DCHECK(self.editingExistingFolder);
+ DCHECK(self.folder);
+ std::set<const BookmarkNode*> editedNodes;
+ editedNodes.insert(self.folder);
+ bookmark_utils_ios::DeleteBookmarksWithUndoToast(
+ editedNodes, self.bookmarkModel, self.browserState);
+ [self.delegate bookmarkFolderEditorDidDeleteEditedFolder:self];
+}
+
+- (void)saveFolder {
+ DCHECK(self.parentFolder);
+
+ NSString* folderString = self.titleItem.text;
+ DCHECK(folderString.length > 0);
+ base::string16 folderTitle = base::SysNSStringToUTF16(folderString);
+
+ if (self.editingExistingFolder) {
+ DCHECK(self.folder);
+ self.bookmarkModel->SetTitle(self.folder, folderTitle);
+ if (self.folder->parent() != self.parentFolder) {
+ base::AutoReset<BOOL> autoReset(&_ignoresOwnMove, YES);
+ std::set<const BookmarkNode*> editedNodes;
+ editedNodes.insert(self.folder);
+ bookmark_utils_ios::MoveBookmarksWithUndoToast(
+ editedNodes, self.bookmarkModel, self.parentFolder,
+ self.browserState);
+ }
+ } else {
+ DCHECK(!self.folder);
+ self.folder = self.bookmarkModel->AddFolder(
+ self.parentFolder, self.parentFolder->child_count(), folderTitle);
+ }
+ [self.delegate bookmarkFolderEditor:self didFinishEditingFolder:self.folder];
+}
+
+- (void)changeParentFolder {
+ std::set<const BookmarkNode*> editedNodes;
+ if (self.folder)
+ editedNodes.insert(self.folder);
+ base::scoped_nsobject<BookmarkFolderViewController> folderViewController(
+ [[BookmarkFolderViewController alloc]
+ initWithBookmarkModel:self.bookmarkModel
+ allowsNewFolders:NO
+ editedNodes:editedNodes
+ allowsCancel:NO
+ selectedFolder:self.parentFolder]);
+ folderViewController.get().delegate = self;
+ self.folderViewController = folderViewController;
+
+ [self.navigationController pushViewController:folderViewController
+ animated:YES];
+}
+
+#pragma mark - BookmarkFolderViewControllerDelegate
+
+- (void)folderPicker:(BookmarkFolderViewController*)folderPicker
+ didFinishWithFolder:(const BookmarkNode*)folder {
+ self.parentFolder = folder;
+ [self updateParentFolderState];
+ [self.navigationController popViewControllerAnimated:YES];
+ self.folderViewController.delegate = nil;
+ self.folderViewController = nil;
+}
+
+- (void)folderPickerDidCancel:(BookmarkFolderViewController*)folderPicker {
+ [self.navigationController popViewControllerAnimated:YES];
+ self.folderViewController.delegate = nil;
+ self.folderViewController = nil;
+}
+
+#pragma mark - BookmarkModelBridgeObserver
+
+- (void)bookmarkModelLoaded {
+ // The bookmark model is assumed to be loaded when this controller is created.
+ NOTREACHED();
+}
+
+- (void)bookmarkNodeChanged:(const BookmarkNode*)bookmarkNode {
+ if (bookmarkNode == self.parentFolder) {
+ [self updateParentFolderState];
+ }
+}
+
+- (void)bookmarkNodeChildrenChanged:(const BookmarkNode*)bookmarkNode {
+ // No-op.
+}
+
+- (void)bookmarkNode:(const BookmarkNode*)bookmarkNode
+ movedFromParent:(const BookmarkNode*)oldParent
+ toParent:(const BookmarkNode*)newParent {
+ if (_ignoresOwnMove)
+ return;
+ if (bookmarkNode == self.folder) {
+ DCHECK(oldParent == self.parentFolder);
+ self.parentFolder = newParent;
+ [self updateParentFolderState];
+ }
+}
+
+- (void)bookmarkNodeDeleted:(const BookmarkNode*)bookmarkNode
+ fromFolder:(const BookmarkNode*)folder {
+ if (bookmarkNode == self.parentFolder) {
+ self.parentFolder = NULL;
+ [self updateParentFolderState];
+ return;
+ }
+ if (bookmarkNode == self.folder) {
+ self.folder = NULL;
+ self.editingExistingFolder = NO;
+ [self updateEditingState];
+ }
+}
+
+- (void)bookmarkModelRemovedAllNodes {
+ if (self.bookmarkModel->is_permanent_node(self.parentFolder))
+ return; // The current parent folder is still valid.
+
+ self.parentFolder = NULL;
+ [self updateParentFolderState];
+}
+
+#pragma mark - BookmarkTextFieldItemDelegate
+
+- (void)textDidChangeForItem:(BookmarkTextFieldItem*)item {
+ [self updateSaveButtonState];
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField*)textField {
+ [textField resignFirstResponder];
+ return YES;
+}
+
+#pragma mark - UICollectionViewDelegate
+
+- (void)collectionView:(UICollectionView*)collectionView
+ didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
+ [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
+ if ([self.collectionViewModel itemTypeForIndexPath:indexPath] ==
+ ItemTypeParentFolder) {
+ [self changeParentFolder];
+ }
+}
+
+#pragma mark - UICollectionViewFlowLayout
+
+- (CGSize)collectionView:(UICollectionView*)collectionView
+ layout:(UICollectionViewLayout*)collectionViewLayout
+ sizeForItemAtIndexPath:(NSIndexPath*)indexPath {
+ switch ([self.collectionViewModel itemTypeForIndexPath:indexPath]) {
+ case ItemTypeFolderTitle: {
+ const CGFloat kTitleCellHeight = 96;
+ return CGSizeMake(CGRectGetWidth(collectionView.bounds),
+ kTitleCellHeight);
+ }
+ case ItemTypeParentFolder: {
+ const CGFloat kParentFolderCellHeight = 50;
+ return CGSizeMake(CGRectGetWidth(collectionView.bounds),
+ kParentFolderCellHeight);
+ }
+ default:
+ NOTREACHED();
+ return CGSizeZero;
+ }
+}
+
+#pragma mark - Private
+
+- (void)setParentFolder:(const BookmarkNode*)parentFolder {
+ if (!parentFolder) {
+ parentFolder = self.bookmarkModel->mobile_node();
+ }
+ _parentFolder = parentFolder;
+}
+
+- (void)updateEditingState {
+ if (![self isViewLoaded])
+ return;
+
+ self.view.accessibilityIdentifier =
+ (self.folder) ? @"Folder Editor" : @"Folder Creator";
+
+ [self setTitle:(self.folder)
+ ? l10n_util::GetNSString(
+ IDS_IOS_BOOKMARK_NEW_GROUP_EDITOR_EDIT_TITLE)
+ : l10n_util::GetNSString(
+ IDS_IOS_BOOKMARK_NEW_GROUP_EDITOR_CREATE_TITLE)];
+}
+
+- (void)updateParentFolderState {
+ NSIndexPath* folderSelectionIndexPath =
+ [self.collectionViewModel indexPathForItemType:ItemTypeParentFolder
+ sectionIdentifier:SectionIdentifierInfo];
+ self.parentFolderItem.title =
+ bookmark_utils_ios::TitleForBookmarkNode(self.parentFolder);
+ [self.collectionView reloadItemsAtIndexPaths:@[ folderSelectionIndexPath ]];
+
+ if (self.editingExistingFolder && !self.toolbar)
+ [self addToolbar];
+
+ if (!self.editingExistingFolder && self.toolbar)
+ [self removeToolbar];
+}
+
+- (void)setupCollectionViewModel {
+ [self loadModel];
+
+ [self.collectionViewModel addSectionWithIdentifier:SectionIdentifierInfo];
+
+ base::scoped_nsobject<BookmarkTextFieldItem> titleItem(
+ [[BookmarkTextFieldItem alloc] initWithType:ItemTypeFolderTitle]);
+ titleItem.get().text =
+ (self.folder)
+ ? bookmark_utils_ios::TitleForBookmarkNode(self.folder)
+ : l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_GROUP_DEFAULT_NAME);
+ titleItem.get().placeholder =
+ l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_EDITOR_NAME_LABEL);
+ titleItem.get().accessibilityIdentifier = @"Title";
+ [self.collectionViewModel addItem:titleItem
+ toSectionWithIdentifier:SectionIdentifierInfo];
+ titleItem.get().delegate = self;
+ self.titleItem = titleItem;
+
+ base::scoped_nsobject<BookmarkParentFolderItem> parentFolderItem(
+ [[BookmarkParentFolderItem alloc] initWithType:ItemTypeParentFolder]);
+ parentFolderItem.get().title =
+ bookmark_utils_ios::TitleForBookmarkNode(self.parentFolder);
+ [self.collectionViewModel addItem:parentFolderItem
+ toSectionWithIdentifier:SectionIdentifierInfo];
+ self.parentFolderItem = parentFolderItem;
+}
+
+- (void)addToolbar {
+ // Add bottom toolbar with Delete button.
+ base::scoped_nsobject<BookmarksElevatedToolbar> buttonBar(
+ [[BookmarksElevatedToolbar alloc] init]);
+ base::scoped_nsobject<UIBarButtonItem> deleteItem([[UIBarButtonItem alloc]
+ initWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_GROUP_DELETE)
+ style:UIBarButtonItemStylePlain
+ target:self
+ action:@selector(deleteFolder)]);
+ deleteItem.get().accessibilityIdentifier = @"Delete Folder";
+ [deleteItem setTitleTextAttributes:@{
+ NSForegroundColorAttributeName : [UIColor blackColor]
+ }
+ forState:UIControlStateNormal];
+ [buttonBar.get().layer
+ addSublayer:[[[MDCShadowLayer alloc] init] autorelease]];
+ buttonBar.get().shadowElevation = MDCShadowElevationSearchBarResting;
+ buttonBar.get().items = @[ deleteItem ];
+ [self.view addSubview:buttonBar];
+
+ // Constraint |buttonBar| to be in bottom.
+ buttonBar.get().translatesAutoresizingMaskIntoConstraints = NO;
+ [self.view addConstraints:
+ [NSLayoutConstraint
+ constraintsWithVisualFormat:@"H:|[buttonBar]|"
+ options:0
+ metrics:nil
+ views:NSDictionaryOfVariableBindings(
+ buttonBar)]];
+ [self.view addConstraint:[NSLayoutConstraint
+ constraintWithItem:buttonBar
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.view
+ attribute:NSLayoutAttributeBottom
+ multiplier:1.0
+ constant:0.0]];
+ [self.view
+ addConstraint:[NSLayoutConstraint
+ constraintWithItem:buttonBar
+ attribute:NSLayoutAttributeHeight
+ relatedBy:NSLayoutRelationEqual
+ toItem:nil
+ attribute:NSLayoutAttributeNotAnAttribute
+ multiplier:1.0
+ constant:48.0]];
+ self.toolbar = buttonBar;
+}
+
+- (void)removeToolbar {
+ [self.toolbar removeFromSuperview];
+ self.toolbar = nil;
+}
+
+- (void)updateSaveButtonState {
+ self.doneItem.enabled = (self.titleItem.text.length > 0);
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698