Rename Feed protocol to SidebarItem.

This commit is contained in:
Brent Simmons 2024-02-25 21:14:10 -08:00
parent 8aa2a1109e
commit d5794a7b4e
15 changed files with 49 additions and 49 deletions

View File

@ -197,7 +197,7 @@ public final class AccountManager: UnreadCountProvider {
return nil return nil
} }
public func existingFeed(with feedID: FeedIdentifier) -> Feed? { public func existingFeed(with feedID: FeedIdentifier) -> SidebarItem? {
switch feedID { switch feedID {
case .folder(let accountID, let folderName): case .folder(let accountID, let folderName):
if let account = existingAccount(with: accountID) { if let account = existingAccount(with: accountID) {

View File

@ -10,7 +10,7 @@ import Foundation
import Articles import Articles
import RSCore import RSCore
public final class Folder: Feed, Renamable, Container, Hashable { public final class Folder: SidebarItem, Renamable, Container, Hashable {
public var defaultReadFilterType: ReadFilterType { public var defaultReadFilterType: ReadFilterType {
return .read return .read

View File

@ -1,5 +1,5 @@
// //
// Feed.swift // SidebarItem.swift
// Account // Account
// //
// Created by Maurice Parker on 11/15/19. // Created by Maurice Parker on 11/15/19.
@ -15,14 +15,14 @@ public enum ReadFilterType {
case alwaysRead case alwaysRead
} }
public protocol Feed: FeedIdentifiable, ArticleFetcher, DisplayNameProvider, UnreadCountProvider { public protocol SidebarItem: FeedIdentifiable, ArticleFetcher, DisplayNameProvider, UnreadCountProvider {
var account: Account? { get } var account: Account? { get }
var defaultReadFilterType: ReadFilterType { get } var defaultReadFilterType: ReadFilterType { get }
} }
public extension Feed { public extension SidebarItem {
func readFiltered(readFilterEnabledTable: [FeedIdentifier: Bool]) -> Bool { func readFiltered(readFilterEnabledTable: [FeedIdentifier: Bool]) -> Bool {
guard defaultReadFilterType != .alwaysRead else { guard defaultReadFilterType != .alwaysRead else {

View File

@ -11,7 +11,7 @@ import RSCore
import RSWeb import RSWeb
import Articles import Articles
public final class WebFeed: Feed, Renamable, Hashable { public final class WebFeed: SidebarItem, Renamable, Hashable {
public var defaultReadFilterType: ReadFilterType { public var defaultReadFilterType: ReadFilterType {
return .none return .none

View File

@ -22,7 +22,7 @@ enum SidebarDeleteItemsAlert {
alert.messageText = NSLocalizedString("Delete Folder", comment: "Delete Folder") alert.messageText = NSLocalizedString("Delete Folder", comment: "Delete Folder")
let localizedInformativeText = NSLocalizedString("Are you sure you want to delete the “%@” folder?", comment: "Folder delete text") let localizedInformativeText = NSLocalizedString("Are you sure you want to delete the “%@” folder?", comment: "Folder delete text")
alert.informativeText = NSString.localizedStringWithFormat(localizedInformativeText as NSString, folder.nameForDisplay) as String alert.informativeText = NSString.localizedStringWithFormat(localizedInformativeText as NSString, folder.nameForDisplay) as String
} else if let feed = nodes.first?.representedObject as? Feed { } else if let feed = nodes.first?.representedObject as? SidebarItem {
alert.messageText = NSLocalizedString("Delete Feed", comment: "Delete Feed") alert.messageText = NSLocalizedString("Delete Feed", comment: "Delete Feed")
let localizedInformativeText = NSLocalizedString("Are you sure you want to delete the “%@” feed?", comment: "Feed delete text") let localizedInformativeText = NSLocalizedString("Are you sure you want to delete the “%@” feed?", comment: "Feed delete text")
alert.informativeText = NSString.localizedStringWithFormat(localizedInformativeText as NSString, feed.nameForDisplay) as String alert.informativeText = NSString.localizedStringWithFormat(localizedInformativeText as NSString, feed.nameForDisplay) as String

View File

@ -447,7 +447,7 @@ protocol SidebarDelegate: AnyObject {
// MARK: - API // MARK: - API
func selectFeed(_ feed: Feed) { func selectFeed(_ feed: SidebarItem) {
if isReadFiltered, let feedID = feed.feedID { if isReadFiltered, let feedID = feed.feedID {
self.treeControllerDelegate.addFilterException(feedID) self.treeControllerDelegate.addFilterException(feedID)
@ -468,7 +468,7 @@ protocol SidebarDelegate: AnyObject {
func deepLinkRevealAndSelect(for userInfo: [AnyHashable : Any]) { func deepLinkRevealAndSelect(for userInfo: [AnyHashable : Any]) {
guard let accountNode = findAccountNode(userInfo), guard let accountNode = findAccountNode(userInfo),
let feedNode = findFeedNode(userInfo, beginningAt: accountNode), let feedNode = findFeedNode(userInfo, beginningAt: accountNode),
let feed = feedNode.representedObject as? Feed else { let feed = feedNode.representedObject as? SidebarItem else {
return return
} }
selectFeed(feed) selectFeed(feed)
@ -513,8 +513,8 @@ private extension SidebarViewController {
return [Node]() return [Node]()
} }
var selectedFeeds: [Feed] { var selectedFeeds: [SidebarItem] {
selectedNodes.compactMap { $0.representedObject as? Feed } selectedNodes.compactMap { $0.representedObject as? SidebarItem }
} }
var singleSelectedNode: Node? { var singleSelectedNode: Node? {
@ -535,7 +535,7 @@ private extension SidebarViewController {
selectedFeeds.forEach { addToFilterExeptionsIfNecessary($0) } selectedFeeds.forEach { addToFilterExeptionsIfNecessary($0) }
} }
func addToFilterExeptionsIfNecessary(_ feed: Feed?) { func addToFilterExeptionsIfNecessary(_ feed: SidebarItem?) {
if isReadFiltered, let feedID = feed?.feedID { if isReadFiltered, let feedID = feed?.feedID {
if feed is PseudoFeed { if feed is PseudoFeed {
treeControllerDelegate.addFilterException(feedID) treeControllerDelegate.addFilterException(feedID)
@ -552,7 +552,7 @@ private extension SidebarViewController {
} }
} }
func addParentFolderToFilterExceptions(_ feed: Feed) { func addParentFolderToFilterExceptions(_ feed: SidebarItem) {
guard let node = treeController.rootNode.descendantNodeRepresentingObject(feed as AnyObject), guard let node = treeController.rootNode.descendantNodeRepresentingObject(feed as AnyObject),
let folder = node.parent?.representedObject as? Folder, let folder = node.parent?.representedObject as? Folder,
let folderFeedID = folder.feedID else { let folderFeedID = folder.feedID else {
@ -613,7 +613,7 @@ private extension SidebarViewController {
} }
func addTreeControllerToFilterExceptionsVisitor(node: Node) { func addTreeControllerToFilterExceptionsVisitor(node: Node) {
if let feed = node.representedObject as? Feed, let feedID = feed.feedID { if let feed = node.representedObject as? SidebarItem, let feedID = feed.feedID {
treeControllerDelegate.addFilterException(feedID) treeControllerDelegate.addFilterException(feedID)
} }
} }

View File

@ -30,7 +30,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
private var readFilterEnabledTable = [FeedIdentifier: Bool]() private var readFilterEnabledTable = [FeedIdentifier: Bool]()
var isReadFiltered: Bool? { var isReadFiltered: Bool? {
guard representedObjects?.count == 1, let timelineFeed = representedObjects?.first as? Feed else { guard representedObjects?.count == 1, let timelineFeed = representedObjects?.first as? SidebarItem else {
return nil return nil
} }
guard timelineFeed.defaultReadFilterType != .alwaysRead else { guard timelineFeed.defaultReadFilterType != .alwaysRead else {
@ -46,7 +46,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
var isCleanUpAvailable: Bool { var isCleanUpAvailable: Bool {
let isEligibleForCleanUp: Bool? let isEligibleForCleanUp: Bool?
if representedObjects?.count == 1, let timelineFeed = representedObjects?.first as? Feed, timelineFeed.defaultReadFilterType == .alwaysRead { if representedObjects?.count == 1, let timelineFeed = representedObjects?.first as? SidebarItem, timelineFeed.defaultReadFilterType == .alwaysRead {
isEligibleForCleanUp = true isEligibleForCleanUp = true
} else { } else {
isEligibleForCleanUp = isReadFiltered isEligibleForCleanUp = isReadFiltered
@ -263,7 +263,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
} }
func toggleReadFilter() { func toggleReadFilter() {
guard let filter = isReadFiltered, let feedID = (representedObjects?.first as? Feed)?.feedID else { return } guard let filter = isReadFiltered, let feedID = (representedObjects?.first as? SidebarItem)?.feedID else { return }
readFilterEnabledTable[feedID] = !filter readFilterEnabledTable[feedID] = !filter
delegate?.timelineInvalidatedRestorationState(self) delegate?.timelineInvalidatedRestorationState(self)
fetchAndReplacePreservingSelection() fetchAndReplacePreservingSelection()
@ -1151,7 +1151,7 @@ private extension TimelineViewController {
var fetchedArticles = Set<Article>() var fetchedArticles = Set<Article>()
for fetchers in fetchers { for fetchers in fetchers {
if (fetchers as? Feed)?.readFiltered(readFilterEnabledTable: readFilterEnabledTable) ?? true { if (fetchers as? SidebarItem)?.readFiltered(readFilterEnabledTable: readFilterEnabledTable) ?? true {
if let articles = try? fetchers.fetchUnreadArticles() { if let articles = try? fetchers.fetchUnreadArticles() {
fetchedArticles.formUnion(articles) fetchedArticles.formUnion(articles)
} }

View File

@ -49,7 +49,7 @@ class ActivityManager {
invalidateNextUnread() invalidateNextUnread()
} }
func selecting(feed: Feed) { func selecting(feed: SidebarItem) {
invalidateCurrentActivities() invalidateCurrentActivities()
selectingActivity = makeSelectFeedActivity(feed: feed) selectingActivity = makeSelectFeedActivity(feed: feed)
@ -87,7 +87,7 @@ class ActivityManager {
nextUnreadActivity = nil nextUnreadActivity = nil
} }
func reading(feed: Feed?, article: Article?) { func reading(feed: SidebarItem?, article: Article?) {
invalidateReading() invalidateReading()
invalidateNextUnread() invalidateNextUnread()
@ -162,7 +162,7 @@ class ActivityManager {
private extension ActivityManager { private extension ActivityManager {
func makeSelectFeedActivity(feed: Feed) -> NSUserActivity { func makeSelectFeedActivity(feed: SidebarItem) -> NSUserActivity {
let activity = NSUserActivity(activityType: ActivityType.selectFeed.rawValue) let activity = NSUserActivity(activityType: ActivityType.selectFeed.rawValue)
let localizedText = NSLocalizedString("See articles in “%@”", comment: "See articles in Folder") let localizedText = NSLocalizedString("See articles in “%@”", comment: "See articles in Folder")
@ -187,7 +187,7 @@ private extension ActivityManager {
return activity return activity
} }
func makeReadArticleActivity(feed: Feed?, article: Article) -> NSUserActivity { func makeReadArticleActivity(feed: SidebarItem?, article: Article) -> NSUserActivity {
let activity = NSUserActivity(activityType: ActivityType.readArticle.rawValue) let activity = NSUserActivity(activityType: ActivityType.readArticle.rawValue)
activity.title = ArticleStringFormatter.truncatedTitle(article) activity.title = ArticleStringFormatter.truncatedTitle(article)

View File

@ -30,7 +30,7 @@ class IconImageCache {
return nil return nil
} }
func imageForFeed(_ feed: Feed) -> IconImage? { func imageForFeed(_ feed: SidebarItem) -> IconImage? {
guard let feedID = feed.feedID else { guard let feedID = feed.feedID else {
return nil return nil
} }

View File

@ -13,7 +13,7 @@ import Articles
import Account import Account
import RSCore import RSCore
protocol PseudoFeed: AnyObject, Feed, SmallIconProvider, PasteboardWriterOwner { protocol PseudoFeed: AnyObject, SidebarItem, SmallIconProvider, PasteboardWriterOwner {
} }
@ -24,7 +24,7 @@ import Articles
import Account import Account
import RSCore import RSCore
protocol PseudoFeed: AnyObject, Feed, SmallIconProvider { protocol PseudoFeed: AnyObject, SidebarItem, SmallIconProvider {
} }

View File

@ -19,7 +19,7 @@ final class SmartFeedsController: DisplayNameProvider, ContainerIdentifiable {
public static let shared = SmartFeedsController() public static let shared = SmartFeedsController()
let nameForDisplay = NSLocalizedString("Smart Feeds", comment: "Smart Feeds group title") let nameForDisplay = NSLocalizedString("Smart Feeds", comment: "Smart Feeds group title")
var smartFeeds = [Feed]() var smartFeeds = [SidebarItem]()
let todayFeed = SmartFeed(delegate: TodayFeedDelegate()) let todayFeed = SmartFeed(delegate: TodayFeedDelegate())
let unreadFeed = UnreadFeed() let unreadFeed = UnreadFeed()
let starredFeed = SmartFeed(delegate: StarredFeedDelegate()) let starredFeed = SmartFeed(delegate: StarredFeedDelegate())

View File

@ -81,7 +81,7 @@ final class FetchRequestOperation {
} }
for fetcher in fetchers { for fetcher in fetchers {
if (fetcher as? Feed)?.readFiltered(readFilterEnabledTable: readFilterEnabledTable) ?? true { if (fetcher as? SidebarItem)?.readFiltered(readFilterEnabledTable: readFilterEnabledTable) ?? true {
fetcher.fetchUnreadArticlesAsync { articleSetResult in fetcher.fetchUnreadArticlesAsync { articleSetResult in
let articles = (try? articleSetResult.get()) ?? Set<Article>() let articles = (try? articleSetResult.get()) ?? Set<Article>()
process(articles) process(articles)

View File

@ -22,7 +22,7 @@ extension MasterFeedViewController: UITableViewDropDelegate {
return UITableViewDropProposal(operation: .forbidden) return UITableViewDropProposal(operation: .forbidden)
} }
guard let destFeed = coordinator.nodeFor(destIndexPath)?.representedObject as? Feed, guard let destFeed = coordinator.nodeFor(destIndexPath)?.representedObject as? SidebarItem,
let destAccount = destFeed.account, let destAccount = destFeed.account,
let destCell = tableView.cellForRow(at: destIndexPath) else { let destCell = tableView.cellForRow(at: destIndexPath) else {
return UITableViewDropProposal(operation: .forbidden) return UITableViewDropProposal(operation: .forbidden)

View File

@ -320,7 +320,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
} }
override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? Feed else { guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? SidebarItem else {
return nil return nil
} }
if feed is WebFeed { if feed is WebFeed {
@ -781,7 +781,7 @@ private extension MasterFeedViewController {
cell.isDisclosureAvailable = false cell.isDisclosureAvailable = false
} }
if let feed = node.representedObject as? Feed { if let feed = node.representedObject as? SidebarItem {
cell.name = feed.nameForDisplay cell.name = feed.nameForDisplay
cell.unreadCount = feed.unreadCount cell.unreadCount = feed.unreadCount
} }
@ -798,7 +798,7 @@ private extension MasterFeedViewController {
} }
func configureIcon(_ cell: MasterFeedTableViewCell, _ indexPath: IndexPath) { func configureIcon(_ cell: MasterFeedTableViewCell, _ indexPath: IndexPath) {
guard let node = coordinator.nodeFor(indexPath), let feed = node.representedObject as? Feed, let feedID = feed.feedID else { guard let node = coordinator.nodeFor(indexPath), let feed = node.representedObject as? SidebarItem, let feedID = feed.feedID else {
return return
} }
cell.iconImage = IconImageCache.shared.imageFor(feedID) cell.iconImage = IconImageCache.shared.imageFor(feedID)
@ -818,8 +818,8 @@ private extension MasterFeedViewController {
func applyToCellsForRepresentedObject(_ representedObject: AnyObject, _ completion: (MasterFeedTableViewCell, IndexPath) -> Void) { func applyToCellsForRepresentedObject(_ representedObject: AnyObject, _ completion: (MasterFeedTableViewCell, IndexPath) -> Void) {
applyToAvailableCells { (cell, indexPath) in applyToAvailableCells { (cell, indexPath) in
if let node = coordinator.nodeFor(indexPath), if let node = coordinator.nodeFor(indexPath),
let representedFeed = representedObject as? Feed, let representedFeed = representedObject as? SidebarItem,
let candidate = node.representedObject as? Feed, let candidate = node.representedObject as? SidebarItem,
representedFeed.feedID == candidate.feedID { representedFeed.feedID == candidate.feedID {
completion(cell, indexPath) completion(cell, indexPath)
} }
@ -1123,7 +1123,7 @@ private extension MasterFeedViewController {
} }
func markAllAsReadAction(indexPath: IndexPath) -> UIAction? { func markAllAsReadAction(indexPath: IndexPath) -> UIAction? {
guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? Feed, guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? SidebarItem,
let contentView = self.tableView.cellForRow(at: indexPath)?.contentView, let contentView = self.tableView.cellForRow(at: indexPath)?.contentView,
feed.unreadCount > 0 else { feed.unreadCount > 0 else {
return nil return nil
@ -1165,7 +1165,7 @@ private extension MasterFeedViewController {
func rename(indexPath: IndexPath) { func rename(indexPath: IndexPath) {
guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? Feed else { return } guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? SidebarItem else { return }
let formatString = NSLocalizedString("Rename “%@”", comment: "Rename feed") let formatString = NSLocalizedString("Rename “%@”", comment: "Rename feed")
let title = NSString.localizedStringWithFormat(formatString as NSString, feed.nameForDisplay) as String let title = NSString.localizedStringWithFormat(formatString as NSString, feed.nameForDisplay) as String
@ -1219,7 +1219,7 @@ private extension MasterFeedViewController {
} }
func delete(indexPath: IndexPath) { func delete(indexPath: IndexPath) {
guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? Feed else { return } guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? SidebarItem else { return }
let title: String let title: String
let message: String let message: String

View File

@ -37,7 +37,7 @@ struct FeedNode: Hashable {
init(_ node: Node) { init(_ node: Node) {
self.node = node self.node = node
self.feedID = (node.representedObject as! Feed).feedID! self.feedID = (node.representedObject as! SidebarItem).feedID!
} }
func hash(into hasher: inout Hasher) { func hash(into hasher: inout Hasher) {
@ -91,7 +91,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
private var readFilterEnabledTable = [FeedIdentifier: Bool]() private var readFilterEnabledTable = [FeedIdentifier: Bool]()
private var shadowTable = [(sectionID: String, feedNodes: [FeedNode])]() private var shadowTable = [(sectionID: String, feedNodes: [FeedNode])]()
private(set) var preSearchTimelineFeed: Feed? private(set) var preSearchTimelineFeed: SidebarItem?
private var lastSearchString = "" private var lastSearchString = ""
private var lastSearchScope: SearchScope? = nil private var lastSearchScope: SearchScope? = nil
private var isSearching: Bool = false private var isSearching: Bool = false
@ -175,7 +175,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
} }
private var exceptionArticleFetcher: ArticleFetcher? private var exceptionArticleFetcher: ArticleFetcher?
private(set) var timelineFeed: Feed? private(set) var timelineFeed: SidebarItem?
var timelineMiddleIndexPath: IndexPath? var timelineMiddleIndexPath: IndexPath?
@ -632,7 +632,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
func nodeFor(feedID: FeedIdentifier) -> Node? { func nodeFor(feedID: FeedIdentifier) -> Node? {
return treeController.rootNode.descendantNode(where: { node in return treeController.rootNode.descendantNode(where: { node in
if let feed = node.representedObject as? Feed { if let feed = node.representedObject as? SidebarItem {
return feed.feedID == feedID return feed.feedID == feedID
} else { } else {
return false return false
@ -766,7 +766,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
return indexPathFor(node) return indexPathFor(node)
} }
func selectFeed(_ feed: Feed?, animations: Animations = [], deselectArticle: Bool = true, completion: (() -> Void)? = nil) { func selectFeed(_ feed: SidebarItem?, animations: Animations = [], deselectArticle: Bool = true, completion: (() -> Void)? = nil) {
let indexPath: IndexPath? = { let indexPath: IndexPath? = {
if let feed = feed, let indexPath = indexPathFor(feed as AnyObject) { if let feed = feed, let indexPath = indexPathFor(feed as AnyObject) {
return indexPath return indexPath
@ -790,7 +790,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
selectArticle(nil) selectArticle(nil)
} }
if let ip = indexPath, let node = nodeFor(ip), let feed = node.representedObject as? Feed { if let ip = indexPath, let node = nodeFor(ip), let feed = node.representedObject as? SidebarItem {
self.activityManager.selecting(feed: feed) self.activityManager.selecting(feed: feed)
self.installTimelineControllerIfNecessary(animated: animations.contains(.navigation)) self.installTimelineControllerIfNecessary(animated: animations.contains(.navigation))
@ -1439,7 +1439,7 @@ private extension SceneCoordinator {
articleDictionaryNeedsUpdate = false articleDictionaryNeedsUpdate = false
} }
func ensureFeedIsAvailableToSelect(_ feed: Feed, completion: @escaping () -> Void) { func ensureFeedIsAvailableToSelect(_ feed: SidebarItem, completion: @escaping () -> Void) {
addToFilterExeptionsIfNecessary(feed) addToFilterExeptionsIfNecessary(feed)
addShadowTableToFilterExceptions() addShadowTableToFilterExceptions()
@ -1449,7 +1449,7 @@ private extension SceneCoordinator {
}) })
} }
func addToFilterExeptionsIfNecessary(_ feed: Feed?) { func addToFilterExeptionsIfNecessary(_ feed: SidebarItem?) {
if isReadFeedsFiltered, let feedID = feed?.feedID { if isReadFeedsFiltered, let feedID = feed?.feedID {
if feed is SmartFeed { if feed is SmartFeed {
treeControllerDelegate.addFilterException(feedID) treeControllerDelegate.addFilterException(feedID)
@ -1466,7 +1466,7 @@ private extension SceneCoordinator {
} }
} }
func addParentFolderToFilterExceptions(_ feed: Feed) { func addParentFolderToFilterExceptions(_ feed: SidebarItem) {
guard let node = treeController.rootNode.descendantNodeRepresentingObject(feed as AnyObject), guard let node = treeController.rootNode.descendantNodeRepresentingObject(feed as AnyObject),
let folder = node.parent?.representedObject as? Folder, let folder = node.parent?.representedObject as? Folder,
let folderFeedID = folder.feedID else { let folderFeedID = folder.feedID else {
@ -1479,7 +1479,7 @@ private extension SceneCoordinator {
func addShadowTableToFilterExceptions() { func addShadowTableToFilterExceptions() {
for section in shadowTable { for section in shadowTable {
for feedNode in section.feedNodes { for feedNode in section.feedNodes {
if let feed = feedNode.node.representedObject as? Feed, let feedID = feed.feedID { if let feed = feedNode.node.representedObject as? SidebarItem, let feedID = feed.feedID {
treeControllerDelegate.addFilterException(feedID) treeControllerDelegate.addFilterException(feedID)
} }
} }
@ -1595,10 +1595,10 @@ private extension SceneCoordinator {
return ShadowTableChanges(deletes: deletes, inserts: inserts, moves: moves, rowChanges: changes) return ShadowTableChanges(deletes: deletes, inserts: inserts, moves: moves, rowChanges: changes)
} }
func shadowTableContains(_ feed: Feed) -> Bool { func shadowTableContains(_ feed: SidebarItem) -> Bool {
for section in shadowTable { for section in shadowTable {
for feedNode in section.feedNodes { for feedNode in section.feedNodes {
if let nodeFeed = feedNode.node.representedObject as? Feed, nodeFeed.feedID == feed.feedID { if let nodeFeed = feedNode.node.representedObject as? SidebarItem, nodeFeed.feedID == feed.feedID {
return true return true
} }
} }
@ -1619,7 +1619,7 @@ private extension SceneCoordinator {
return indexPathFor(node) return indexPathFor(node)
} }
func setTimelineFeed(_ feed: Feed?, animated: Bool, completion: (() -> Void)? = nil) { func setTimelineFeed(_ feed: SidebarItem?, animated: Bool, completion: (() -> Void)? = nil) {
timelineFeed = feed timelineFeed = feed
fetchAndReplaceArticlesAsync(animated: animated) { fetchAndReplaceArticlesAsync(animated: animated) {