mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Add filter exceptions so that the correct timeline is always selected regardless of filter state. Issue #1366
This commit is contained in:
@@ -13,8 +13,17 @@ import Account
|
||||
|
||||
final class WebFeedTreeControllerDelegate: TreeControllerDelegate {
|
||||
|
||||
private var filterExceptions = Set<FeedIdentifier>()
|
||||
var isReadFiltered = false
|
||||
|
||||
func addFilterException(_ feedID: FeedIdentifier) {
|
||||
filterExceptions.insert(feedID)
|
||||
}
|
||||
|
||||
func resetFilterExceptions() {
|
||||
filterExceptions = Set<FeedIdentifier>()
|
||||
}
|
||||
|
||||
func treeController(treeController: TreeController, childNodesFor node: Node) -> [Node]? {
|
||||
if node.isRoot {
|
||||
return childNodesForRootNode(node)
|
||||
@@ -50,7 +59,7 @@ private extension WebFeedTreeControllerDelegate {
|
||||
|
||||
func childNodesForSmartFeeds(_ parentNode: Node) -> [Node] {
|
||||
return SmartFeedsController.shared.smartFeeds.compactMap { (feed) -> Node? in
|
||||
if isReadFiltered && feed.unreadCount == 0 {
|
||||
if let feedID = feed.feedID, !filterExceptions.contains(feedID) && isReadFiltered && feed.unreadCount == 0 {
|
||||
return nil
|
||||
}
|
||||
return parentNode.existingOrNewChildNode(with: feed as AnyObject)
|
||||
@@ -63,14 +72,14 @@ private extension WebFeedTreeControllerDelegate {
|
||||
var children = [AnyObject]()
|
||||
|
||||
for webFeed in container.topLevelWebFeeds {
|
||||
if !(isReadFiltered && webFeed.unreadCount == 0) {
|
||||
if let feedID = webFeed.feedID, !(!filterExceptions.contains(feedID) && isReadFiltered && webFeed.unreadCount == 0) {
|
||||
children.append(webFeed)
|
||||
}
|
||||
}
|
||||
|
||||
if let folders = container.folders {
|
||||
for folder in folders {
|
||||
if !(isReadFiltered && folder.unreadCount == 0) {
|
||||
if let feedID = folder.feedID, !(!filterExceptions.contains(feedID) && isReadFiltered && folder.unreadCount == 0) {
|
||||
children.append(folder)
|
||||
}
|
||||
}
|
||||
@@ -129,10 +138,21 @@ private extension WebFeedTreeControllerDelegate {
|
||||
}
|
||||
|
||||
func sortedAccountNodes(_ parent: Node) -> [Node] {
|
||||
|
||||
var accountFilterException: String? = nil
|
||||
switch filterExceptions.first {
|
||||
case .folder(let accountID, _), .webFeed(let accountID, _):
|
||||
accountFilterException = accountID
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
let nodes = AccountManager.shared.sortedActiveAccounts.compactMap { (account) -> Node? in
|
||||
if isReadFiltered && account.unreadCount == 0 {
|
||||
|
||||
if isReadFiltered && account.accountID != accountFilterException && account.unreadCount == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
let accountNode = parent.existingOrNewChildNode(with: account)
|
||||
accountNode.canHaveChildNodes = true
|
||||
accountNode.isGroupItem = true
|
||||
|
||||
@@ -426,6 +426,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
if isReadFeedsFiltered {
|
||||
rebuildBackingStores()
|
||||
}
|
||||
treeControllerDelegate.resetFilterExceptions()
|
||||
}
|
||||
|
||||
@objc func statusesDidChange(_ note: Notification) {
|
||||
@@ -1819,6 +1820,8 @@ private extension SceneCoordinator {
|
||||
return
|
||||
}
|
||||
|
||||
treeControllerDelegate.addFilterException(feedIdentifier)
|
||||
|
||||
switch feedIdentifier {
|
||||
|
||||
case .smartFeed:
|
||||
@@ -1842,6 +1845,9 @@ private extension SceneCoordinator {
|
||||
guard let accountNode = findAccountNode(accountID: accountID), let feedNode = findWebFeedNode(webFeedID: webFeedID, beginningAt: accountNode) else {
|
||||
return
|
||||
}
|
||||
if let folder = feedNode.parent?.representedObject as? Folder, let folderFeedID = folder.feedID {
|
||||
treeControllerDelegate.addFilterException(folderFeedID)
|
||||
}
|
||||
if let feed = feedNode.representedObject as? WebFeed {
|
||||
discloseFeed(feed, animated: false)
|
||||
}
|
||||
@@ -1860,20 +1866,26 @@ private extension SceneCoordinator {
|
||||
return
|
||||
}
|
||||
|
||||
if restoreFeed(userInfo, accountID: accountID, webFeedID: webFeedID, articleID: articleID) {
|
||||
if restoreFeedSelection(userInfo, accountID: accountID, webFeedID: webFeedID, articleID: articleID) {
|
||||
return
|
||||
}
|
||||
|
||||
guard let accountNode = findAccountNode(accountID: accountID, accountName: accountName), let feedNode = findWebFeedNode(webFeedID: webFeedID, beginningAt: accountNode) else {
|
||||
return
|
||||
guard let accountNode = findAccountNode(accountID: accountID, accountName: accountName),
|
||||
let webFeedNode = findWebFeedNode(webFeedID: webFeedID, beginningAt: accountNode),
|
||||
let webFeed = webFeedNode.representedObject as? WebFeed,
|
||||
let webFeedFeedID = webFeed.feedID else {
|
||||
return
|
||||
}
|
||||
|
||||
discloseFeed(feedNode.representedObject as! WebFeed, animated: false) {
|
||||
treeControllerDelegate.addFilterException(webFeedFeedID)
|
||||
addParentFolderToFilterExceptions(webFeedNode)
|
||||
|
||||
discloseFeed(webFeed, animated: false) {
|
||||
self.selectArticleInCurrentFeed(articleID)
|
||||
}
|
||||
}
|
||||
|
||||
func restoreFeed(_ userInfo: [AnyHashable : Any], accountID: String, webFeedID: String, articleID: String) -> Bool {
|
||||
func restoreFeedSelection(_ userInfo: [AnyHashable : Any], accountID: String, webFeedID: String, articleID: String) -> Bool {
|
||||
guard let feedIdentifierUserInfo = userInfo[UserInfoKey.feedIdentifier] as? [AnyHashable : AnyHashable],
|
||||
let feedIdentifier = FeedIdentifier(userInfo: feedIdentifierUserInfo) else {
|
||||
return false
|
||||
@@ -1883,13 +1895,12 @@ private extension SceneCoordinator {
|
||||
|
||||
case .smartFeed:
|
||||
guard let smartFeed = SmartFeedsController.shared.find(by: feedIdentifier) else { return false }
|
||||
if smartFeed.fetchArticles().contains(accountID: accountID, articleID: articleID) {
|
||||
if let indexPath = indexPathFor(smartFeed) {
|
||||
selectFeed(indexPath, animated: false) {
|
||||
self.selectArticleInCurrentFeed(articleID)
|
||||
}
|
||||
return true
|
||||
if let indexPath = indexPathFor(smartFeed) {
|
||||
selectFeed(indexPath, animated: false) {
|
||||
self.selectArticleInCurrentFeed(articleID)
|
||||
}
|
||||
treeControllerDelegate.addFilterException(feedIdentifier)
|
||||
return true
|
||||
}
|
||||
|
||||
case .script:
|
||||
@@ -1897,20 +1908,26 @@ private extension SceneCoordinator {
|
||||
|
||||
case .folder(let accountID, let folderName):
|
||||
guard let accountNode = findAccountNode(accountID: accountID),
|
||||
let folderNode = findFolderNode(folderName: folderName, beginningAt: accountNode),
|
||||
let folderFeed = folderNode.representedObject as? Feed else {
|
||||
let folderNode = findFolderNode(folderName: folderName, beginningAt: accountNode) else {
|
||||
return false
|
||||
}
|
||||
if folderFeed.fetchArticles().contains(accountID: accountID, articleID: articleID) {
|
||||
return selectFeedAndArticle(feedNode: folderNode, articleID: articleID)
|
||||
let found = selectFeedAndArticle(feedNode: folderNode, articleID: articleID)
|
||||
if found {
|
||||
treeControllerDelegate.addFilterException(feedIdentifier)
|
||||
}
|
||||
return found
|
||||
|
||||
case .webFeed:
|
||||
guard let accountNode = findAccountNode(accountID: accountID), let webFeedNode = findWebFeedNode(webFeedID: webFeedID, beginningAt: accountNode) else {
|
||||
return false
|
||||
}
|
||||
return selectFeedAndArticle(feedNode: webFeedNode, articleID: articleID)
|
||||
|
||||
let found = selectFeedAndArticle(feedNode: webFeedNode, articleID: articleID)
|
||||
if found {
|
||||
treeControllerDelegate.addFilterException(feedIdentifier)
|
||||
addParentFolderToFilterExceptions(webFeedNode)
|
||||
}
|
||||
return found
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -1958,4 +1975,10 @@ private extension SceneCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
func addParentFolderToFilterExceptions(_ feedNode: Node) {
|
||||
if let folder = feedNode.parent?.representedObject as? Folder, let folderFeedID = folder.feedID {
|
||||
treeControllerDelegate.addFilterException(folderFeedID)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user