Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit db4b4ab

Browse files
committed
Fix cells highlighting in different modes
1 parent bc2fec3 commit db4b4ab

File tree

9 files changed

+81
-35
lines changed

9 files changed

+81
-35
lines changed

DuckDuckGo.xcodeproj/project.pbxproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6056,6 +6056,8 @@
60566056
4BE5336A286912D40019DBFD /* BookmarksBarCollectionViewItem.swift */,
60576057
4BE53369286912D40019DBFD /* BookmarksBarCollectionViewItem.xib */,
60586058
85774AFE2A713D3B00DE0561 /* BookmarksBarMenuFactory.swift */,
6059+
84F1C8CE2C7705B500716446 /* BookmarksBarMenuPopover.swift */,
6060+
848648A02C76F4B20082282D /* BookmarksBarMenuViewController.swift */,
60596061
4BD18EFF283F0BC500058124 /* BookmarksBarViewController.swift */,
60606062
4BE41A5D28446EAD00760399 /* BookmarksBarViewModel.swift */,
60616063
4BE5336D286915A10019DBFD /* HorizontallyCenteredLayout.swift */,
@@ -6482,8 +6484,8 @@
64826484
859F30622A72A7A900C20372 /* Prompt */ = {
64836485
isa = PBXGroup;
64846486
children = (
6485-
859F30632A72A7BB00C20372 /* BookmarksBarPromptPopover.swift */,
64866487
859F30662A72B38500C20372 /* BookmarksBarPromptAssets.xcassets */,
6488+
859F30632A72A7BB00C20372 /* BookmarksBarPromptPopover.swift */,
64876489
);
64886490
path = Prompt;
64896491
sourceTree = "<group>";
@@ -7673,8 +7675,6 @@
76737675
4B9292C72667123700AD2C21 /* BookmarkManagementSidebarViewController.swift */,
76747676
4B9292C82667123700AD2C21 /* BookmarkManagementSplitViewController.swift */,
76757677
4B92928726670D1600AD2C21 /* BookmarkOutlineCellView.swift */,
7676-
84F1C8CE2C7705B500716446 /* BookmarksBarMenuPopover.swift */,
7677-
848648A02C76F4B20082282D /* BookmarksBarMenuViewController.swift */,
76787678
4B92928526670D1600AD2C21 /* BookmarksOutlineView.swift */,
76797679
4B92928926670D1700AD2C21 /* BookmarkTableCellView.swift */,
76807680
4B9292C92667123700AD2C21 /* BookmarkTableRowView.swift */,

DuckDuckGo/Bookmarks/Model/BookmarkOutlineViewDataSource.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import Foundation
2222

2323
final class BookmarkOutlineViewDataSource: NSObject, BookmarksOutlineViewDataSource, NSOutlineViewDelegate {
2424

25-
enum ContentMode {
25+
enum ContentMode: CaseIterable {
2626
case bookmarksAndFolders
2727
case foldersOnly
2828
case bookmarksMenu
@@ -33,6 +33,13 @@ final class BookmarkOutlineViewDataSource: NSObject, BookmarksOutlineViewDataSou
3333
case .foldersOnly: false
3434
}
3535
}
36+
37+
var showMenuButtonOnHover: Bool {
38+
switch self {
39+
case .bookmarksAndFolders, .bookmarksMenu: true
40+
case .foldersOnly: false
41+
}
42+
}
3643
}
3744

3845
@Published var selectedFolders: [BookmarkFolder] = []
@@ -72,7 +79,6 @@ final class BookmarkOutlineViewDataSource: NSObject, BookmarksOutlineViewDataSou
7279
private let treeController: BookmarkTreeController
7380
private let bookmarkManager: BookmarkManager
7481
private let dragDropManager: BookmarkDragDropManager
75-
private let showMenuButtonOnHover: Bool
7682
private let presentFaviconsFetcherOnboarding: (() -> Void)?
7783

7884
init(
@@ -81,14 +87,12 @@ final class BookmarkOutlineViewDataSource: NSObject, BookmarksOutlineViewDataSou
8187
treeController: BookmarkTreeController,
8288
dragDropManager: BookmarkDragDropManager = .shared,
8389
sortMode: BookmarksSortMode,
84-
showMenuButtonOnHover: Bool = true,
8590
presentFaviconsFetcherOnboarding: (() -> Void)? = nil
8691
) {
8792
self.contentMode = contentMode
8893
self.bookmarkManager = bookmarkManager
8994
self.dragDropManager = dragDropManager
9095
self.treeController = treeController
91-
self.showMenuButtonOnHover = showMenuButtonOnHover
9296
self.presentFaviconsFetcherOnboarding = presentFaviconsFetcherOnboarding
9397

9498
super.init()
@@ -205,11 +209,10 @@ final class BookmarkOutlineViewDataSource: NSObject, BookmarksOutlineViewDataSou
205209
?? OutlineSeparatorViewCell(isSeparatorVisible: contentMode.isSeparatorVisible)
206210
}
207211

208-
let cell = outlineView.makeView(withIdentifier: .init(BookmarkOutlineCellView.className()), owner: self) as? BookmarkOutlineCellView
209-
?? BookmarkOutlineCellView(identifier: .init(BookmarkOutlineCellView.className()))
210-
cell.shouldShowMenuButton = showMenuButtonOnHover
212+
let cell = outlineView.makeView(withIdentifier: BookmarkOutlineCellView.identifier(for: contentMode), owner: self) as? BookmarkOutlineCellView
213+
?? BookmarkOutlineCellView(identifier: BookmarkOutlineCellView.identifier(for: contentMode))
211214
cell.delegate = self
212-
cell.update(from: node, isSearch: isSearching, isMenuPopover: contentMode == .bookmarksMenu)
215+
cell.update(from: node, isSearch: isSearching)
213216

214217
if let bookmark = node.representedObject as? Bookmark, bookmark.favicon(.small) == nil {
215218
presentFaviconsFetcherOnboarding?()

DuckDuckGo/Bookmarks/View/BookmarkManagementSidebarViewController.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ final class BookmarkManagementSidebarViewController: NSViewController {
5656
bookmarkManager: bookmarkManager,
5757
treeController: treeController,
5858
dragDropManager: dragDropManager,
59-
sortMode: selectedSortMode,
60-
showMenuButtonOnHover: false)
59+
sortMode: selectedSortMode)
6160

6261
private var cancellables = Set<AnyCancellable>()
6362
private var selectedSortMode: BookmarksSortMode

DuckDuckGo/Bookmarks/View/BookmarkOutlineCellView.swift

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ protocol BookmarkOutlineCellViewDelegate: AnyObject {
2626
final class BookmarkOutlineCellView: NSTableCellView {
2727

2828
private static let sizingCellIdentifier = NSUserInterfaceItemIdentifier("sizing")
29+
static func identifier(for mode: BookmarkOutlineViewDataSource.ContentMode) -> NSUserInterfaceItemIdentifier {
30+
NSUserInterfaceItemIdentifier("\(mode)_\(self.className())")
31+
}
32+
2933
static let sizingCell = BookmarkOutlineCellView(identifier: BookmarkOutlineCellView.sizingCellIdentifier)
3034

3135
static let rowHeight: CGFloat = 28
@@ -51,7 +55,18 @@ final class BookmarkOutlineCellView: NSTableCellView {
5155
}
5256
}
5357

54-
var shouldShowMenuButton = false
58+
var contentMode: BookmarkOutlineViewDataSource.ContentMode? {
59+
BookmarkOutlineViewDataSource.ContentMode.allCases.first { mode in
60+
Self.identifier(for: mode) == self.identifier
61+
}
62+
}
63+
64+
var shouldShowMenuButton: Bool {
65+
contentMode != .foldersOnly
66+
}
67+
var shouldShowChevron: Bool {
68+
contentMode == .bookmarksMenu
69+
}
5570

5671
weak var delegate: BookmarkOutlineCellViewDelegate?
5772

@@ -222,7 +237,9 @@ final class BookmarkOutlineCellView: NSTableCellView {
222237
}
223238
if !titleLabel.isEnabled {
224239
titleLabel.textColor = .disabledControlTextColor
225-
} else if highlight && isInKeyWindow {
240+
} else if highlight,
241+
isInKeyWindow,
242+
contentMode != .foldersOnly {
226243
titleLabel.textColor = .selectedMenuItemTextColor
227244
urlLabel.textColor = .selectedMenuItemTextColor
228245
} else {
@@ -253,19 +270,19 @@ final class BookmarkOutlineCellView: NSTableCellView {
253270
|| representedObject is PseudoFolder || representedObject is MenuItemNode else { return 0 }
254271

255272
sizingCell.frame = .zero
256-
sizingCell.update(from: representedObject, isMenuPopover: true)
273+
sizingCell.update(from: representedObject)
257274
sizingCell.layoutSubtreeIfNeeded()
258275

259276
return sizingCell.frame.width + 6
260277
}
261278

262-
func update(from object: Any, isSearch: Bool = false, isMenuPopover: Bool) {
279+
func update(from object: Any, isSearch: Bool = false) {
263280
let representedObject = (object as? BookmarkNode)?.representedObject ?? object
264281
switch representedObject {
265282
case let bookmark as Bookmark:
266283
update(from: bookmark, isSearch: isSearch, showURL: identifier != Self.sizingCellIdentifier)
267284
case let folder as BookmarkFolder:
268-
update(from: folder, isSearch: isSearch, showChevron: isMenuPopover)
285+
update(from: folder, isSearch: isSearch)
269286
case let folder as PseudoFolder:
270287
update(from: folder)
271288
case let menuItem as MenuItemNode:
@@ -298,18 +315,18 @@ final class BookmarkOutlineCellView: NSTableCellView {
298315
updateConstraints(isSearch: isSearch)
299316
}
300317

301-
func update(from folder: BookmarkFolder, isSearch: Bool = false, showChevron: Bool) {
318+
func update(from folder: BookmarkFolder, isSearch: Bool = false) {
302319
faviconImageView.image = .folder
303320
faviconImageView.isHidden = false
304321
titleLabel.stringValue = folder.title
305322
titleLabel.isEnabled = true
306-
favoriteImageView.image = showChevron ? .chevronMediumRight16 : nil
323+
favoriteImageView.image = shouldShowChevron ? .chevronMediumRight16 : nil
307324
favoriteImageView.isHidden = favoriteImageView.image == nil
308325
urlLabel.stringValue = ""
309326
self.toolTip = nil
310327

311328
let totalChildBookmarks = folder.totalChildBookmarks
312-
if totalChildBookmarks > 0 && !showChevron {
329+
if totalChildBookmarks > 0 && !shouldShowChevron {
313330
countLabel.stringValue = String(totalChildBookmarks)
314331
countLabel.isHidden = false
315332
} else {
@@ -373,12 +390,12 @@ extension BookmarkOutlineCellView {
373390
BookmarkOutlineCellView(identifier: .init("")),
374391
BookmarkOutlineCellView(identifier: .init("")),
375392
BookmarkOutlineCellView(identifier: .init("")),
393+
BookmarkOutlineCellView(identifier: BookmarkOutlineCellView.identifier(for: .bookmarksMenu)),
376394
BookmarkOutlineCellView(identifier: .init("")),
377395
BookmarkOutlineCellView(identifier: .init("")),
378396
BookmarkOutlineCellView(identifier: .init("")),
379-
BookmarkOutlineCellView(identifier: .init("")),
380-
BookmarkOutlineCellView(identifier: .init("")),
381-
BookmarkOutlineCellView(identifier: .init("")),
397+
BookmarkOutlineCellView(identifier: BookmarkOutlineCellView.identifier(for: .bookmarksMenu)),
398+
BookmarkOutlineCellView(identifier: BookmarkOutlineCellView.identifier(for: .bookmarksMenu)),
382399
BookmarkOutlineCellView(identifier: .init("")),
383400
BookmarkOutlineCellView(identifier: .init("")),
384401
]
@@ -397,22 +414,22 @@ extension BookmarkOutlineCellView {
397414
let bkm2 = Bookmark(id: "3", url: "http://a.b", title: "Bookmark with longer title to test width", isFavorite: false)
398415
cells[2].update(from: bkm2, showURL: false)
399416

400-
cells[3].update(from: BookmarkFolder(id: "4", title: "Bookmark Folder with a reasonably long name"), showChevron: true)
401-
cells[4].update(from: BookmarkFolder(id: "5", title: "Bookmark Folder with 42 bookmark children", children: Array(repeating: Bookmark(id: "2", url: "http://a.b", title: "DuckDuckGo", isFavorite: true), count: 42)), showChevron: false)
417+
cells[3].update(from: BookmarkFolder(id: "4", title: "Bookmark Folder with a reasonably long name"))
418+
cells[4].update(from: BookmarkFolder(id: "5", title: "Bookmark Folder with 42 bookmark children", children: Array(repeating: Bookmark(id: "2", url: "http://a.b", title: "DuckDuckGo", isFavorite: true), count: 42)))
402419
PseudoFolder.favorites.count = 64
403420
cells[5].update(from: PseudoFolder.favorites)
404421
PseudoFolder.bookmarks.count = 256
405422
cells[6].update(from: PseudoFolder.bookmarks)
406423

407424
let node = BookmarkNode(representedObject: MenuItemNode(identifier: "", title: UserText.bookmarksOpenInNewTabs, isEnabled: true), parent: BookmarkNode.genericRootNode())
408-
cells[7].update(from: node, isMenuPopover: true)
425+
cells[7].update(from: node)
409426

410427
let emptyNode = BookmarkNode(representedObject: MenuItemNode(identifier: "", title: UserText.bookmarksBarFolderEmpty, isEnabled: false), parent: BookmarkNode.genericRootNode())
411-
cells[8].update(from: emptyNode, isMenuPopover: true)
428+
cells[8].update(from: emptyNode)
412429

413430
let sbkm = Bookmark(id: "3", url: "http://a.b", title: "Bookmark in Search mode", isFavorite: false)
414431
cells[9].update(from: sbkm, isSearch: true, showURL: false)
415-
cells[10].update(from: BookmarkFolder(id: "5", title: "Folder in Search mode", children: Array(repeating: Bookmark(id: "2", url: "http://a.b", title: "DuckDuckGo", isFavorite: true), count: 42)), isSearch: true, showChevron: false)
432+
cells[10].update(from: BookmarkFolder(id: "5", title: "Folder in Search mode", children: Array(repeating: Bookmark(id: "2", url: "http://a.b", title: "DuckDuckGo", isFavorite: true), count: 42)), isSearch: true)
416433

417434
widthAnchor.constraint(equalToConstant: 258).isActive = true
418435
heightAnchor.constraint(equalToConstant: CGFloat((28 + 1) * cells.count)).isActive = true

DuckDuckGo/Bookmarks/View/BookmarksOutlineView.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ final class BookmarksOutlineView: NSOutlineView {
8383
return nil
8484
}
8585

86+
private var isInPopover: Bool {
87+
popover != nil
88+
}
8689
private var isInKeyPopover: Bool {
8790
guard highlightedRow != nil else { return false }
8891
// is there a child menu popover window owned by our window?
@@ -103,6 +106,11 @@ final class BookmarksOutlineView: NSOutlineView {
103106

104107
// mark highlight with inactive color for non-key popover menu and with active color for key popover menu
105108
private func updateIsInKeyPopoverState() {
109+
guard isInPopover else {
110+
highlightedRowView?.isInKeyWindow = false
111+
highlightedCellView?.isInKeyWindow = false
112+
return
113+
}
106114
// when no highlighted row - our parent is the key popover
107115
guard highlightedRow != nil else {
108116
parentMenuOutlineView?.updateIsInKeyPopoverState()
@@ -366,7 +374,7 @@ final class BookmarksOutlineView: NSOutlineView {
366374
}
367375
if highlightedRow != row {
368376
highlightedRow = row
369-
} else {
377+
} else if isInPopover {
370378
highlightedRowView?.isInKeyWindow = true
371379
highlightedCellView?.isInKeyWindow = true
372380
}

UnitTests/Bookmarks/Model/BookmarkOutlineViewDataSourceTests.swift

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,35 +223,54 @@ class BookmarkOutlineViewDataSourceTests: XCTestCase {
223223
}
224224

225225
@MainActor
226-
func testWhenShowMenuButtonOnHoverIsTrue_ThenCellShouldHaveShouldMenuButtonFlagTrue() throws {
226+
func testWhenContentModeIsBookmarksAndFolders_ThenCellShouldHaveShouldMenuButtonFlagTrue() throws {
227227
// GIVEN
228228
let mockFolder = BookmarkFolder.mock
229229
let mockOutlineView = NSOutlineView(frame: .zero)
230230
let treeController = createTreeController(with: [mockFolder])
231231
let mockFolderNode = treeController.node(representing: mockFolder)!
232-
let dataSource = BookmarkOutlineViewDataSource(contentMode: .bookmarksAndFolders, bookmarkManager: LocalBookmarkManager(), treeController: treeController, sortMode: .manual, showMenuButtonOnHover: true)
232+
let dataSource = BookmarkOutlineViewDataSource(contentMode: .bookmarksAndFolders, bookmarkManager: LocalBookmarkManager(), treeController: treeController, sortMode: .manual)
233233

234234
// WHEN
235235
let cell = try XCTUnwrap(dataSource.outlineView(mockOutlineView, viewFor: nil, item: mockFolderNode) as? BookmarkOutlineCellView)
236236

237237
// THEN
238238
XCTAssertTrue(cell.shouldShowMenuButton)
239+
XCTAssertFalse(cell.shouldShowChevron)
239240
}
240241

241242
@MainActor
242-
func testWhenShowMenuButtonOnHoverIsFalse_ThenCellShouldHaveShouldMenuButtonFlagFalse() throws {
243+
func testWhenContentModeIsFolders_ThenCellShouldHaveShouldMenuButtonFlagFalse() throws {
243244
// GIVEN
244245
let mockFolder = BookmarkFolder.mock
245246
let mockOutlineView = NSOutlineView(frame: .zero)
246247
let treeController = createTreeController(with: [mockFolder])
247248
let mockFolderNode = treeController.node(representing: mockFolder)!
248-
let dataSource = BookmarkOutlineViewDataSource(contentMode: .foldersOnly, bookmarkManager: LocalBookmarkManager(), treeController: treeController, sortMode: .manual, showMenuButtonOnHover: false)
249+
let dataSource = BookmarkOutlineViewDataSource(contentMode: .foldersOnly, bookmarkManager: LocalBookmarkManager(), treeController: treeController, sortMode: .manual)
249250

250251
// WHEN
251252
let cell = try XCTUnwrap(dataSource.outlineView(mockOutlineView, viewFor: nil, item: mockFolderNode) as? BookmarkOutlineCellView)
252253

253254
// THEN
254255
XCTAssertFalse(cell.shouldShowMenuButton)
256+
XCTAssertFalse(cell.shouldShowChevron)
257+
}
258+
259+
@MainActor
260+
func testWhenContentModeIsBookmarksMenu_ThenCellShouldHaveShouldMenuButtonFlagFalse() throws {
261+
// GIVEN
262+
let mockFolder = BookmarkFolder.mock
263+
let mockOutlineView = NSOutlineView(frame: .zero)
264+
let treeController = createTreeController(with: [mockFolder])
265+
let mockFolderNode = treeController.node(representing: mockFolder)!
266+
let dataSource = BookmarkOutlineViewDataSource(contentMode: .bookmarksMenu, bookmarkManager: LocalBookmarkManager(), treeController: treeController, sortMode: .manual)
267+
268+
// WHEN
269+
let cell = try XCTUnwrap(dataSource.outlineView(mockOutlineView, viewFor: nil, item: mockFolderNode) as? BookmarkOutlineCellView)
270+
271+
// THEN
272+
XCTAssertTrue(cell.shouldShowMenuButton)
273+
XCTAssertTrue(cell.shouldShowChevron)
255274
}
256275

257276
// MARK: - Private

0 commit comments

Comments
 (0)