Add article exception fetcher to always restore article to timeline regardless of timeline state.

This commit is contained in:
Maurice Parker 2019-11-29 14:31:15 -06:00
parent d62ff04c64
commit 7d39933ba4
3 changed files with 58 additions and 5 deletions

View File

@ -29,6 +29,7 @@
5133230C2281088A00C30F19 /* subscriptions_add.json in Resources */ = {isa = PBXBuildFile; fileRef = 5133230B2281088A00C30F19 /* subscriptions_add.json */; };
5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA48227B497600D19003 /* FeedbinAPICaller.swift */; };
5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */; };
514BF5202391B0DB00902FE8 /* SingleArticleFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514BF51F2391B0DB00902FE8 /* SingleArticleFetcher.swift */; };
5154367B228EEB28005E1CDF /* FeedbinImportResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */; };
515E4EB52324FF8C0057B0E7 /* CredentialsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515E4EB22324FF8C0057B0E7 /* CredentialsManager.swift */; };
515E4EB62324FF8C0057B0E7 /* URLRequest+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515E4EB32324FF8C0057B0E7 /* URLRequest+RSWeb.swift */; };
@ -242,6 +243,7 @@
5133230B2281088A00C30F19 /* subscriptions_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_add.json; sourceTree = "<group>"; };
5144EA48227B497600D19003 /* FeedbinAPICaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAPICaller.swift; sourceTree = "<group>"; };
5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAccountDelegate.swift; sourceTree = "<group>"; };
514BF51F2391B0DB00902FE8 /* SingleArticleFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleArticleFetcher.swift; sourceTree = "<group>"; };
5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinImportResult.swift; sourceTree = "<group>"; };
515E4EB22324FF8C0057B0E7 /* CredentialsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CredentialsManager.swift; sourceTree = "<group>"; };
515E4EB32324FF8C0057B0E7 /* URLRequest+RSWeb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URLRequest+RSWeb.swift"; sourceTree = "<group>"; };
@ -575,6 +577,7 @@
84AF4EA3222CFDD100F6A800 /* AccountMetadata.swift */,
510BD110232C3801002692E4 /* AccountMetadataFile.swift */,
84F73CF0202788D80000BCEF /* ArticleFetcher.swift */,
514BF51F2391B0DB00902FE8 /* SingleArticleFetcher.swift */,
84C365491F899F3B001EC85C /* CombinedRefreshProgress.swift */,
8419740D1F6DD25F006346C4 /* Container.swift */,
51BFDECD238B508D00216323 /* ContainerIdentifier.swift */,
@ -963,6 +966,7 @@
9EEAE071235D019B00E3FEE4 /* FeedlyGetStreamContentsService.swift in Sources */,
9E7299D9235062A200DAEFB7 /* FeedlyResourceProviding.swift in Sources */,
9E672394236F7CA0000BE141 /* FeedlyRefreshAccessTokenOperation.swift in Sources */,
514BF5202391B0DB00902FE8 /* SingleArticleFetcher.swift in Sources */,
9EC688EC232C583300A8D0A2 /* FeedlyAccountDelegate+OAuth.swift in Sources */,
8469F81C1F6DD15E0084783E /* Account.swift in Sources */,
9EAEC60E2332FEC20085D7C9 /* FeedlyFeed.swift in Sources */,

View File

@ -0,0 +1,38 @@
//
// SingleArticleFetcher.swift
// Account
//
// Created by Maurice Parker on 11/29/19.
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import Articles
public struct SingleArticleFetcher: ArticleFetcher {
private let account: Account
private let articleID: String
public init(account: Account, articleID: String) {
self.account = account
self.articleID = articleID
}
public func fetchArticles() -> Set<Article> {
return account.fetchArticles(.articleIDs(Set([articleID])))
}
public func fetchArticlesAsync(_ callback: @escaping ArticleSetBlock) {
return account.fetchArticlesAsync(.articleIDs(Set([articleID])), callback)
}
public func fetchUnreadArticles() -> Set<Article> {
return account.fetchArticles(.articleIDs(Set([articleID])))
}
public func fetchUnreadArticlesAsync(_ callback: @escaping ArticleSetBlock) {
return account.fetchArticlesAsync(.articleIDs(Set([articleID])), callback)
}
}

View File

@ -157,6 +157,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
return (timelineFeed as? SmallIconProvider)?.smallIcon
}
private var exceptionArticleFetcher: ArticleFetcher?
private(set) var timelineFeed: Feed?
var timelineMiddleIndexPath: IndexPath?
@ -1596,13 +1597,20 @@ private extension SceneCoordinator {
// To be called when we need to do an entire fetch, but an async delay is okay.
// Example: we have the Today feed selected, and the calendar day just changed.
cancelPendingAsyncFetches()
guard let timelineFetcher = timelineFeed else {
guard let timelineFeed = timelineFeed else {
emptyTheTimeline()
completion()
return
}
fetchUnsortedArticlesAsync(for: [timelineFetcher]) { [weak self] (articles) in
var fetchers = [ArticleFetcher]()
fetchers.append(timelineFeed)
if exceptionArticleFetcher != nil {
fetchers.append(exceptionArticleFetcher!)
exceptionArticleFetcher = nil
}
fetchUnsortedArticlesAsync(for: fetchers) { [weak self] (articles) in
self?.replaceArticles(with: articles, animated: animated)
completion()
}
@ -1862,16 +1870,19 @@ private extension SceneCoordinator {
let accountID = articlePathUserInfo[ArticlePathKey.accountID] as? String,
let accountName = articlePathUserInfo[ArticlePathKey.accountName] as? String,
let webFeedID = articlePathUserInfo[ArticlePathKey.webFeedID] as? String,
let articleID = articlePathUserInfo[ArticlePathKey.articleID] as? String else {
let articleID = articlePathUserInfo[ArticlePathKey.articleID] as? String,
let accountNode = findAccountNode(accountID: accountID, accountName: accountName),
let account = accountNode.representedObject as? Account else {
return
}
exceptionArticleFetcher = SingleArticleFetcher(account: account, articleID: articleID)
if restoreFeedSelection(userInfo, accountID: accountID, webFeedID: webFeedID, articleID: articleID) {
return
}
guard let accountNode = findAccountNode(accountID: accountID, accountName: accountName),
let webFeedNode = findWebFeedNode(webFeedID: webFeedID, beginningAt: accountNode),
guard let webFeedNode = findWebFeedNode(webFeedID: webFeedID, beginningAt: accountNode),
let webFeed = webFeedNode.representedObject as? WebFeed,
let webFeedFeedID = webFeed.feedID else {
return