Skip to content

Commit

Permalink
[IOS][Bkmrks] Create bookmarks folder chooser mediator
Browse files Browse the repository at this point in the history
This cl creates a skeleton bookmarks folder chooser mediator and
transfers ownership of `selectedFolder` property from the coordinator.
This properties can be modified by callers, BookmarkModelBridge observer and user selection. The mediator is now the source of truth for this
property.
Also the mediator takes a pointer to the set of editedNodes from the
coordinator. This property is only initialized once and is readonly
later on for coordinator clients. Mediator makes changes to this set, through the pointer that it owns, depending on model changes but the coordinator is the owner of the set.

BookmarkModelBridge observer will be moved in a following cl.

Bug: 1405746
Change-Id: Ieea58ee52b19c4720af708a2ad083578ddc654d4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4307538
Reviewed-by: Jérôme Lebel <jlebel@chromium.org>
Commit-Queue: Tanmoy Mollik <triploblastic@google.com>
Cr-Commit-Position: refs/heads/main@{#1115677}
  • Loading branch information
Tanmoy Mollik authored and Chromium LUCI CQ committed Mar 10, 2023
1 parent 65b032a commit e4733d4
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 101 deletions.
4 changes: 4 additions & 0 deletions ios/chrome/browser/ui/bookmarks/folder_chooser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ source_set("ui") {
configs += [ "//build/config/compiler:enable_arc" ]
visibility = [ ":coordinator_impl" ]
sources = [
"bookmarks_folder_chooser_consumer.h",
"bookmarks_folder_chooser_mediator.h",
"bookmarks_folder_chooser_mediator.mm",
"bookmarks_folder_chooser_mutator.h",
"bookmarks_folder_chooser_view_controller.h",
"bookmarks_folder_chooser_view_controller.mm",
"bookmarks_folder_chooser_view_controller_presentation_delegate.h",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2023 The Chromium Authors
// 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_BOOKMARKS_FOLDER_CHOOSER_BOOKMARKS_FOLDER_CHOOSER_CONSUMER_H_
#define IOS_CHROME_BROWSER_UI_BOOKMARKS_FOLDER_CHOOSER_BOOKMARKS_FOLDER_CHOOSER_CONSUMER_H_

#import <Foundation/Foundation.h>
#import <set>
#import <vector>

namespace bookmarks {
class BookmarkNode;
}

// Consumer protocol to receive updates from the model layer.
@protocol BookmarksFolderChooserConsumer <NSObject>

// Notifies the UI layer that model layer has been updated.
- (void)notifyModelUpdated;

@end

// TODO(crbug.com/1405746): Refactor all the methods in this protocol after the
// view controller has been refactored. View controller should not know about
// BookmarkNode.
// Data source protocol to get data on demand.
@protocol BookmarksFolderChooserDataSource <NSObject>

// Root folder in the bookmark model tree.
- (const bookmarks::BookmarkNode*)rootFolder;
// The folder that should have a blue check mark beside it in the UI.
- (const bookmarks::BookmarkNode*)selectedFolder;
// TODO(crbug.com/1405746): Delete this method and return visible folders
// instead after BookmarkModelBridge is configured inside the mediator.
- (const std::set<const bookmarks::BookmarkNode*>&)editedNodes;
// The list of visible folders to show in the folder chooser UI.
- (std::vector<const bookmarks::BookmarkNode*>)visibleFolders;

@end

#endif // IOS_CHROME_BROWSER_UI_BOOKMARKS_FOLDER_CHOOSER_BOOKMARKS_FOLDER_CHOOSER_CONSUMER_H_
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ class BookmarkNode;
// Coordinator's delegate.
@property(nonatomic, weak) id<BookmarksFolderChooserCoordinatorDelegate>
delegate;
// The current nodes (bookmarks or folders) that are considered for a move.
// Will be set right before this coordinator sends a confirm selection signal
// through it's delegate.
@property(nonatomic, assign, readonly)
const std::set<const bookmarks::BookmarkNode*>& editedNodes;
// Will provide the necessary UI to create a folder. `YES` by default.
// Should be set before calling `start`.
@property(nonatomic) BOOL allowsNewFolders;
Expand Down Expand Up @@ -60,6 +55,10 @@ class BookmarkNode;

// Whether the bookmark folder chooser can be dismissed.
- (BOOL)canDismiss;
// The current nodes (bookmarks or folders) that are considered for a move.
// Will be available right before this coordinator sends a confirm selection
// signal through it's delegate.
- (const std::set<const bookmarks::BookmarkNode*>&)editedNodes;
// Puts a blue check mark beside a folder it in the UI.
// If unset no blue check mark is shown.
- (void)setSelectedFolder:(const bookmarks::BookmarkNode*)folder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#import "ios/chrome/browser/main/browser.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
#import "ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_coordinator_delegate.h"
#import "ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_mediator.h"
#import "ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_view_controller.h"
#import "ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_view_controller_presentation_delegate.h"
#import "ios/chrome/browser/ui/bookmarks/folder_editor/bookmarks_folder_editor_coordinator.h"
Expand All @@ -29,6 +30,7 @@ @interface BookmarksFolderChooserCoordinator () <
BookmarksFolderChooserViewControllerPresentationDelegate,
BookmarksFolderEditorCoordinatorDelegate,
UIAdaptivePresentationControllerDelegate> {
BookmarksFolderChooserMediator* _mediator;
// If folder chooser is created with a base view controller then folder
// chooser will create and own `_navigationController` that should be deleted
// in the end.
Expand All @@ -41,8 +43,6 @@ @interface BookmarksFolderChooserCoordinator () <
// List of nodes to hide when displaying folders. This is to avoid to move a
// folder inside a child folder.
std::set<const bookmarks::BookmarkNode*> _hiddenNodes;
// The current nodes that are considered for a move.
std::set<const bookmarks::BookmarkNode*> _editedNodes;
// The folder that has a blue check mark beside it in the UI.
// This is only used for clients of this coordinator to update the UI. This
// does not reflect the folder users chose by clicking. For that information
Expand Down Expand Up @@ -92,31 +92,37 @@ - (BOOL)canDismiss {
return YES;
}

- (const std::set<const bookmarks::BookmarkNode*>&)editedNodes {
return _hiddenNodes;
}

- (void)setSelectedFolder:(const bookmarks::BookmarkNode*)folder {
DCHECK(folder);
DCHECK(folder->is_folder());
_selectedFolder = folder;
if (_viewController) {
[_viewController changeSelectedFolder:_selectedFolder];
}
_mediator.selectedFolder = _selectedFolder;
}

#pragma mark - ChromeCoordinator

- (void)start {
[super start];
// TODO(crbug.com/1402758): Create a mediator.
bookmarks::BookmarkModel* model =
ios::BookmarkModelFactory::GetForBrowserState(
self.browser->GetBrowserState());
_mediator = [[BookmarksFolderChooserMediator alloc]
initWithBookmarkModel:model
editedNodes:&_hiddenNodes];
_mediator.selectedFolder = _selectedFolder;
_viewController = [[BookmarksFolderChooserViewController alloc]
initWithBookmarkModel:model
allowsNewFolders:_allowsNewFolders
editedNodes:_hiddenNodes
allowsCancel:!_baseNavigationController
selectedFolder:_selectedFolder
browser:self.browser];
_viewController.delegate = self;
_viewController.dataSource = _mediator;
_viewController.mutator = _mediator;
_mediator.consumer = _viewController;

if (_baseNavigationController) {
_viewController.navigationItem.largeTitleDisplayMode =
Expand All @@ -138,7 +144,10 @@ - (void)stop {
// Stop child coordinator before stopping `self`.
[self stopBookmarksFolderEditorCoordinator];

DCHECK(_mediator);
DCHECK(_viewController);
_mediator.consumer = nil;
_mediator = nil;
if (_baseNavigationController) {
DCHECK_EQ(_baseNavigationController.topViewController, _viewController);
[_baseNavigationController popViewControllerAnimated:YES];
Expand All @@ -154,19 +163,23 @@ - (void)stop {
// `nullptr`.
DCHECK(!self.baseViewController.presentedViewController);
}
_viewController.delegate = nil;
_viewController.dataSource = nil;
_viewController.mutator = nil;
_viewController = nil;
}

#pragma mark - BookmarksFolderChooserViewControllerPresentationDelegate

- (void)showBookmarksFolderEditor {
- (void)showBookmarksFolderEditorWithParentFolder:
(const bookmarks::BookmarkNode*)parent {
DCHECK(!_folderEditorCoordinator);
_folderEditorCoordinator = [[BookmarksFolderEditorCoordinator alloc]
initWithBaseNavigationController:(_baseNavigationController
? _baseNavigationController
: _navigationController)
browser:self.browser
parentFolderNode:_selectedFolder];
parentFolderNode:parent];
_folderEditorCoordinator.delegate = self;
[_folderEditorCoordinator start];
}
Expand Down Expand Up @@ -231,12 +244,6 @@ - (BOOL)presentationControllerShouldDismiss:
return [self canDismiss];
}

#pragma mark - Properties

- (const std::set<const bookmarks::BookmarkNode*>&)editedNodes {
return _viewController.editedNodes;
}

#pragma mark - Private

- (void)stopBookmarksFolderEditorCoordinator {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2023 The Chromium Authors
// 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_BOOKMARKS_FOLDER_CHOOSER_BOOKMARKS_FOLDER_CHOOSER_MEDIATOR_H_
#define IOS_CHROME_BROWSER_UI_BOOKMARKS_FOLDER_CHOOSER_BOOKMARKS_FOLDER_CHOOSER_MEDIATOR_H_

#import "ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_consumer.h"
#import "ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_mutator.h"

#import <Foundation/Foundation.h>
#import <set>

namespace bookmarks {
class BookmarkModel;
class BookmarkNode;
} // namespace bookmarks

// A mediator class to encapsulate BookmarkModel from the view controller.
@interface BookmarksFolderChooserMediator
: NSObject <BookmarksFolderChooserDataSource, BookmarksFolderChooserMutator>

// Consumer to reflect model changes in the UI.
@property(nonatomic, weak) id<BookmarksFolderChooserConsumer> consumer;
// The currently selected folder.
@property(nonatomic, assign) const bookmarks::BookmarkNode* selectedFolder;

// Initialize the mediator with a bookmark model.
// `bookmarkModel` must not be `nullptr` and must be loaded.
// `editedNodes` are the list of nodes to hide when displaying folders. This is
// to avoid to move a folder inside a child folder. These are also the list of
// nodes that are being edited (moved to a folder).
- (instancetype)initWithBookmarkModel:(bookmarks::BookmarkModel*)model
editedNodes:
(std::set<const bookmarks::BookmarkNode*>*)nodes
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;

@end

#endif // IOS_CHROME_BROWSER_UI_BOOKMARKS_FOLDER_CHOOSER_BOOKMARKS_FOLDER_CHOOSER_MEDIATOR_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2023 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/folder_chooser/bookmarks_folder_chooser_mediator.h"

#import "base/containers/contains.h"
#import "components/bookmarks/browser/bookmark_model.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
#import "ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_consumer.h"
#import "ios/chrome/browser/ui/bookmarks/folder_chooser/bookmarks_folder_chooser_mutator.h"

#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif

using bookmarks::BookmarkModel;
using bookmarks::BookmarkNode;

@interface BookmarksFolderChooserMediator () <BookmarksFolderChooserMutator> {
BookmarkModel* _bookmarkModel;
std::set<const BookmarkNode*>* _editedNodes;
}

@end

@implementation BookmarksFolderChooserMediator

- (instancetype)initWithBookmarkModel:(BookmarkModel*)model
editedNodes:(std::set<const BookmarkNode*>*)nodes {
DCHECK(model);
DCHECK(model->loaded());

self = [super init];
if (self) {
_bookmarkModel = model;
_editedNodes = nodes;
}
return self;
}

#pragma mark - BookmarksFolderChooserDataSource

- (const BookmarkNode*)rootFolder {
return _bookmarkModel->root_node();
}

- (const std::set<const BookmarkNode*>&)editedNodes {
return *_editedNodes;
}

- (std::vector<const BookmarkNode*>)visibleFolders {
return bookmark_utils_ios::VisibleNonDescendantNodes(*_editedNodes,
_bookmarkModel);
}

#pragma mark - BookmarksFolderChooserMutator

- (void)setSelectedFolder:(const BookmarkNode*)folder {
_selectedFolder = folder;
[_consumer notifyModelUpdated];
}

- (void)removeFromEditedNodes:(const BookmarkNode*)node {
_editedNodes->erase(node);
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2023 The Chromium Authors
// 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_BOOKMARKS_FOLDER_CHOOSER_BOOKMARKS_FOLDER_CHOOSER_MUTATOR_H_
#define IOS_CHROME_BROWSER_UI_BOOKMARKS_FOLDER_CHOOSER_BOOKMARKS_FOLDER_CHOOSER_MUTATOR_H_

#import <Foundation/Foundation.h>

namespace bookmarks {
class BookmarkNode;
} // namespace bookmarks

// A model mutator class for folder chooser view controller to make changes to
// te model.
@protocol BookmarksFolderChooserMutator <NSObject>

// TODO(crbug.com/1405746): Change parameter signature. View controller should
// not know about BookmarkNode.
- (void)setSelectedFolder:(const bookmarks::BookmarkNode*)folder;
// TODO(crbug.com/1405746): Delete this method after the mediator is configured
// to observe BookmarkModelBridge.
- (void)removeFromEditedNodes:(const bookmarks::BookmarkNode*)node;

@end

#endif // IOS_CHROME_BROWSER_UI_BOOKMARKS_FOLDER_CHOOSER_BOOKMARKS_FOLDER_CHOOSER_MUTATOR_H_

0 comments on commit e4733d4

Please sign in to comment.