diff --git a/Shared/SmartFeeds/SmartFeedsController.swift b/Shared/SmartFeeds/SmartFeedsController.swift
index 37a424a17..683495606 100644
--- a/Shared/SmartFeeds/SmartFeedsController.swift
+++ b/Shared/SmartFeeds/SmartFeedsController.swift
@@ -8,13 +8,14 @@
import Foundation
import RSCore
+import Account
final class SmartFeedsController: DisplayNameProvider {
public static let shared = SmartFeedsController()
let nameForDisplay = NSLocalizedString("Smart Feeds", comment: "Smart Feeds group title")
- var smartFeeds = [AnyObject]()
+ var smartFeeds = [Feed]()
let todayFeed = SmartFeed(delegate: TodayFeedDelegate())
let unreadFeed = UnreadFeed()
let starredFeed = SmartFeed(delegate: StarredFeedDelegate())
diff --git a/Shared/Tree/WebFeedTreeControllerDelegate.swift b/Shared/Tree/WebFeedTreeControllerDelegate.swift
index 62409cd14..6fa6fbc8c 100644
--- a/Shared/Tree/WebFeedTreeControllerDelegate.swift
+++ b/Shared/Tree/WebFeedTreeControllerDelegate.swift
@@ -13,8 +13,9 @@ import Account
final class WebFeedTreeControllerDelegate: TreeControllerDelegate {
+ var isUnreadFiltered = false
+
func treeController(treeController: TreeController, childNodesFor node: Node) -> [Node]? {
-
if node.isRoot {
return childNodesForRootNode(node)
}
@@ -32,29 +33,47 @@ final class WebFeedTreeControllerDelegate: TreeControllerDelegate {
private extension WebFeedTreeControllerDelegate {
func childNodesForRootNode(_ rootNode: Node) -> [Node]? {
+ var topLevelNodes = [Node]()
- // The top-level nodes are Smart Feeds and accounts.
+ // Check to see if we should show the SmartFeeds top level by checking the unreadFeed
+ if !(isUnreadFiltered && SmartFeedsController.shared.unreadFeed.unreadCount == 0) {
+ let smartFeedsNode = rootNode.existingOrNewChildNode(with: SmartFeedsController.shared)
+ smartFeedsNode.canHaveChildNodes = true
+ smartFeedsNode.isGroupItem = true
+ topLevelNodes.append(smartFeedsNode)
+ }
- let smartFeedsNode = rootNode.existingOrNewChildNode(with: SmartFeedsController.shared)
- smartFeedsNode.canHaveChildNodes = true
- smartFeedsNode.isGroupItem = true
-
- return [smartFeedsNode] + sortedAccountNodes(rootNode)
+ topLevelNodes.append(contentsOf: sortedAccountNodes(rootNode))
+
+ return topLevelNodes
}
func childNodesForSmartFeeds(_ parentNode: Node) -> [Node] {
-
- return SmartFeedsController.shared.smartFeeds.map { parentNode.existingOrNewChildNode(with: $0) }
+ return SmartFeedsController.shared.smartFeeds.compactMap { (feed) -> Node? in
+ if isUnreadFiltered && feed.unreadCount == 0 {
+ return nil
+ }
+ return parentNode.existingOrNewChildNode(with: feed as AnyObject)
+ }
}
func childNodesForContainerNode(_ containerNode: Node) -> [Node]? {
-
let container = containerNode.representedObject as! Container
var children = [AnyObject]()
- children.append(contentsOf: Array(container.topLevelWebFeeds))
+
+ for webFeed in container.topLevelWebFeeds {
+ if !(isUnreadFiltered && webFeed.unreadCount == 0) {
+ children.append(webFeed)
+ }
+ }
+
if let folders = container.folders {
- children.append(contentsOf: Array(folders))
+ for folder in folders {
+ if !(isUnreadFiltered && folder.unreadCount == 0) {
+ children.append(folder)
+ }
+ }
}
var updatedChildNodes = [Node]()
@@ -77,13 +96,14 @@ private extension WebFeedTreeControllerDelegate {
}
func createNode(representedObject: Any, parent: Node) -> Node? {
-
if let webFeed = representedObject as? WebFeed {
return createNode(webFeed: webFeed, parent: parent)
}
+
if let folder = representedObject as? Folder {
return createNode(folder: folder, parent: parent)
}
+
if let account = representedObject as? Account {
return createNode(account: account, parent: parent)
}
@@ -92,19 +112,16 @@ private extension WebFeedTreeControllerDelegate {
}
func createNode(webFeed: WebFeed, parent: Node) -> Node {
-
return parent.createChildNode(webFeed)
}
func createNode(folder: Folder, parent: Node) -> Node {
-
let node = parent.createChildNode(folder)
node.canHaveChildNodes = true
return node
}
func createNode(account: Account, parent: Node) -> Node {
-
let node = parent.createChildNode(account)
node.canHaveChildNodes = true
node.isGroupItem = true
@@ -112,8 +129,10 @@ private extension WebFeedTreeControllerDelegate {
}
func sortedAccountNodes(_ parent: Node) -> [Node] {
-
- let nodes = AccountManager.shared.sortedActiveAccounts.map { (account) -> Node in
+ let nodes = AccountManager.shared.sortedActiveAccounts.compactMap { (account) -> Node? in
+ if isUnreadFiltered && account.unreadCount == 0 {
+ return nil
+ }
let accountNode = parent.existingOrNewChildNode(with: account)
accountNode.canHaveChildNodes = true
accountNode.isGroupItem = true
@@ -123,7 +142,6 @@ private extension WebFeedTreeControllerDelegate {
}
func nodeInArrayRepresentingObject(_ nodes: [Node], _ representedObject: AnyObject) -> Node? {
-
for oneNode in nodes {
if oneNode.representedObject === representedObject {
return oneNode
diff --git a/iOS/AppAssets.swift b/iOS/AppAssets.swift
index 20993af6f..081725a9a 100644
--- a/iOS/AppAssets.swift
+++ b/iOS/AppAssets.swift
@@ -89,6 +89,14 @@ struct AppAssets {
return RSImage(named: "faviconTemplateImage")!
}()
+ static var filterInactiveImage: UIImage = {
+ UIImage(systemName: "line.horizontal.3.decrease.circle")!
+ }()
+
+ static var filterActiveImage: UIImage = {
+ UIImage(systemName: "line.horizontal.3.decrease.circle.fill")!
+ }()
+
static var fullScreenBackgroundColor: UIColor = {
return UIColor(named: "fullScreenBackgroundColor")!
}()
diff --git a/iOS/Base.lproj/Main.storyboard b/iOS/Base.lproj/Main.storyboard
index dab0d6343..194e60b7b 100644
--- a/iOS/Base.lproj/Main.storyboard
+++ b/iOS/Base.lproj/Main.storyboard
@@ -214,9 +214,17 @@
+
+
+
+
+
+
+
+
@@ -289,6 +297,7 @@
+
diff --git a/iOS/MasterFeed/MasterFeedViewController.swift b/iOS/MasterFeed/MasterFeedViewController.swift
index 2afb785b7..89315194b 100644
--- a/iOS/MasterFeed/MasterFeedViewController.swift
+++ b/iOS/MasterFeed/MasterFeedViewController.swift
@@ -14,6 +14,7 @@ import RSTree
class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
+ @IBOutlet weak var filterButton: UIBarButtonItem!
private var refreshProgressView: RefreshProgressView?
private var addNewItemButton: UIBarButtonItem!
@@ -370,6 +371,16 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
coordinator.showSettings()
}
+ @IBAction func toggleFilter(_ sender: Any) {
+ if coordinator.isUnreadFeedsFiltered {
+ filterButton.image = AppAssets.filterInactiveImage
+ coordinator.showAllFeeds()
+ } else {
+ filterButton.image = AppAssets.filterActiveImage
+ coordinator.hideUnreadFeeds()
+ }
+ }
+
@IBAction func add(_ sender: UIBarButtonItem) {
coordinator.showAdd(.feed)
}
diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift
index 7e89ea43f..78d02adf3 100644
--- a/iOS/SceneCoordinator.swift
+++ b/iOS/SceneCoordinator.swift
@@ -112,6 +112,10 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
return panelMode == .three
}
+ var isUnreadFeedsFiltered: Bool {
+ return treeControllerDelegate.isUnreadFiltered
+ }
+
var rootNode: Node {
return treeController.rootNode
}
@@ -484,6 +488,16 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
}
return 0
}
+
+ func showAllFeeds() {
+ treeControllerDelegate.isUnreadFiltered = false
+ rebuildBackingStores()
+ }
+
+ func hideUnreadFeeds() {
+ treeControllerDelegate.isUnreadFiltered = true
+ rebuildBackingStores()
+ }
func expand(_ node: Node) {
node.isExpanded = true