Add the unread statuses on receipt to CloudKit.

This commit is contained in:
Maurice Parker 2020-04-10 17:23:39 -05:00
parent 983138366f
commit a8dcf3eeee
6 changed files with 59 additions and 28 deletions

View File

@ -715,7 +715,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
webFeedDictionariesNeedUpdate = true
}
func update(_ webFeed: WebFeed, with parsedFeed: ParsedFeed, _ completion: @escaping DatabaseCompletionBlock) {
func update(_ webFeed: WebFeed, with parsedFeed: ParsedFeed, _ completion: @escaping UpdateArticlesCompletionBlock) {
// Used only by an On My Mac or iCloud account.
precondition(Thread.isMainThread)
precondition(type == .onMyMac || type == .cloudKit)
@ -723,14 +723,14 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
webFeed.takeSettings(from: parsedFeed)
let parsedItems = parsedFeed.items
guard !parsedItems.isEmpty else {
completion(nil)
completion(.success(NewAndUpdatedArticles()))
return
}
update(webFeed.webFeedID, with: parsedItems, completion: completion)
}
func update(_ webFeedID: String, with parsedItems: Set<ParsedItem>, completion: @escaping DatabaseCompletionBlock) {
func update(_ webFeedID: String, with parsedItems: Set<ParsedItem>, completion: @escaping UpdateArticlesCompletionBlock) {
// Used only by an On My Mac or iCloud account.
precondition(Thread.isMainThread)
precondition(type == .onMyMac || type == .cloudKit)
@ -739,9 +739,9 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
switch updateArticlesResult {
case .success(let newAndUpdatedArticles):
self.sendNotificationAbout(newAndUpdatedArticles)
completion(nil)
completion(.success(newAndUpdatedArticles))
case .failure(let databaseError):
completion(databaseError)
completion(.failure(databaseError))
}
}
}

View File

@ -13,6 +13,7 @@ import SyncDatabase
import RSCore
import RSParser
import Articles
import ArticlesDatabase
import RSWeb
public enum CloudKitAccountDelegateError: String, Error {
@ -50,7 +51,6 @@ final class CloudKitAccountDelegate: AccountDelegate {
var accountMetadata: AccountMetadata?
var refreshProgress = DownloadProgress(numberOfTasks: 0)
var refreshAllCompletion: ((Result<Void, Error>) -> Void)? = nil
init(dataFolder: String) {
accountZone = CloudKitAccountZone(container: container)
@ -79,13 +79,12 @@ final class CloudKitAccountDelegate: AccountDelegate {
}
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
guard refreshAllCompletion == nil else {
guard refreshProgress.isComplete else {
completion(.success(()))
return
}
refreshAllCompletion = completion
refreshAll(for: account, downloadFeeds: true)
refreshAll(for: account, downloadFeeds: true, completion: completion)
}
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
@ -155,11 +154,10 @@ final class CloudKitAccountDelegate: AccountDelegate {
}
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
guard refreshAllCompletion == nil else {
guard refreshProgress.isComplete else {
completion(.success(()))
return
}
refreshAllCompletion = completion
var fileData: Data?
@ -214,7 +212,7 @@ final class CloudKitAccountDelegate: AccountDelegate {
}
self.accountZone.importOPML(rootExternalID: rootExternalID, items: normalizedItems) { _ in
self.refreshAll(for: account, downloadFeeds: false)
self.refreshAll(for: account, downloadFeeds: false, completion: completion)
}
}
@ -493,7 +491,7 @@ final class CloudKitAccountDelegate: AccountDelegate {
switch result {
case .success(let externalID):
account.externalID = externalID
self.refreshAll(for: account, downloadFeeds: false)
self.refreshAll(for: account, downloadFeeds: false) { _ in }
case .failure(let error):
os_log(.error, log: self.log, "Error adding account container: %@", error.localizedDescription)
}
@ -533,7 +531,7 @@ final class CloudKitAccountDelegate: AccountDelegate {
private extension CloudKitAccountDelegate {
func refreshAll(for account: Account, downloadFeeds: Bool) {
func refreshAll(for account: Account, downloadFeeds: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
let intialWebFeedsCount = downloadFeeds ? account.flattenedWebFeeds().count : 0
refreshProgress.addToNumberOfTasksAndRemaining(3 + intialWebFeedsCount)
@ -541,8 +539,7 @@ private extension CloudKitAccountDelegate {
func fail(_ error: Error) {
self.processAccountError(account, error)
self.refreshProgress.clear()
self.refreshAllCompletion?(.failure(error))
self.refreshAllCompletion = nil
completion(.failure(error))
}
BatchUpdate.shared.start()
@ -569,12 +566,24 @@ private extension CloudKitAccountDelegate {
self.refreshProgress.completeTask()
guard downloadFeeds else {
self.refreshAllCompletion?(.success(()))
self.refreshAllCompletion = nil
completion(.success(()))
return
}
self.refresher?.refreshFeeds(webFeeds)
self.refresher?.refreshFeeds(webFeeds) {
account.metadata.lastArticleFetchEndTime = Date()
self.sendArticleStatus(for: account) { result in
switch result {
case .success:
completion(.success(()))
case .failure(let error):
fail(error)
}
}
}
case .failure(let error):
fail(error)
@ -605,6 +614,15 @@ private extension CloudKitAccountDelegate {
}
extension CloudKitAccountDelegate: LocalAccountRefresherDelegate {
func localAccountRefresher(_ refresher: LocalAccountRefresher, didProcess newAndUpdatedArticles: NewAndUpdatedArticles) {
if let newArticles = newAndUpdatedArticles.newArticles {
let syncStatuses = newArticles.map { article in
return SyncStatus(articleID: article.articleID, key: .read, flag: false)
}
database.insertStatuses(syncStatuses)
}
}
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: WebFeed) {
refreshProgress.completeTask()
@ -612,9 +630,6 @@ extension CloudKitAccountDelegate: LocalAccountRefresherDelegate {
func localAccountRefresherDidFinish(_ refresher: LocalAccountRefresher) {
self.refreshProgress.clear()
account?.metadata.lastArticleFetchEndTime = Date()
refreshAllCompletion?(.success(()))
refreshAllCompletion = nil
}
}

View File

@ -138,9 +138,9 @@ private extension CloudKitArticlesZoneDelegate {
for receivedStarredArticle in receivedStarredArticles {
if let parsedItem = makeParsedItem(receivedStarredArticle) {
group.enter()
self.account?.update(parsedItem.feedURL, with: Set([parsedItem])) { databaseError in
self.account?.update(parsedItem.feedURL, with: Set([parsedItem])) { result in
group.leave()
if let databaseError = databaseError {
if case .failure(let databaseError) = result {
os_log(.error, log: self.log, "Error occurred while storing starred items: %@", databaseError.localizedDescription)
}
}

View File

@ -10,6 +10,7 @@ import Foundation
import RSCore
import RSParser
import Articles
import ArticlesDatabase
import RSWeb
public enum LocalAccountDelegateError: String, Error {
@ -233,6 +234,9 @@ final class LocalAccountDelegate: AccountDelegate {
extension LocalAccountDelegate: LocalAccountRefresherDelegate {
func localAccountRefresher(_ refresher: LocalAccountRefresher, didProcess newAndUpdatedArticles: NewAndUpdatedArticles) {
}
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: WebFeed) {
refreshProgress.completeTask()
}

View File

@ -11,8 +11,10 @@ import RSCore
import RSParser
import RSWeb
import Articles
import ArticlesDatabase
protocol LocalAccountRefresherDelegate {
func localAccountRefresher(_ refresher: LocalAccountRefresher, didProcess: NewAndUpdatedArticles)
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: WebFeed)
func localAccountRefresherDidFinish(_ refresher: LocalAccountRefresher)
}
@ -97,12 +99,12 @@ extension LocalAccountRefresher: DownloadSessionDelegate {
return
}
account.update(feed, with: parsedFeed) { error in
if error == nil {
account.update(feed, with: parsedFeed) { result in
if case .success(let newAndUpdatedArticles) = result {
self.delegate?.localAccountRefresher(self, didProcess: newAndUpdatedArticles)
if let httpResponse = response as? HTTPURLResponse {
feed.conditionalGetInfo = HTTPConditionalGetInfo(urlResponse: httpResponse)
}
feed.contentHash = dataHash
}
completion()
@ -157,9 +159,9 @@ extension LocalAccountRefresher: DownloadSessionDelegate {
}
func downloadSessionDidCompleteDownloadObjects(_ downloadSession: DownloadSession) {
delegate?.localAccountRefresherDidFinish(self)
completions.forEach({ $0() })
completions = [() -> Void]()
delegate?.localAccountRefresherDidFinish(self)
}
}

View File

@ -27,6 +27,16 @@ public typealias SingleUnreadCountCompletionBlock = (SingleUnreadCountResult) ->
public struct NewAndUpdatedArticles {
public let newArticles: Set<Article>?
public let updatedArticles: Set<Article>?
public init() {
self.newArticles = Set<Article>()
self.updatedArticles = Set<Article>()
}
public init(newArticles: Set<Article>?, updatedArticles: Set<Article>?) {
self.newArticles = newArticles
self.updatedArticles = updatedArticles
}
}
public typealias UpdateArticlesResult = Result<NewAndUpdatedArticles, DatabaseError>