diff --git a/Mac/AppDefaults.swift b/Mac/AppDefaults.swift
index 51985e00da..bc405c6f33 100644
--- a/Mac/AppDefaults.swift
+++ b/Mac/AppDefaults.swift
@@ -43,6 +43,8 @@ final class AppDefaults: Sendable {
static let defaultBrowserID = "defaultBrowserID"
static let currentThemeName = "currentThemeName"
static let articleContentJavascriptEnabled = "articleContentJavascriptEnabled"
+ static let sidebarSortType = "sidebarSortType"
+ static let sidebarSortAscending = "sidebarSortAscending"
// Hidden prefs
static let showDebugMenu = "ShowDebugMenu"
@@ -319,6 +321,36 @@ final class AppDefaults: Sendable {
}
}
+ var sidebarSortType: SidebarSortType {
+ get {
+ let rawValue = UserDefaults.standard.integer(forKey: Key.sidebarSortType)
+ return SidebarSortType(rawValue: rawValue) ?? .alphabetically
+ }
+ set {
+ guard newValue != sidebarSortType else {
+ return
+ }
+ UserDefaults.standard.set(newValue.rawValue, forKey: Key.sidebarSortType)
+ NotificationCenter.default.post(name: .SidebarSortTypeDidChange, object: nil)
+ }
+ }
+
+ var sidebarSortAscending: Bool {
+ get {
+ if UserDefaults.standard.object(forKey: Key.sidebarSortAscending) == nil {
+ return true
+ }
+ return UserDefaults.standard.bool(forKey: Key.sidebarSortAscending)
+ }
+ set {
+ guard newValue != sidebarSortAscending else {
+ return
+ }
+ UserDefaults.standard.set(newValue, forKey: Key.sidebarSortAscending)
+ NotificationCenter.default.post(name: .SidebarSortTypeDidChange, object: nil)
+ }
+ }
+
init() {
// Migrate every-10-minute refresh interval to 30 minutes.
let rawValue = UserDefaults.standard.integer(forKey: Key.refreshInterval)
@@ -344,7 +376,9 @@ final class AppDefaults: Sendable {
Key.refreshInterval: RefreshInterval.every2Hours.rawValue,
Key.showDebugMenu: showDebugMenu,
Key.currentThemeName: Self.defaultThemeName,
- Key.articleContentJavascriptEnabled: true
+ Key.articleContentJavascriptEnabled: true,
+ Key.sidebarSortType: SidebarSortType.alphabetically.rawValue,
+ Key.sidebarSortAscending: true
]
UserDefaults.standard.register(defaults: defaults)
diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift
index 54aa5eb75c..9f819c00b8 100644
--- a/Mac/AppDelegate.swift
+++ b/Mac/AppDelegate.swift
@@ -52,6 +52,10 @@ let appName = "NetNewsWire"
@IBOutlet var sortByNewestArticleOnTopMenuItem: NSMenuItem!
@IBOutlet var groupArticlesByFeedMenuItem: NSMenuItem!
@IBOutlet var checkForUpdatesMenuItem: NSMenuItem!
+ @IBOutlet var sortFeedsByNameMenuItem: NSMenuItem!
+ @IBOutlet var sortFeedsByUnreadCountMenuItem: NSMenuItem!
+ @IBOutlet var sortFeedsAscendingMenuItem: NSMenuItem!
+ @IBOutlet var sortFeedsDescendingMenuItem: NSMenuItem!
var unreadCount = 0 {
didSet {
@@ -191,6 +195,7 @@ let appName = "NetNewsWire"
updateSortMenuItems()
updateGroupByFeedMenuItem()
+ updateSortFeedsMenuItems()
if mainWindowController == nil {
let mainWindowController = createAndShowMainWindow()
@@ -371,6 +376,7 @@ let appName = "NetNewsWire"
func userDefaultsDidChange() {
updateSortMenuItems()
updateGroupByFeedMenuItem()
+ updateSortFeedsMenuItems()
if lastRefreshInterval != AppDefaults.shared.refreshInterval {
refreshTimer?.update()
@@ -465,6 +471,11 @@ let appName = "NetNewsWire"
return mainWindowController?.isOpen ?? false
}
+ if item.action == #selector(sortFeedsByName(_:)) || item.action == #selector(sortFeedsByUnreadCount(_:)) ||
+ item.action == #selector(sortFeedsAscending(_:)) || item.action == #selector(sortFeedsDescending(_:)) {
+ return mainWindowController?.isOpen ?? false
+ }
+
if item.action == #selector(showAddFeedWindow(_:)) || item.action == #selector(showAddFolderWindow(_:)) {
return !isDisplayingSheet && !AccountManager.shared.activeAccounts.isEmpty
}
@@ -703,6 +714,22 @@ let appName = "NetNewsWire"
AppDefaults.shared.timelineGroupByFeed.toggle()
}
+ @IBAction func sortFeedsByName(_ sender: Any?) {
+ AppDefaults.shared.sidebarSortType = .alphabetically
+ }
+
+ @IBAction func sortFeedsByUnreadCount(_ sender: Any?) {
+ AppDefaults.shared.sidebarSortType = .byUnreadCount
+ }
+
+ @IBAction func sortFeedsAscending(_ sender: Any?) {
+ AppDefaults.shared.sidebarSortAscending = true
+ }
+
+ @IBAction func sortFeedsDescending(_ sender: Any?) {
+ AppDefaults.shared.sidebarSortAscending = false
+ }
+
@IBAction func checkForUpdates(_ sender: Any?) {
softwareUpdater?.checkForUpdates()
}
@@ -835,6 +862,16 @@ extension AppDelegate {
sortByOldestArticleOnTopMenuItem.state = sortByNewestOnTop ? .off : .on
}
+ @MainActor func updateSortFeedsMenuItems() {
+ let sortType = AppDefaults.shared.sidebarSortType
+ sortFeedsByNameMenuItem.state = sortType == .alphabetically ? .on : .off
+ sortFeedsByUnreadCountMenuItem.state = sortType == .byUnreadCount ? .on : .off
+
+ let ascending = AppDefaults.shared.sidebarSortAscending
+ sortFeedsAscendingMenuItem.state = ascending ? .on : .off
+ sortFeedsDescendingMenuItem.state = ascending ? .off : .on
+ }
+
@MainActor func updateGroupByFeedMenuItem() {
let groupByFeedEnabled = AppDefaults.shared.timelineGroupByFeed
groupArticlesByFeedMenuItem.state = groupByFeedEnabled ? .on : .off
diff --git a/Mac/Base.lproj/Main.storyboard b/Mac/Base.lproj/Main.storyboard
index 6edf58fe28..5eddb7b0f8 100644
--- a/Mac/Base.lproj/Main.storyboard
+++ b/Mac/Base.lproj/Main.storyboard
@@ -367,6 +367,38 @@
+