Skip to content

Commit

Permalink
Sort bookmarks in bookmarks panel (#3001)
Browse files Browse the repository at this point in the history
  • Loading branch information
jotaemepereira authored Jul 24, 2024
1 parent b79737f commit c82227f
Show file tree
Hide file tree
Showing 23 changed files with 589 additions and 91 deletions.
12 changes: 12 additions & 0 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2537,6 +2537,10 @@
BBB881892C4029BA001247C6 /* BookmarkListTreeControllerSearchDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB881872C4029BA001247C6 /* BookmarkListTreeControllerSearchDataSource.swift */; };
BBDFDC5A2B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBDFDC592B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift */; };
BBDFDC5D2B2B8E2100F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBDFDC592B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift */; };
BBFB727F2C48047C0088884C /* SortBookmarksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBFB727E2C48047C0088884C /* SortBookmarksViewModel.swift */; };
BBFB72802C48047C0088884C /* SortBookmarksViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBFB727E2C48047C0088884C /* SortBookmarksViewModel.swift */; };
BBFF355D2C4AF26200DA3289 /* BookmarksSortModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBFF355C2C4AF26200DA3289 /* BookmarksSortModeTests.swift */; };
BBFF355E2C4AF26200DA3289 /* BookmarksSortModeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBFF355C2C4AF26200DA3289 /* BookmarksSortModeTests.swift */; };
BD384AC92BBC821A00EF3735 /* vpn-dark-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */; };
BD384ACA2BBC821A00EF3735 /* vpn-light-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC72BBC821100EF3735 /* vpn-light-mode.json */; };
BD384ACB2BBC821B00EF3735 /* vpn-dark-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */; };
Expand Down Expand Up @@ -4213,6 +4217,8 @@
BB5789712B2CA70F0009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionSubscriptionEventHandler.swift; sourceTree = "<group>"; };
BBB881872C4029BA001247C6 /* BookmarkListTreeControllerSearchDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkListTreeControllerSearchDataSource.swift; sourceTree = "<group>"; };
BBDFDC592B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionExternalWaitlistPixels.swift; sourceTree = "<group>"; };
BBFB727E2C48047C0088884C /* SortBookmarksViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SortBookmarksViewModel.swift; sourceTree = "<group>"; };
BBFF355C2C4AF26200DA3289 /* BookmarksSortModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksSortModeTests.swift; sourceTree = "<group>"; };
BD384AC72BBC821100EF3735 /* vpn-light-mode.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "vpn-light-mode.json"; sourceTree = "<group>"; };
BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "vpn-dark-mode.json"; sourceTree = "<group>"; };
BDA7647B2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultVPNLocationFormatter.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6654,6 +6660,7 @@
9F26060D2B85E17D00819292 /* AddEditBookmarkDialogCoordinatorViewModelTests.swift */,
9F0FFFB32BCCAE37007C87DD /* BookmarkAllTabsDialogCoordinatorViewModelTests.swift */,
9FA5A0A82BC900FC00153786 /* BookmarkAllTabsDialogViewModelTests.swift */,
BBFF355C2C4AF26200DA3289 /* BookmarksSortModeTests.swift */,
);
path = ViewModels;
sourceTree = "<group>";
Expand Down Expand Up @@ -7479,6 +7486,7 @@
9FEE986C2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift */,
9F9C4A002BC7F36D0099738D /* BookmarkAllTabsDialogCoordinatorViewModel.swift */,
9F9C49FC2BC7E9820099738D /* BookmarkAllTabsDialogViewModel.swift */,
BBFB727E2C48047C0088884C /* SortBookmarksViewModel.swift */,
);
path = ViewModel;
sourceTree = "<group>";
Expand Down Expand Up @@ -10008,6 +10016,7 @@
4BF0E5062AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */,
3706FAF8293F65D500E42796 /* URLEventHandler.swift in Sources */,
9FBD84742BB3E15D00220859 /* InstallationAttributionPixelHandler.swift in Sources */,
BBFB72802C48047C0088884C /* SortBookmarksViewModel.swift in Sources */,
37197EA72942443D00394917 /* AuthenticationAlert.swift in Sources */,
3706FEC3293F6F0600E42796 /* BWCommunicator.swift in Sources */,
3706FAFA293F65D500E42796 /* CleanThisHistoryMenuItem.swift in Sources */,
Expand Down Expand Up @@ -10850,6 +10859,7 @@
3706FE49293F661700E42796 /* BookmarkNodePathTests.swift in Sources */,
1DE03425298BC7F000CAB3D7 /* InternalUserDeciderStoreMock.swift in Sources */,
3706FE4A293F661700E42796 /* BookmarkManagedObjectTests.swift in Sources */,
BBFF355E2C4AF26200DA3289 /* BookmarksSortModeTests.swift in Sources */,
EEC8EB402982CD550065AA39 /* JSAlertViewModelTests.swift in Sources */,
BDA764922BC4E57200D0400C /* MockVPNLocationFormatter.swift in Sources */,
3706FE4B293F661700E42796 /* BookmarksHTMLImporterTests.swift in Sources */,
Expand Down Expand Up @@ -11711,6 +11721,7 @@
B6E6B9E32BA1F5F1008AA7E1 /* FilePresenter.swift in Sources */,
B6CC266C2BAD9CD800F53F8D /* FileProgressPresenter.swift in Sources */,
3158B14D2B0BF74D00AF130C /* DataBrokerProtectionManager.swift in Sources */,
BBFB727F2C48047C0088884C /* SortBookmarksViewModel.swift in Sources */,
4BA1A6A5258B07DF00F6F690 /* EncryptedValueTransformer.swift in Sources */,
B634DBE1293C8FD500C3C99E /* Tab+Dialogs.swift in Sources */,
4B92929F26670D2A00AD2C21 /* PasteboardBookmark.swift in Sources */,
Expand Down Expand Up @@ -12230,6 +12241,7 @@
37CD54BB27F25A4000F1F7B9 /* DownloadsPreferencesTests.swift in Sources */,
4BE344EE2B2376DF003FC223 /* VPNFeedbackFormViewModelTests.swift in Sources */,
9F872D9D2B9058D000138637 /* Bookmarks+TabTests.swift in Sources */,
BBFF355D2C4AF26200DA3289 /* BookmarksSortModeTests.swift in Sources */,
9F3910622B68C35600CB5112 /* DownloadsTabExtensionTests.swift in Sources */,
4B9DB0562A983B55000927DB /* MockNotificationService.swift in Sources */,
4B02199C25E063DE00ED7DEA /* FireproofDomainsTests.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "0fbc8848e389af3bb55c182bc19ca9d5dc2f255b",
"version" : "1.4.0"
"revision" : "41982a3656a71c768319979febd796c6fd111d5c",
"version" : "1.5.0"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "sort-asc.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "sort-desc.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions DuckDuckGo/Bookmarks/Model/Bookmark.swift
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,16 @@ final class Bookmark: BaseBookmarkEntity {
}

}

extension Array where Element == BaseBookmarkEntity {
func sorted(by sortMode: BookmarksSortMode) -> [BaseBookmarkEntity] {
switch sortMode {
case .manual:
return self
case .nameAscending:
return self.sorted { $0.title.localizedCaseInsensitiveCompare($1.title) == .orderedAscending }
case .nameDescending:
return self.sorted { $0.title.localizedCaseInsensitiveCompare($1.title) == .orderedDescending }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,37 @@ final class BookmarkListTreeControllerDataSource: BookmarkTreeControllerDataSour
self.bookmarkManager = bookmarkManager
}

func treeController(childNodesFor node: BookmarkNode) -> [BookmarkNode] {
return node.isRoot ? childNodesForRootNode(node) : childNodes(node)
func treeController(childNodesFor node: BookmarkNode, sortMode: BookmarksSortMode) -> [BookmarkNode] {
return node.isRoot ? childNodesForRootNode(node, for: sortMode) : childNodes(node, for: sortMode)
}

// MARK: - Private

private func childNodesForRootNode(_ node: BookmarkNode) -> [BookmarkNode] {
let topLevelNodes = bookmarkManager.list?.topLevelEntities.compactMap { (item) -> BookmarkNode? in
if let folder = item as? BookmarkFolder {
let itemNode = node.createChildNode(item)
itemNode.canHaveChildNodes = !folder.children.isEmpty

return itemNode
} else if item is Bookmark {
let itemNode = node.findOrCreateChildNode(with: item)
itemNode.canHaveChildNodes = false
return itemNode
} else {
assertionFailure("\(#file): Tried to display non-bookmark type in bookmark list")
return nil
}
} ?? []
private func childNodesForRootNode(_ node: BookmarkNode, for sortMode: BookmarksSortMode) -> [BookmarkNode] {
let topLevelNodes = bookmarkManager.list?.topLevelEntities
.sorted(by: sortMode)
.compactMap { (item) -> BookmarkNode? in
if let folder = item as? BookmarkFolder {
let itemNode = node.createChildNode(item)
itemNode.canHaveChildNodes = !folder.children.isEmpty

return itemNode
} else if item is Bookmark {
let itemNode = node.findOrCreateChildNode(with: item)
itemNode.canHaveChildNodes = false
return itemNode
} else {
assertionFailure("\(#file): Tried to display non-bookmark type in bookmark list")
return nil
}
} ?? []

return topLevelNodes
}

private func childNodes(_ node: BookmarkNode) -> [BookmarkNode] {
private func childNodes(_ node: BookmarkNode, for sortMode: BookmarksSortMode) -> [BookmarkNode] {
if let folder = node.representedObject as? BookmarkFolder {
return childNodes(for: folder, parentNode: node)
return childNodes(for: folder, parentNode: node, sortMode: sortMode)
}

return []
Expand All @@ -72,20 +74,22 @@ final class BookmarkListTreeControllerDataSource: BookmarkTreeControllerDataSour
return node
}

private func childNodes(for folder: BookmarkFolder, parentNode: BookmarkNode) -> [BookmarkNode] {
private func childNodes(for folder: BookmarkFolder, parentNode: BookmarkNode, sortMode: BookmarksSortMode) -> [BookmarkNode] {
var updatedChildNodes = [BookmarkNode]()

folder.children.forEach { representedObject in
if let existingNode = parentNode.childNodeRepresenting(object: representedObject) {
if !updatedChildNodes.contains(existingNode) {
updatedChildNodes += [existingNode]
return
folder.children
.sorted(by: sortMode)
.forEach { representedObject in
if let existingNode = parentNode.childNodeRepresenting(object: representedObject) {
if !updatedChildNodes.contains(existingNode) {
updatedChildNodes += [existingNode]
return
}
}
}

let newNode = self.createNode(representedObject, parent: parentNode)
updatedChildNodes += [newNode]
}
let newNode = self.createNode(representedObject, parent: parentNode)
updatedChildNodes += [newNode]
}

return updatedChildNodes
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ final class BookmarkListTreeControllerSearchDataSource: BookmarkTreeControllerSe
self.bookmarkManager = bookmarkManager
}

func nodes(for searchQuery: String) -> [BookmarkNode] {
func nodes(for searchQuery: String, sortMode: BookmarksSortMode) -> [BookmarkNode] {
let searchResults = bookmarkManager.search(by: searchQuery)

return rebuildChildNodes(for: searchResults)
return rebuildChildNodes(for: searchResults.sorted(by: sortMode))
}

private func rebuildChildNodes(for results: [BaseBookmarkEntity]) -> [BookmarkNode] {
Expand Down
13 changes: 7 additions & 6 deletions DuckDuckGo/Bookmarks/Model/BookmarkOutlineViewDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ final class BookmarkOutlineViewDataSource: NSObject, NSOutlineViewDataSource, NS
contentMode: ContentMode,
bookmarkManager: BookmarkManager,
treeController: BookmarkTreeController,
sortMode: BookmarksSortMode,
showMenuButtonOnHover: Bool = true,
onMenuRequestedAction: ((BookmarkOutlineCellView) -> Void)? = nil,
presentFaviconsFetcherOnboarding: (() -> Void)? = nil
Expand All @@ -64,20 +65,20 @@ final class BookmarkOutlineViewDataSource: NSObject, NSOutlineViewDataSource, NS

super.init()

reloadData()
reloadData(with: sortMode)
}

func reloadData() {
func reloadData(with sortMode: BookmarksSortMode) {
isSearching = false
dragDestinationFolderInSearchMode = nil
setFolderCount()
treeController.rebuild()
treeController.rebuild(for: sortMode)
}

func reloadData(for searchQuery: String) {
func reloadData(for searchQuery: String, and sortMode: BookmarksSortMode) {
isSearching = true
setFolderCount()
treeController.rebuild(for: searchQuery)
treeController.rebuild(for: searchQuery, sortMode: sortMode)
}

private func setFolderCount() {
Expand Down Expand Up @@ -270,7 +271,7 @@ final class BookmarkOutlineViewDataSource: NSObject, NSOutlineViewDataSource, NS
let containsDescendantOfDestination = draggedFolders.contains { draggedFolder in
let folder = BookmarkFolder(id: draggedFolder.id, title: draggedFolder.name, parentFolderUUID: draggedFolder.parentFolderUUID, children: draggedFolder.children)

guard let draggedNode = treeController.node(representing: folder) else {
guard let draggedNode = treeController.findNodeWithId(representing: folder) else {
return false
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import Foundation

final class BookmarkSidebarTreeController: BookmarkTreeControllerDataSource {

func treeController(childNodesFor node: BookmarkNode) -> [BookmarkNode] {
func treeController(childNodesFor node: BookmarkNode, sortMode: BookmarksSortMode) -> [BookmarkNode] {
return node.isRoot ? childNodesForRootNode(node) : childNodes(for: node)
}

Expand Down
Loading

0 comments on commit c82227f

Please sign in to comment.