diff --git a/Mac/AppDefaults.swift b/Mac/AppDefaults.swift index f4180440b..9afd69ecb 100644 --- a/Mac/AppDefaults.swift +++ b/Mac/AppDefaults.swift @@ -22,6 +22,7 @@ struct AppDefaults { static let sidebarFontSize = "sidebarFontSize" static let timelineFontSize = "timelineFontSize" static let timelineSortDirection = "timelineSortDirection" + static let timelineGroupByFeed = "timelineGroupByFeed" static let detailFontSize = "detailFontSize" static let openInBrowserInBackground = "openInBrowserInBackground" static let mainWindowWidths = "mainWindowWidths" @@ -137,6 +138,15 @@ struct AppDefaults { } } + static var timelineGroupByFeed: Bool { + get { + return bool(for: Key.timelineGroupByFeed) + } + set { + setBool(for: Key.timelineGroupByFeed, newValue) + } + } + static var timelineShowsSeparators: Bool { return bool(for: Key.timelineShowsSeparators) } @@ -161,7 +171,13 @@ struct AppDefaults { } static func registerDefaults() { - let defaults: [String : Any] = [Key.sidebarFontSize: FontSize.medium.rawValue, Key.timelineFontSize: FontSize.medium.rawValue, Key.detailFontSize: FontSize.medium.rawValue, Key.timelineSortDirection: ComparisonResult.orderedDescending.rawValue, "NSScrollViewShouldScrollUnderTitlebar": false, Key.refreshInterval: RefreshInterval.everyHour.rawValue] + let defaults: [String : Any] = [Key.sidebarFontSize: FontSize.medium.rawValue, + Key.timelineFontSize: FontSize.medium.rawValue, + Key.detailFontSize: FontSize.medium.rawValue, + Key.timelineSortDirection: ComparisonResult.orderedDescending.rawValue, + Key.timelineGroupByFeed: false, + "NSScrollViewShouldScrollUnderTitlebar": false, + Key.refreshInterval: RefreshInterval.everyHour.rawValue] UserDefaults.standard.register(defaults: defaults) diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index dd300884a..46bc8e864 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -41,6 +41,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, @IBOutlet var debugMenuItem: NSMenuItem! @IBOutlet var sortByOldestArticleOnTopMenuItem: NSMenuItem! @IBOutlet var sortByNewestArticleOnTopMenuItem: NSMenuItem! + @IBOutlet var groupArticlesByFeedMenuItem: NSMenuItem! @IBOutlet var checkForUpdatesMenuItem: NSMenuItem! var unreadCount = 0 { @@ -146,6 +147,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, feedIconDownloader = FeedIconDownloader(imageDownloader: imageDownloader, folder: cacheFolder) updateSortMenuItems() + updateGroupByFeedMenuItem() createAndShowMainWindow() if isFirstRun { mainWindowController?.window?.center() @@ -257,6 +259,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, @objc func userDefaultsDidChange(_ note: Notification) { updateSortMenuItems() + updateGroupByFeedMenuItem() refreshTimer?.update() updateDockBadge() } @@ -507,6 +510,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, AppDefaults.timelineSortDirection = .orderedDescending } + + @IBAction func groupByFeedToggled(_ sender: NSMenuItem) { + AppDefaults.timelineGroupByFeed.toggle() + } + } // MARK: - Debug Menu @@ -544,6 +552,11 @@ private extension AppDelegate { sortByNewestArticleOnTopMenuItem.state = sortByNewestOnTop ? .on : .off sortByOldestArticleOnTopMenuItem.state = sortByNewestOnTop ? .off : .on } + + func updateGroupByFeedMenuItem() { + let groupByFeedEnabled = AppDefaults.timelineGroupByFeed + groupArticlesByFeedMenuItem.state = groupByFeedEnabled ? .on : .off + } } /* diff --git a/Mac/Base.lproj/Main.storyboard b/Mac/Base.lproj/Main.storyboard index 8d270183a..9d5854258 100644 --- a/Mac/Base.lproj/Main.storyboard +++ b/Mac/Base.lproj/Main.storyboard @@ -1,7 +1,8 @@ - + - + + @@ -349,6 +350,12 @@ + + + + + + @@ -581,6 +588,7 @@ + diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift index 54fef9c54..55fcfd0f4 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController.swift @@ -128,6 +128,13 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr } } } + private var groupByFeed = AppDefaults.timelineGroupByFeed { + didSet { + if groupByFeed != oldValue { + groupByFeedDidChange() + } + } + } private var fontSize: FontSize = AppDefaults.timelineFontSize { didSet { if fontSize != oldValue { @@ -553,6 +560,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr self.fontSize = AppDefaults.timelineFontSize self.sortDirection = AppDefaults.timelineSortDirection + self.groupByFeed = AppDefaults.timelineGroupByFeed } @objc func appleInterfaceThemeChanged(_ note: Notification) { @@ -875,7 +883,13 @@ private extension TimelineViewController { } func sortDirectionDidChange() { - + performBlockAndRestoreSelection { + let unsortedArticles = Set(articles) + replaceArticles(with: unsortedArticles) + } + } + + func groupByFeedDidChange() { performBlockAndRestoreSelection { let unsortedArticles = Set(articles) replaceArticles(with: unsortedArticles) @@ -978,7 +992,7 @@ private extension TimelineViewController { } func replaceArticles(with unsortedArticles: Set
) { - let sortedArticles = Array(unsortedArticles).sortedByDate(sortDirection) + let sortedArticles = Array(unsortedArticles).sortedByDate(sortDirection, groupByFeed: groupByFeed) if articles != sortedArticles { articles = sortedArticles }