diff --git a/Frameworks/Account/Account.swift b/Frameworks/Account/Account.swift index 93ca065f6..12d609314 100644 --- a/Frameworks/Account/Account.swift +++ b/Frameworks/Account/Account.swift @@ -673,8 +673,8 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, database.fetchStarredAndUnreadCount(for: flattenedWebFeeds().webFeedIDs(), callback: callback) } - public func fetchUnreadArticleIDs() -> Set { - return database.fetchUnreadArticleIDs() + public func fetchUnreadArticleIDs(_ callback: @escaping (Set) -> Void) { + return database.fetchUnreadArticleIDsAsync(webFeedIDs: flattenedWebFeeds().webFeedIDs(), callback: callback) } public func fetchStarredArticleIDs() -> Set { diff --git a/Frameworks/Account/FeedWrangler/FeedWranglerAccountDelegate.swift b/Frameworks/Account/FeedWrangler/FeedWranglerAccountDelegate.swift index f0af956f1..ebb98a24c 100644 --- a/Frameworks/Account/FeedWrangler/FeedWranglerAccountDelegate.swift +++ b/Frameworks/Account/FeedWrangler/FeedWranglerAccountDelegate.swift @@ -500,46 +500,46 @@ private extension FeedWranglerAccountDelegate { func syncArticleReadState(_ account: Account, _ unreadFeedItems: [FeedWranglerFeedItem]) { let unreadServerItemIDs = Set(unreadFeedItems.map { String($0.feedItemID) }) - let unreadLocalItemIDs = account.fetchUnreadArticleIDs() - - // unread if unread on server - let unreadDiffItemIDs = unreadServerItemIDs.subtracting(unreadLocalItemIDs) - let unreadFoundArticles = account.fetchArticles(.articleIDs(unreadDiffItemIDs)) - account.update(unreadFoundArticles, statusKey: .read, flag: false) - - let unreadFoundItemIDs = Set(unreadFoundArticles.map { $0.articleID }) - let missingArticleIDs = unreadDiffItemIDs.subtracting(unreadFoundItemIDs) - account.ensureStatuses(missingArticleIDs, true, .read, false) + account.fetchUnreadArticleIDs { unreadLocalItemIDs in + // unread if unread on server + let unreadDiffItemIDs = unreadServerItemIDs.subtracting(unreadLocalItemIDs) + let unreadFoundArticles = account.fetchArticles(.articleIDs(unreadDiffItemIDs)) + account.update(unreadFoundArticles, statusKey: .read, flag: false) - let readItemIDs = unreadLocalItemIDs.subtracting(unreadServerItemIDs) - let readArtices = account.fetchArticles(.articleIDs(readItemIDs)) - account.update(readArtices, statusKey: .read, flag: true) - - let foundReadArticleIDs = Set(readArtices.map { $0.articleID }) - let readMissingIDs = readItemIDs.subtracting(foundReadArticleIDs) - account.ensureStatuses(readMissingIDs, true, .read, true) + let unreadFoundItemIDs = Set(unreadFoundArticles.map { $0.articleID }) + let missingArticleIDs = unreadDiffItemIDs.subtracting(unreadFoundItemIDs) + account.ensureStatuses(missingArticleIDs, true, .read, false) + + let readItemIDs = unreadLocalItemIDs.subtracting(unreadServerItemIDs) + let readArtices = account.fetchArticles(.articleIDs(readItemIDs)) + account.update(readArtices, statusKey: .read, flag: true) + + let foundReadArticleIDs = Set(readArtices.map { $0.articleID }) + let readMissingIDs = readItemIDs.subtracting(foundReadArticleIDs) + account.ensureStatuses(readMissingIDs, true, .read, true) + } } func syncArticleStarredState(_ account: Account, _ unreadFeedItems: [FeedWranglerFeedItem]) { let unreadServerItemIDs = Set(unreadFeedItems.map { String($0.feedItemID) }) - let unreadLocalItemIDs = account.fetchUnreadArticleIDs() - - // starred if start on server - let unreadDiffItemIDs = unreadServerItemIDs.subtracting(unreadLocalItemIDs) - let unreadFoundArticles = account.fetchArticles(.articleIDs(unreadDiffItemIDs)) - account.update(unreadFoundArticles, statusKey: .starred, flag: true) - - let unreadFoundItemIDs = Set(unreadFoundArticles.map { $0.articleID }) - let missingArticleIDs = unreadDiffItemIDs.subtracting(unreadFoundItemIDs) - account.ensureStatuses(missingArticleIDs, true, .starred, true) + account.fetchUnreadArticleIDs { unreadLocalItemIDs in + // starred if start on server + let unreadDiffItemIDs = unreadServerItemIDs.subtracting(unreadLocalItemIDs) + let unreadFoundArticles = account.fetchArticles(.articleIDs(unreadDiffItemIDs)) + account.update(unreadFoundArticles, statusKey: .starred, flag: true) - let readItemIDs = unreadLocalItemIDs.subtracting(unreadServerItemIDs) - let readArtices = account.fetchArticles(.articleIDs(readItemIDs)) - account.update(readArtices, statusKey: .starred, flag: false) - - let foundReadArticleIDs = Set(readArtices.map { $0.articleID }) - let readMissingIDs = readItemIDs.subtracting(foundReadArticleIDs) - account.ensureStatuses(readMissingIDs, true, .starred, false) + let unreadFoundItemIDs = Set(unreadFoundArticles.map { $0.articleID }) + let missingArticleIDs = unreadDiffItemIDs.subtracting(unreadFoundItemIDs) + account.ensureStatuses(missingArticleIDs, true, .starred, true) + + let readItemIDs = unreadLocalItemIDs.subtracting(unreadServerItemIDs) + let readArtices = account.fetchArticles(.articleIDs(readItemIDs)) + account.update(readArtices, statusKey: .starred, flag: false) + + let foundReadArticleIDs = Set(readArtices.map { $0.articleID }) + let readMissingIDs = readItemIDs.subtracting(foundReadArticleIDs) + account.ensureStatuses(readMissingIDs, true, .starred, false) + } } func syncArticleState(_ account: Account, key: ArticleStatus.Key, flag: Bool, serverFeedItems: [FeedWranglerFeedItem]) { diff --git a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift index ac42e7b73..ed730e833 100644 --- a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift @@ -1195,28 +1195,27 @@ private extension FeedbinAccountDelegate { } let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } ) - let currentUnreadArticleIDs = account.fetchUnreadArticleIDs() - - // Mark articles as unread - let deltaUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) - let markUnreadArticles = account.fetchArticles(.articleIDs(deltaUnreadArticleIDs)) - account.update(markUnreadArticles, statusKey: .read, flag: false) + account.fetchUnreadArticleIDs { currentUnreadArticleIDs in + // Mark articles as unread + let deltaUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) + let markUnreadArticles = account.fetchArticles(.articleIDs(deltaUnreadArticleIDs)) + account.update(markUnreadArticles, statusKey: .read, flag: false) - // Save any unread statuses for articles we haven't yet received - let markUnreadArticleIDs = Set(markUnreadArticles.map { $0.articleID }) - let missingUnreadArticleIDs = deltaUnreadArticleIDs.subtracting(markUnreadArticleIDs) - account.ensureStatuses(missingUnreadArticleIDs, true, .read, false) + // Save any unread statuses for articles we haven't yet received + let markUnreadArticleIDs = Set(markUnreadArticles.map { $0.articleID }) + let missingUnreadArticleIDs = deltaUnreadArticleIDs.subtracting(markUnreadArticleIDs) + account.ensureStatuses(missingUnreadArticleIDs, true, .read, false) - // Mark articles as read - let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(feedbinUnreadArticleIDs) - let markReadArticles = account.fetchArticles(.articleIDs(deltaReadArticleIDs)) - account.update(markReadArticles, statusKey: .read, flag: true) - - // Save any read statuses for articles we haven't yet received - let markReadArticleIDs = Set(markReadArticles.map { $0.articleID }) - let missingReadArticleIDs = deltaReadArticleIDs.subtracting(markReadArticleIDs) - account.ensureStatuses(missingReadArticleIDs, true, .read, true) + // Mark articles as read + let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(feedbinUnreadArticleIDs) + let markReadArticles = account.fetchArticles(.articleIDs(deltaReadArticleIDs)) + account.update(markReadArticles, statusKey: .read, flag: true) + // Save any read statuses for articles we haven't yet received + let markReadArticleIDs = Set(markReadArticles.map { $0.articleID }) + let missingReadArticleIDs = deltaReadArticleIDs.subtracting(markReadArticleIDs) + account.ensureStatuses(missingReadArticleIDs, true, .read, true) + } } func syncArticleStarredState(account: Account, articleIDs: [Int]?) { diff --git a/Frameworks/Account/Feedly/Operations/FeedlySetUnreadArticlesOperation.swift b/Frameworks/Account/Feedly/Operations/FeedlySetUnreadArticlesOperation.swift index e48cac533..3e431ea62 100644 --- a/Frameworks/Account/Feedly/Operations/FeedlySetUnreadArticlesOperation.swift +++ b/Frameworks/Account/Feedly/Operations/FeedlySetUnreadArticlesOperation.swift @@ -36,37 +36,37 @@ final class FeedlySetUnreadArticlesOperation: FeedlyOperation { let remoteUnreadArticleIds = allUnreadIdsProvider.entryIds //Set(entries.filter { $0.unread }.map { $0.id }) - let localUnreadArticleIds = account.fetchUnreadArticleIDs() - - // Mark articles as unread - let deltaUnreadArticleIds = remoteUnreadArticleIds.subtracting(localUnreadArticleIds) - let markUnreadArticles = account.fetchArticles(.articleIDs(deltaUnreadArticleIds)) - account.update(markUnreadArticles, statusKey: .read, flag: false) + account.fetchUnreadArticleIDs { localUnreadArticleIds in + // Mark articles as unread + let deltaUnreadArticleIds = remoteUnreadArticleIds.subtracting(localUnreadArticleIds) + let markUnreadArticles = self.account.fetchArticles(.articleIDs(deltaUnreadArticleIds)) + self.account.update(markUnreadArticles, statusKey: .read, flag: false) - // Save any unread statuses for articles we haven't yet received - let markUnreadArticleIDs = Set(markUnreadArticles.map { $0.articleID }) - let missingUnreadArticleIDs = deltaUnreadArticleIds.subtracting(markUnreadArticleIDs) - - group.enter() - account.ensureStatuses(missingUnreadArticleIDs, true, .read, false) { - group.leave() - } + // Save any unread statuses for articles we haven't yet received + let markUnreadArticleIDs = Set(markUnreadArticles.map { $0.articleID }) + let missingUnreadArticleIDs = deltaUnreadArticleIds.subtracting(markUnreadArticleIDs) - // Mark articles as read - let deltaReadArticleIds = localUnreadArticleIds.subtracting(remoteUnreadArticleIds) - let markReadArticles = account.fetchArticles(.articleIDs(deltaReadArticleIds)) - account.update(markReadArticles, statusKey: .read, flag: true) + group.enter() + self.account.ensureStatuses(missingUnreadArticleIDs, true, .read, false) { + group.leave() + } - // Save any read statuses for articles we haven't yet received - let markReadArticleIDs = Set(markReadArticles.map { $0.articleID }) - let missingReadArticleIDs = deltaReadArticleIds.subtracting(markReadArticleIDs) - group.enter() - account.ensureStatuses(missingReadArticleIDs, true, .read, true) { - group.leave() - } - - group.notify(queue: .main) { - self.didFinish() + // Mark articles as read + let deltaReadArticleIds = localUnreadArticleIds.subtracting(remoteUnreadArticleIds) + let markReadArticles = self.account.fetchArticles(.articleIDs(deltaReadArticleIds)) + self.account.update(markReadArticles, statusKey: .read, flag: true) + + // Save any read statuses for articles we haven't yet received + let markReadArticleIDs = Set(markReadArticles.map { $0.articleID }) + let missingReadArticleIDs = deltaReadArticleIds.subtracting(markReadArticleIDs) + group.enter() + self.account.ensureStatuses(missingReadArticleIDs, true, .read, true) { + group.leave() + } + + group.notify(queue: .main) { + self.didFinish() + } } } } diff --git a/Frameworks/Account/ReaderAPI/ReaderAPIAccountDelegate.swift b/Frameworks/Account/ReaderAPI/ReaderAPIAccountDelegate.swift index c47da8f6e..9d138750f 100644 --- a/Frameworks/Account/ReaderAPI/ReaderAPIAccountDelegate.swift +++ b/Frameworks/Account/ReaderAPI/ReaderAPIAccountDelegate.swift @@ -913,28 +913,27 @@ private extension ReaderAPIAccountDelegate { } let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } ) - let currentUnreadArticleIDs = account.fetchUnreadArticleIDs() - - // Mark articles as unread - let deltaUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) - let markUnreadArticles = account.fetchArticles(.articleIDs(deltaUnreadArticleIDs)) - account.update(markUnreadArticles, statusKey: .read, flag: false) + account.fetchUnreadArticleIDs { currentUnreadArticleIDs in + // Mark articles as unread + let deltaUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) + let markUnreadArticles = account.fetchArticles(.articleIDs(deltaUnreadArticleIDs)) + account.update(markUnreadArticles, statusKey: .read, flag: false) - // Save any unread statuses for articles we haven't yet received - let markUnreadArticleIDs = Set(markUnreadArticles.map { $0.articleID }) - let missingUnreadArticleIDs = deltaUnreadArticleIDs.subtracting(markUnreadArticleIDs) - account.ensureStatuses(missingUnreadArticleIDs, true, .read, false) + // Save any unread statuses for articles we haven't yet received + let markUnreadArticleIDs = Set(markUnreadArticles.map { $0.articleID }) + let missingUnreadArticleIDs = deltaUnreadArticleIDs.subtracting(markUnreadArticleIDs) + account.ensureStatuses(missingUnreadArticleIDs, true, .read, false) - // Mark articles as read - let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(feedbinUnreadArticleIDs) - let markReadArticles = account.fetchArticles(.articleIDs(deltaReadArticleIDs)) - account.update(markReadArticles, statusKey: .read, flag: true) - - // Save any read statuses for articles we haven't yet received - let markReadArticleIDs = Set(markReadArticles.map { $0.articleID }) - let missingReadArticleIDs = deltaReadArticleIDs.subtracting(markReadArticleIDs) - account.ensureStatuses(missingReadArticleIDs, true, .read, true) + // Mark articles as read + let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(feedbinUnreadArticleIDs) + let markReadArticles = account.fetchArticles(.articleIDs(deltaReadArticleIDs)) + account.update(markReadArticles, statusKey: .read, flag: true) + // Save any read statuses for articles we haven't yet received + let markReadArticleIDs = Set(markReadArticles.map { $0.articleID }) + let missingReadArticleIDs = deltaReadArticleIDs.subtracting(markReadArticleIDs) + account.ensureStatuses(missingReadArticleIDs, true, .read, true) + } } func syncArticleStarredState(account: Account, articleIDs: [Int]?) { diff --git a/Frameworks/ArticlesDatabase/ArticlesDatabase.swift b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift index 5e785cf95..283fdbcfa 100644 --- a/Frameworks/ArticlesDatabase/ArticlesDatabase.swift +++ b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift @@ -153,9 +153,10 @@ public final class ArticlesDatabase { } // MARK: - Status - - public func fetchUnreadArticleIDs() -> Set { - return articlesTable.fetchUnreadArticleIDs() + + /// Fetch the articleIDs of unread articles for feeds specified by webFeedIDs. + public func fetchUnreadArticleIDsAsync(webFeedIDs: Set, callback: @escaping (Set) -> Void) { + articlesTable.fetchUnreadArticleIDsAsync(webFeedIDs, callback) } public func fetchStarredArticleIDs() -> Set { diff --git a/Frameworks/ArticlesDatabase/ArticlesTable.swift b/Frameworks/ArticlesDatabase/ArticlesTable.swift index 4d8d565b7..c81f4f318 100644 --- a/Frameworks/ArticlesDatabase/ArticlesTable.swift +++ b/Frameworks/ArticlesDatabase/ArticlesTable.swift @@ -404,7 +404,27 @@ final class ArticlesTable: DatabaseTable { func fetchUnreadArticleIDs() -> Set{ return statusesTable.fetchUnreadArticleIDs() } - + + func fetchUnreadArticleIDsAsync(_ webFeedIDs: Set, _ callback: @escaping (Set) -> Void) { + queue.runInDatabase { database in + let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))! + let sql = "select articleID from articles natural join statuses where feedID in \(placeholders) and read=0 and userDeleted=0;" + let parameters = Array(webFeedIDs) as [Any] + + guard let resultSet = database.executeQuery(sql, withArgumentsIn: parameters) else { + DispatchQueue.main.async { + callback(Set()) + } + return + } + + let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) } + DispatchQueue.main.async { + callback(articleIDs) + } + } + } + func fetchStarredArticleIDs() -> Set { return statusesTable.fetchStarredArticleIDs() }