From 1f0123db3692e0fd3a0e9815afa1402dba4a6af7 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 7 Feb 2018 13:11:40 -0800 Subject: [PATCH 1/7] =?UTF-8?q?Remove=20code=20setting=20the=20sidebarView?= =?UTF-8?q?Controller=20on=20SidebarOutlineView,=20since=20it=20doesn?= =?UTF-8?q?=E2=80=99t=20use=20it.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sidebar/SidebarOutlineView.swift | 25 +++++++++++-------- .../Sidebar/SidebarViewController.swift | 1 - 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Evergreen/MainWindow/Sidebar/SidebarOutlineView.swift b/Evergreen/MainWindow/Sidebar/SidebarOutlineView.swift index b154d410d..2ed394dd7 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarOutlineView.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarOutlineView.swift @@ -12,19 +12,9 @@ import RSTree class SidebarOutlineView : NSOutlineView { - weak var sidebarViewController: SidebarViewController? @IBOutlet var keyboardDelegate: KeyboardDelegate! - //MARK: NSResponder - - override func keyDown(with event: NSEvent) { - - if keyboardDelegate.keydown(event, in: self) { - return - } - - super.keyDown(with: event) - } + // MARK: NSTableView override func frameOfCell(atColumn column: Int, row: Int) -> NSRect { @@ -45,6 +35,8 @@ class SidebarOutlineView : NSOutlineView { return frame } + // MARK: NSView + override func viewWillStartLiveResize() { if let scrollView = self.enclosingScrollView { @@ -60,4 +52,15 @@ class SidebarOutlineView : NSOutlineView { } super.viewDidEndLiveResize() } + + // MARK: NSResponder + + override func keyDown(with event: NSEvent) { + + if keyboardDelegate.keydown(event, in: self) { + return + } + + super.keyDown(with: event) + } } diff --git a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift index 788051ae5..bbca2b5ce 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift @@ -37,7 +37,6 @@ import RSCore sidebarCellAppearance = SidebarCellAppearance(theme: appDelegate.currentTheme, fontSize: AppDefaults.shared.sidebarFontSize) - outlineView.sidebarViewController = self outlineView.setDraggingSourceOperationMask(.move, forLocal: true) outlineView.setDraggingSourceOperationMask(.copy, forLocal: false) From d59058c0147e8429563340569c34253b69c1464c Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 7 Feb 2018 13:17:28 -0800 Subject: [PATCH 2/7] Show a contextual menu in the sidebar. Create and wire-up SidebarContextualMenuDelegate. --- Evergreen.xcodeproj/project.pbxproj | 4 ++ Evergreen/Base.lproj/MainWindow.storyboard | 37 +++++++++++++++---- .../SidebarContextualMenuDelegate.swift | 34 +++++++++++++++++ .../Sidebar/SidebarViewController.swift | 1 + 4 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 Evergreen/MainWindow/Sidebar/SidebarContextualMenuDelegate.swift diff --git a/Evergreen.xcodeproj/project.pbxproj b/Evergreen.xcodeproj/project.pbxproj index 6c6918fe6..89429b796 100644 --- a/Evergreen.xcodeproj/project.pbxproj +++ b/Evergreen.xcodeproj/project.pbxproj @@ -51,6 +51,7 @@ 846E77421F6EF6A100A165E2 /* Database.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 846E77211F6EF5D100A165E2 /* Database.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 84702AA41FA27AC0006B8943 /* MarkReadOrUnreadCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84702AA31FA27AC0006B8943 /* MarkReadOrUnreadCommand.swift */; }; 8472058120142E8900AD578B /* FeedInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8472058020142E8900AD578B /* FeedInspectorViewController.swift */; }; + 847FA121202BA34100BB56C8 /* SidebarContextualMenuDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847FA120202BA34100BB56C8 /* SidebarContextualMenuDelegate.swift */; }; 848F6AE51FC29CFB002D422E /* FaviconDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848F6AE41FC29CFA002D422E /* FaviconDownloader.swift */; }; 849A97431ED9EAA9007D329B /* AddFolderWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97421ED9EAA9007D329B /* AddFolderWindowController.swift */; }; 849A97531ED9EAC0007D329B /* AddFeedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97511ED9EAC0007D329B /* AddFeedController.swift */; }; @@ -542,6 +543,7 @@ 84702AA31FA27AC0006B8943 /* MarkReadOrUnreadCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkReadOrUnreadCommand.swift; sourceTree = ""; }; 8472058020142E8900AD578B /* FeedInspectorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedInspectorViewController.swift; sourceTree = ""; }; 847752FE2008879500D93690 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; + 847FA120202BA34100BB56C8 /* SidebarContextualMenuDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarContextualMenuDelegate.swift; sourceTree = ""; }; 848F6AE41FC29CFA002D422E /* FaviconDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconDownloader.swift; sourceTree = ""; }; 849A97421ED9EAA9007D329B /* AddFolderWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderWindowController.swift; sourceTree = ""; }; 849A97511ED9EAC0007D329B /* AddFeedController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddFeedController.swift; path = AddFeed/AddFeedController.swift; sourceTree = ""; }; @@ -920,6 +922,7 @@ 845F52EC1FB2B9FC00C10BF0 /* FeedPasteboardWriter.swift */, 849A97821ED9EC63007D329B /* SidebarStatusBarView.swift */, 84D5BA1F201E8FB6009092BD /* SidebarGearMenuDelegate.swift */, + 847FA120202BA34100BB56C8 /* SidebarContextualMenuDelegate.swift */, 844B5B6A1FEA224000C7C76A /* Keyboard */, 845A29251FC928C7007B49E3 /* Cell */, 84A37CB3201ECD610087C5AF /* Renaming */, @@ -1826,6 +1829,7 @@ 84E46C7D1F75EF7B005ECFB3 /* AppDefaults.swift in Sources */, D5907D972004B7EB005947E5 /* Account+Scriptability.swift in Sources */, 841ABA4E20145E7300980E11 /* NothingInspectorViewController.swift in Sources */, + 847FA121202BA34100BB56C8 /* SidebarContextualMenuDelegate.swift in Sources */, 842E45CE1ED8C308000A8B52 /* AppNotifications.swift in Sources */, 844B5B5B1FEA00FB00C7C76A /* TimelineKeyboardDelegate.swift in Sources */, 84DAEE321F870B390058304B /* DockBadge.swift in Sources */, diff --git a/Evergreen/Base.lproj/MainWindow.storyboard b/Evergreen/Base.lproj/MainWindow.storyboard index a2232733d..bb942f01b 100644 --- a/Evergreen/Base.lproj/MainWindow.storyboard +++ b/Evergreen/Base.lproj/MainWindow.storyboard @@ -359,6 +359,7 @@ + @@ -441,11 +442,28 @@ + + + + + + + + + + + + + + + + + @@ -456,6 +474,11 @@ + + + + + @@ -682,12 +705,12 @@ - - - - - - - + + + + + + + diff --git a/Evergreen/MainWindow/Sidebar/SidebarContextualMenuDelegate.swift b/Evergreen/MainWindow/Sidebar/SidebarContextualMenuDelegate.swift new file mode 100644 index 000000000..bec219b97 --- /dev/null +++ b/Evergreen/MainWindow/Sidebar/SidebarContextualMenuDelegate.swift @@ -0,0 +1,34 @@ +// +// SidebarContextualMenuDelegate.swift +// Evergreen +// +// Created by Brent Simmons on 2/7/18. +// Copyright © 2018 Ranchero Software. All rights reserved. +// + +import AppKit + +@objc final class SidebarContextualMenuDelegate: NSObject, NSMenuDelegate { + + @IBOutlet weak var sidebarViewController: SidebarViewController? + + public func menuNeedsUpdate(_ menu: NSMenu) { + + guard let sidebarViewController = sidebarViewController else { + return + } + + menu.removeAllItems() + + guard let contextualMenu = sidebarViewController.contextualMenuForSelectedObjects() else { + return + } + + let items = contextualMenu.items + contextualMenu.removeAllItems() + for menuItem in items { + menu.addItem(menuItem) + } + } +} + diff --git a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift index bbca2b5ce..38c53323f 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift @@ -16,6 +16,7 @@ import RSCore @IBOutlet var outlineView: SidebarOutlineView! @IBOutlet var gearMenuDelegate: SidebarGearMenuDelegate! + @IBOutlet var contextualMenuDelegate: SidebarContextualMenuDelegate! let treeControllerDelegate = SidebarTreeControllerDelegate() lazy var treeController: TreeController = { From 4491c5f443a9476d92f959e96a5daed380292f7d Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 7 Feb 2018 13:25:17 -0800 Subject: [PATCH 3/7] Make the sidebar contextual menu refer to the clicked row rather than the selected row. --- .../Sidebar/SidebarContextualMenuDelegate.swift | 2 +- .../Sidebar/SidebarGearMenuDelegate.swift | 7 +++---- .../MainWindow/Sidebar/SidebarViewController.swift | 13 +++++++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Evergreen/MainWindow/Sidebar/SidebarContextualMenuDelegate.swift b/Evergreen/MainWindow/Sidebar/SidebarContextualMenuDelegate.swift index bec219b97..1c2944646 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarContextualMenuDelegate.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarContextualMenuDelegate.swift @@ -20,7 +20,7 @@ import AppKit menu.removeAllItems() - guard let contextualMenu = sidebarViewController.contextualMenuForSelectedObjects() else { + guard let contextualMenu = sidebarViewController.contextualMenuForClickedRows() else { return } diff --git a/Evergreen/MainWindow/Sidebar/SidebarGearMenuDelegate.swift b/Evergreen/MainWindow/Sidebar/SidebarGearMenuDelegate.swift index 1d33f3e37..a363f1804 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarGearMenuDelegate.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarGearMenuDelegate.swift @@ -14,10 +14,6 @@ import AppKit public func menuNeedsUpdate(_ menu: NSMenu) { - guard let sidebarViewController = sidebarViewController else { - return - } - // Save the first item, since it’s the gear icon itself. guard let gearMenuItem = menu.item(at: 0) else { assertionFailure("Expected sidebar gear menu to have at least one item.") @@ -26,6 +22,9 @@ import AppKit menu.removeAllItems() menu.addItem(gearMenuItem) + guard let sidebarViewController = sidebarViewController else { + return + } guard let contextualMenu = sidebarViewController.contextualMenuForSelectedObjects() else { return } diff --git a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift index 38c53323f..9ca5fb51d 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift @@ -200,6 +200,19 @@ import RSCore return menu(for: selectedObjects) } + func contextualMenuForClickedRows() -> NSMenu? { + + // TODO: If the clickedRow is part of the selected rows, then do a contextual menu for all the selected rows. + + let row = outlineView.clickedRow + guard row != -1, let node = nodeForRow(row) else { + return nil + } + + let object = node.representedObject + return menu(for: [object]) + } + // MARK: NSOutlineViewDelegate func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { From a3a9d467dc137d3433a1ca6f7456f05996a31af4 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 7 Feb 2018 21:23:18 -0800 Subject: [PATCH 4/7] Show the contextual menu for all selected items in the sidebar when the clicked row is part of the selection. --- Evergreen/MainWindow/Sidebar/SidebarViewController.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift index 9ca5fb51d..3afc39974 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift @@ -202,13 +202,16 @@ import RSCore func contextualMenuForClickedRows() -> NSMenu? { - // TODO: If the clickedRow is part of the selected rows, then do a contextual menu for all the selected rows. - let row = outlineView.clickedRow guard row != -1, let node = nodeForRow(row) else { return nil } + if outlineView.selectedRowIndexes.contains(row) { + // If the clickedRow is part of the selected rows, then do a contextual menu for all the selected rows. + return contextualMenuForSelectedObjects() + } + let object = node.representedObject return menu(for: [object]) } From 78530dbb96ac79bf897f5793d4e57c3752a4f676 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 7 Feb 2018 21:42:33 -0800 Subject: [PATCH 5/7] Change the name of the Show/Hide Sidebar command as needed. Fix #98. --- .../MainWindow/MainWindowController.swift | 91 ++++++++++--------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/Evergreen/MainWindow/MainWindowController.swift b/Evergreen/MainWindow/MainWindowController.swift index 3132c8149..e336244b6 100644 --- a/Evergreen/MainWindow/MainWindowController.swift +++ b/Evergreen/MainWindow/MainWindowController.swift @@ -13,7 +13,7 @@ import Account private let kWindowFrameKey = "MainWindow" class MainWindowController : NSWindowController, NSUserInterfaceValidations { - + var isOpen: Bool { return isWindowLoaded && window!.isVisible } @@ -38,9 +38,9 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { static var didPositionWindowOnFirstRun = false - override func windowDidLoad() { - - super.windowDidLoad() + override func windowDidLoad() { + + super.windowDidLoad() if !AppDefaults.shared.showTitleOnMainWindow { window?.titleVisibility = .hidden @@ -82,12 +82,12 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { return sidebarViewController?.selectedObjects } - // MARK: Notifications - + // MARK: Notifications + @objc func applicationWillTerminate(_ note: Notification) { - + window?.saveFrame(usingName: windowAutosaveName) - } + } @objc func appNavigationKeyPressed(_ note: Notification) { @@ -152,7 +152,22 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { if item.action == #selector(toolbarShowShareMenu(_:)) { return canShowShareMenu() } - + + if item.action == #selector(toggleSidebar(_:)) { + + guard let splitViewItem = sidebarSplitViewItem else { + return false + } + + let sidebarIsShowing = !splitViewItem.isCollapsed + if let menuItem = item as? NSMenuItem { + let title = sidebarIsShowing ? NSLocalizedString("Hide Sidebar", comment: "Menu item") : NSLocalizedString("Show Sidebar", comment: "Menu item") + menuItem.title = title + } + + return true + } + return true } @@ -171,10 +186,10 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { } - @IBAction func showAddFolderWindow(_ sender: Any) { + @IBAction func showAddFolderWindow(_ sender: Any) { - appDelegate.showAddFolderSheetOnWindow(window!) - } + appDelegate.showAddFolderSheetOnWindow(window!) + } @IBAction func showAddFeedWindow(_ sender: Any) { @@ -390,59 +405,47 @@ extension MainWindowController: NSToolbarDelegate { private extension MainWindowController { var splitViewController: NSSplitViewController? { - get { - guard let viewController = contentViewController else { - return nil - } - return viewController.childViewControllers.first as? NSSplitViewController + guard let viewController = contentViewController else { + return nil } + return viewController.childViewControllers.first as? NSSplitViewController } var sidebarViewController: SidebarViewController? { - get { - return splitViewController?.splitViewItems[0].viewController as? SidebarViewController - } + return splitViewController?.splitViewItems[0].viewController as? SidebarViewController } var timelineViewController: TimelineViewController? { - get { - return splitViewController?.splitViewItems[1].viewController as? TimelineViewController - } + return splitViewController?.splitViewItems[1].viewController as? TimelineViewController } - + + var sidebarSplitViewItem: NSSplitViewItem? { + return splitViewController?.splitViewItems[0] + } + var detailSplitViewItem: NSSplitViewItem? { - get { - return splitViewController?.splitViewItems[2] - } + return splitViewController?.splitViewItems[2] } var detailViewController: DetailViewController? { - get { - return splitViewController?.splitViewItems[2].viewController as? DetailViewController - } + return splitViewController?.splitViewItems[2].viewController as? DetailViewController } var selectedArticles: [Article]? { - get { - return timelineViewController?.selectedArticles - } + return timelineViewController?.selectedArticles } - + var oneSelectedArticle: Article? { - get { - if let articles = selectedArticles { - return articles.count == 1 ? articles[0] : nil - } - return nil + if let articles = selectedArticles { + return articles.count == 1 ? articles[0] : nil } + return nil } - + var currentLink: String? { - get { - return oneSelectedArticle?.preferredLink - } + return oneSelectedArticle?.preferredLink } - + func canGoToNextUnread() -> Bool { guard let timelineViewController = timelineViewController, let sidebarViewController = sidebarViewController else { From 2797c607c30369c87ecb7b2ff07d347229b19992 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 7 Feb 2018 21:46:54 -0800 Subject: [PATCH 6/7] Update row height in timeline when font setting changes. --- .../Timeline/TimelineViewController.swift | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/Evergreen/MainWindow/Timeline/TimelineViewController.swift b/Evergreen/MainWindow/Timeline/TimelineViewController.swift index 2d5243c75..3df1c350a 100644 --- a/Evergreen/MainWindow/Timeline/TimelineViewController.swift +++ b/Evergreen/MainWindow/Timeline/TimelineViewController.swift @@ -36,7 +36,7 @@ class TimelineViewController: NSViewController, UndoableCommandRunner { didSet { if showFeedNames != oldValue { updateShowAvatars() - tableView.rowHeight = currentRowHeight + updateTableViewRowHeight() } } } @@ -416,6 +416,7 @@ class TimelineViewController: NSViewController, UndoableCommandRunner { rowHeightWithFeedName = calculateRowHeight(showingFeedNames: true) rowHeightWithoutFeedName = calculateRowHeight(showingFeedNames: false) + updateTableViewRowHeight() } } @@ -587,6 +588,11 @@ private extension TimelineViewController { } } + func updateTableViewRowHeight() { + + tableView.rowHeight = currentRowHeight + } + func updateShowAvatars() { if showFeedNames { @@ -617,17 +623,32 @@ private extension TimelineViewController { func sortDirectionDidChange() { - let selectedArticleIDs = selectedArticles.articleIDs() + performBlockAndRestoreSelection { + let unsortedArticles = Set(articles) + updateArticles(with: unsortedArticles) + } + } - let unsortedArticles = Set(articles) - updateArticles(with: unsortedArticles) + func selectedArticleIDs() -> [String] { - selectArticles(selectedArticleIDs) + return selectedArticles.articleIDs() + } + + func restoreSelection(_ articleIDs: [String]) { + + selectArticles(articleIDs) if tableView.selectedRow != -1 { tableView.scrollRowToVisible(tableView.selectedRow) } } + func performBlockAndRestoreSelection(_ block: (() -> Void)) { + + let savedSelection = selectedArticleIDs() + block() + restoreSelection(savedSelection) + } + // MARK: Fetching Articles func fetchArticles() { @@ -672,15 +693,13 @@ private extension TimelineViewController { return } - let selectedArticleIDs = selectedArticles.articleIDs() - - var unsortedArticles = fetchUnsortedArticles(for: representedObjects) - unsortedArticles.formUnion(Set(articles)) - updateArticles(with: unsortedArticles) - - selectArticles(selectedArticleIDs) + performBlockAndRestoreSelection { + var unsortedArticles = fetchUnsortedArticles(for: representedObjects) + unsortedArticles.formUnion(Set(articles)) + updateArticles(with: unsortedArticles) + } } - + func selectArticles(_ articleIDs: [String]) { let indexesToSelect = articles.indexesForArticleIDs(Set(articleIDs)) From 765a91dd34045aeb204342001c1adeaf6d9893e3 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 7 Feb 2018 21:48:51 -0800 Subject: [PATCH 7/7] Restore selection in timeline after reload due to font size change. --- Evergreen/MainWindow/Timeline/TimelineViewController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Evergreen/MainWindow/Timeline/TimelineViewController.swift b/Evergreen/MainWindow/Timeline/TimelineViewController.swift index 3df1c350a..afcf64d16 100644 --- a/Evergreen/MainWindow/Timeline/TimelineViewController.swift +++ b/Evergreen/MainWindow/Timeline/TimelineViewController.swift @@ -147,7 +147,9 @@ class TimelineViewController: NSViewController, UndoableCommandRunner { cellAppearance = TimelineCellAppearance(theme: appDelegate.currentTheme, showAvatar: false, fontSize: fontSize) cellAppearanceWithAvatar = TimelineCellAppearance(theme: appDelegate.currentTheme, showAvatar: true, fontSize: fontSize) updateRowHeights() - tableView.reloadData() + performBlockAndRestoreSelection { + tableView.reloadData() + } } // MARK: - API