From fb4f72ad18207d22ef84f1e6401fe36efd45c0b6 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Sun, 22 Mar 2020 19:25:53 -0700 Subject: [PATCH] =?UTF-8?q?Save=20articles=20from=20multiple=20web=20feeds?= =?UTF-8?q?=20at=20once=20=E2=80=94=C2=A0rather=20than=20doing=20it=20feed?= =?UTF-8?q?-by-feed=20=E2=80=94=20when=20syncing.=20(This=20makes=20syncin?= =?UTF-8?q?g=20faster.)=20Fix=20#1794.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Frameworks/Account/Account.swift | 81 +++++++++---------- .../ArticlesDatabase/ArticlesDatabase.swift | 4 +- .../ArticlesDatabase/ArticlesTable.swift | 12 ++- .../Extensions/Article+Database.swift | 11 ++- 4 files changed, 56 insertions(+), 52 deletions(-) diff --git a/Frameworks/Account/Account.swift b/Frameworks/Account/Account.swift index 5bbc1f6b2..271677817 100644 --- a/Frameworks/Account/Account.swift +++ b/Frameworks/Account/Account.swift @@ -688,56 +688,49 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, completion(nil) return } - - let group = DispatchGroup() - var possibleError: DatabaseError? = nil - var newArticles = Set
() - var updatedArticles = Set
() - - for (webFeedID, items) in webFeedIDsAndItems { - - group.enter() - database.update(webFeedID: webFeedID, items: items, defaultRead: defaultRead) { updateArticlesResult in - switch updateArticlesResult { - case .success(let newAndUpdatedArticles): - if let articles = newAndUpdatedArticles.newArticles { - newArticles.formUnion(articles) - } - if let articles = newAndUpdatedArticles.updatedArticles { - updatedArticles.formUnion(articles) - } - case .failure(let databaseError): - possibleError = databaseError + database.update(webFeedIDsAndItems: webFeedIDsAndItems, defaultRead: defaultRead) { updateArticlesResult in + + func sendNotificationAbout(newArticles: Set
?, updatedArticles: Set
?) { + var webFeeds = Set() + + if let newArticles = newArticles { + webFeeds.formUnion(Set(newArticles.compactMap { $0.webFeed })) } - - group.leave() - } - - } - - group.notify(queue: DispatchQueue.main) { - var userInfo = [String: Any]() - var webFeeds = Set(newArticles.compactMap { $0.webFeed }) - webFeeds.formUnion(Set(updatedArticles.compactMap { $0.webFeed })) - - if !newArticles.isEmpty { - self.updateUnreadCounts(for: webFeeds) { - NotificationCenter.default.post(name: .DownloadArticlesDidUpdateUnreadCounts, object: self, userInfo: nil) + if let updatedArticles = updatedArticles { + webFeeds.formUnion(Set(updatedArticles.compactMap { $0.webFeed })) + } + + var shouldSendNotification = false + var userInfo = [String: Any]() + + if let newArticles = newArticles, !newArticles.isEmpty { + shouldSendNotification = true + userInfo[UserInfoKey.newArticles] = newArticles + self.updateUnreadCounts(for: webFeeds) { + NotificationCenter.default.post(name: .DownloadArticlesDidUpdateUnreadCounts, object: self, userInfo: nil) + } + } + + if let updatedArticles = updatedArticles, !updatedArticles.isEmpty { + shouldSendNotification = true + userInfo[UserInfoKey.updatedArticles] = updatedArticles + } + + if shouldSendNotification { + userInfo[UserInfoKey.webFeeds] = webFeeds + NotificationCenter.default.post(name: .AccountDidDownloadArticles, object: self, userInfo: userInfo) } - userInfo[UserInfoKey.newArticles] = newArticles } - - if !updatedArticles.isEmpty { - userInfo[UserInfoKey.updatedArticles] = updatedArticles + + switch updateArticlesResult { + case .success(let newAndUpdatedArticles): + sendNotificationAbout(newArticles: newAndUpdatedArticles.newArticles, updatedArticles: newAndUpdatedArticles.updatedArticles) + completion(nil) + case .failure(let databaseError): + completion(databaseError) } - - userInfo[UserInfoKey.webFeeds] = webFeeds - NotificationCenter.default.post(name: .AccountDidDownloadArticles, object: self, userInfo: userInfo) - - completion(possibleError) } - } @discardableResult diff --git a/Frameworks/ArticlesDatabase/ArticlesDatabase.swift b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift index 8b96e1f02..ec94b2e35 100644 --- a/Frameworks/ArticlesDatabase/ArticlesDatabase.swift +++ b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift @@ -184,8 +184,8 @@ public final class ArticlesDatabase { // MARK: - Saving and Updating Articles /// Update articles and save new ones. - public func update(webFeedID: String, items: Set, defaultRead: Bool, completion: @escaping UpdateArticlesCompletionBlock) { - articlesTable.update(webFeedID, items, defaultRead, completion) + public func update(webFeedIDsAndItems: [String: Set], defaultRead: Bool, completion: @escaping UpdateArticlesCompletionBlock) { + articlesTable.update(webFeedIDsAndItems, defaultRead, completion) } // MARK: - Status diff --git a/Frameworks/ArticlesDatabase/ArticlesTable.swift b/Frameworks/ArticlesDatabase/ArticlesTable.swift index 1f0ab8414..35b52d583 100644 --- a/Frameworks/ArticlesDatabase/ArticlesTable.swift +++ b/Frameworks/ArticlesDatabase/ArticlesTable.swift @@ -169,8 +169,8 @@ final class ArticlesTable: DatabaseTable { // MARK: - Updating - func update(_ webFeedID: String, _ items: Set, _ read: Bool, _ completion: @escaping UpdateArticlesCompletionBlock) { - if items.isEmpty { + func update(_ webFeedIDsAndItems: [String: Set], _ read: Bool, _ completion: @escaping UpdateArticlesCompletionBlock) { + if webFeedIDsAndItems.isEmpty { callUpdateArticlesCompletionBlock(nil, nil, completion) return } @@ -187,11 +187,15 @@ final class ArticlesTable: DatabaseTable { self.queue.runInTransaction { (databaseResult) in func makeDatabaseCalls(_ database: FMDatabase) { - let articleIDs = items.articleIDs() + var articleIDs = Set() + for (_, parsedItems) in webFeedIDsAndItems { + articleIDs.formUnion(parsedItems.articleIDs()) + } + let statusesDictionary = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, read, database) //1 assert(statusesDictionary.count == articleIDs.count) - let allIncomingArticles = Article.articlesWithWebFeedIDsAndItems(webFeedID, items, self.accountID, statusesDictionary) //2 + let allIncomingArticles = Article.articlesWithWebFeedIDsAndItems(webFeedIDsAndItems, self.accountID, statusesDictionary) //2 if allIncomingArticles.isEmpty { self.callUpdateArticlesCompletionBlock(nil, nil, completion) return diff --git a/Frameworks/ArticlesDatabase/Extensions/Article+Database.swift b/Frameworks/ArticlesDatabase/Extensions/Article+Database.swift index 165887067..47b88caf7 100644 --- a/Frameworks/ArticlesDatabase/Extensions/Article+Database.swift +++ b/Frameworks/ArticlesDatabase/Extensions/Article+Database.swift @@ -112,9 +112,16 @@ extension Article { // return Set(parsedItems.map{ Article(parsedItem: $0, maximumDateAllowed: maximumDateAllowed, accountID: accountID, feedID: feedID, status: statusesDictionary[$0.articleID]!) }) // } - static func articlesWithWebFeedIDsAndItems(_ webFeedID: String, _ items: Set, _ accountID: String, _ statusesDictionary: [String: ArticleStatus]) -> Set
{ + static func articlesWithWebFeedIDsAndItems(_ webFeedIDsAndItems: [String: Set], _ accountID: String, _ statusesDictionary: [String: ArticleStatus]) -> Set
{ let maximumDateAllowed = Date().addingTimeInterval(60 * 60 * 24) // Allow dates up to about 24 hours ahead of now - let feedArticles = Set(items.map{ Article(parsedItem: $0, maximumDateAllowed: maximumDateAllowed, accountID: accountID, webFeedID: webFeedID, status: statusesDictionary[$0.articleID]!) }) + var feedArticles = Set
() + for (webFeedID, parsedItems) in webFeedIDsAndItems { + for parsedItem in parsedItems { + let status = statusesDictionary[parsedItem.articleID]! + let article = Article(parsedItem: parsedItem, maximumDateAllowed: maximumDateAllowed, accountID: accountID, webFeedID: webFeedID, status: status) + feedArticles.insert(article) + } + } return feedArticles } }