From d468961d81290233faa5a6e2302b8b92a5231010 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 28 Aug 2019 21:40:21 -0700 Subject: [PATCH 1/3] Update version and build number. --- Mac/Resources/Info.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mac/Resources/Info.plist b/Mac/Resources/Info.plist index bffec6487..d340a3ece 100644 --- a/Mac/Resources/Info.plist +++ b/Mac/Resources/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 5.0 + 5.0.1a CFBundleURLTypes @@ -33,7 +33,7 @@ CFBundleVersion - 2609 + 2610 LSApplicationCategoryType public.app-category.news LSMinimumSystemVersion From 29efae42fdb1c56b5ccb8a7494e1b89bb3926ad5 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 28 Aug 2019 21:40:56 -0700 Subject: [PATCH 2/3] Update Apple events privacy statement to refer to article instead of news item. --- Mac/Resources/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mac/Resources/Info.plist b/Mac/Resources/Info.plist index d340a3ece..02b218ceb 100644 --- a/Mac/Resources/Info.plist +++ b/Mac/Resources/Info.plist @@ -44,7 +44,7 @@ NSAppleEventsUsageDescription - NetNewsWire communicates with other apps on your Mac when you choose to share a news item. + NetNewsWire communicates with other apps on your Mac when you choose to share an article. NSAppleScriptEnabled NSHumanReadableCopyright From a69be4117a7a99e5d9c8ec956702e5c20f90f7e5 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Fri, 30 Aug 2019 10:39:52 -0500 Subject: [PATCH 3/3] Retrieve statuses before articles during sync process and default starred articles to read if there isn't an unread status Issue #868 --- Frameworks/Account/Account.swift | 16 +-- .../Feedbin/FeedbinAccountDelegate.swift | 113 +++++++++--------- .../ArticlesDatabase/ArticlesDatabase.swift | 16 +-- .../ArticlesDatabase/ArticlesTable.swift | 16 +-- .../ArticlesDatabase/StatusesTable.swift | 22 ++-- 5 files changed, 90 insertions(+), 93 deletions(-) diff --git a/Frameworks/Account/Account.swift b/Frameworks/Account/Account.swift index 6a94bf4e4..63b30cd21 100644 --- a/Frameworks/Account/Account.swift +++ b/Frameworks/Account/Account.swift @@ -516,16 +516,16 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, database.fetchStarredAndUnreadCount(for: flattenedFeeds().feedIDs(), callback: callback) } - public func fetchUnreadArticleIDs(_ callback: @escaping (Set) -> Void) { - database.fetchUnreadArticleIDs(callback) + public func fetchUnreadArticleIDs() -> Set { + return database.fetchUnreadArticleIDs() } - public func fetchStarredArticleIDs(_ callback: @escaping (Set) -> Void) { - database.fetchStarredArticleIDs(callback) + public func fetchStarredArticleIDs() -> Set { + return database.fetchStarredArticleIDs() } - public func fetchArticleIDsForStatusesWithoutArticles(_ callback: @escaping (Set) -> Void) { - database.fetchArticleIDsForStatusesWithoutArticles(callback) + public func fetchArticleIDsForStatusesWithoutArticles() -> Set { + return database.fetchArticleIDsForStatusesWithoutArticles() } public func opmlDocument() -> String { @@ -609,9 +609,9 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, return updatedArticles } - func ensureStatuses(_ articleIDs: Set, _ statusKey: ArticleStatus.Key, _ flag: Bool) { + func ensureStatuses(_ articleIDs: Set, _ defaultRead: Bool, _ statusKey: ArticleStatus.Key, _ flag: Bool) { if !articleIDs.isEmpty { - database.ensureStatuses(articleIDs, statusKey, flag) + database.ensureStatuses(articleIDs, defaultRead, statusKey, flag) } } diff --git a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift index 4286c04ed..9131b703e 100644 --- a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift @@ -87,9 +87,9 @@ final class FeedbinAccountDelegate: AccountDelegate { switch result { case .success(): - self.refreshArticles(account) { - self.sendArticleStatus(for: account) { - self.refreshArticleStatus(for: account) { + self.sendArticleStatus(for: account) { + self.refreshArticleStatus(for: account) { + self.refreshArticles(account) { self.refreshMissingArticles(account) { self.refreshProgress.clear() DispatchQueue.main.async { @@ -939,8 +939,8 @@ private extension FeedbinAccountDelegate { case .success(let (entries, page)): self.processEntries(account: account, entries: entries) { - self.refreshArticles(account, page: page) { - self.refreshArticleStatus(for: account) { + self.refreshArticleStatus(for: account) { + self.refreshArticles(account, page: page) { self.refreshProgress.completeTask() self.refreshMissingArticles(account) { self.refreshProgress.completeTask() @@ -996,24 +996,24 @@ private extension FeedbinAccountDelegate { os_log(.debug, log: log, "Refreshing missing articles...") let group = DispatchGroup() - account.fetchArticleIDsForStatusesWithoutArticles { (fetchedArticleIDs) in - let articleIDs = Array(fetchedArticleIDs) - let chunkedArticleIDs = articleIDs.chunked(into: 100) - for chunk in chunkedArticleIDs { - group.enter() - self.caller.retrieveEntries(articleIDs: chunk) { result in + let fetchedArticleIDs = account.fetchArticleIDsForStatusesWithoutArticles() + let articleIDs = Array(fetchedArticleIDs) + let chunkedArticleIDs = articleIDs.chunked(into: 100) - switch result { - case .success(let entries): + for chunk in chunkedArticleIDs { + group.enter() + self.caller.retrieveEntries(articleIDs: chunk) { result in - self.processEntries(account: account, entries: entries) { - group.leave() - } + switch result { + case .success(let entries): - case .failure(let error): - os_log(.error, log: self.log, "Refresh missing articles failed: %@.", error.localizedDescription) + self.processEntries(account: account, entries: entries) { group.leave() } + + case .failure(let error): + os_log(.error, log: self.log, "Refresh missing articles failed: %@.", error.localizedDescription) + group.leave() } } } @@ -1101,29 +1101,28 @@ private extension FeedbinAccountDelegate { } let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } ) - account.fetchUnreadArticleIDs { (currentUnreadArticleIDs) in - // Mark articles as unread - let deltaUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) - account.fetchArticlesAsync(.articleIDs(deltaUnreadArticleIDs)) { (markUnreadArticles) in - account.update(markUnreadArticles, statusKey: .read, flag: false) + 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) - // 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, .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) - account.fetchArticlesAsync(.articleIDs(deltaReadArticleIDs)) { (markReadArticles) in - account.update(markReadArticles, statusKey: .read, flag: 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) - // 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, .read, true) - } - } } func syncArticleStarredState(account: Account, articleIDs: [Int]?) { @@ -1132,29 +1131,27 @@ private extension FeedbinAccountDelegate { } let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } ) - account.fetchStarredArticleIDs { (currentStarredArticleIDs) in - // Mark articles as starred - let deltaStarredArticleIDs = feedbinStarredArticleIDs.subtracting(currentStarredArticleIDs) - account.fetchArticlesAsync(.articleIDs(deltaStarredArticleIDs)) { (markStarredArticles) in - account.update(markStarredArticles, statusKey: .starred, flag: true) + let currentStarredArticleIDs = account.fetchStarredArticleIDs() + + // Mark articles as starred + let deltaStarredArticleIDs = feedbinStarredArticleIDs.subtracting(currentStarredArticleIDs) + let markStarredArticles = account.fetchArticles(.articleIDs(deltaStarredArticleIDs)) + account.update(markStarredArticles, statusKey: .starred, flag: true) - // Save any starred statuses for articles we haven't yet received - let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID }) - let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs) - account.ensureStatuses(missingStarredArticleIDs, .starred, true) - } + // Save any starred statuses for articles we haven't yet received + let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID }) + let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs) + account.ensureStatuses(missingStarredArticleIDs, true, .starred, true) - // Mark articles as unstarred - let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(feedbinStarredArticleIDs) - account.fetchArticlesAsync(.articleIDs(deltaUnstarredArticleIDs)) { (markUnstarredArticles) in - account.update(markUnstarredArticles, statusKey: .starred, flag: false) + // Mark articles as unstarred + let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(feedbinStarredArticleIDs) + let markUnstarredArticles = account.fetchArticles(.articleIDs(deltaUnstarredArticleIDs)) + account.update(markUnstarredArticles, statusKey: .starred, flag: false) - // Save any unstarred statuses for articles we haven't yet received - let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID }) - let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs) - account.ensureStatuses(missingUnstarredArticleIDs, .starred, false) - } - } + // Save any unstarred statuses for articles we haven't yet received + let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID }) + let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs) + account.ensureStatuses(missingUnstarredArticleIDs, true, .starred, false) } func deleteTagging(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result) -> Void) { diff --git a/Frameworks/ArticlesDatabase/ArticlesDatabase.swift b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift index 951162def..d3e455e36 100644 --- a/Frameworks/ArticlesDatabase/ArticlesDatabase.swift +++ b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift @@ -122,22 +122,22 @@ public final class ArticlesDatabase { return articlesTable.update(feedID, parsedItems, defaultRead, completion) } - public func ensureStatuses(_ articleIDs: Set, _ statusKey: ArticleStatus.Key, _ flag: Bool) { - articlesTable.ensureStatuses(articleIDs, statusKey, flag) + public func ensureStatuses(_ articleIDs: Set, _ defaultRead: Bool, _ statusKey: ArticleStatus.Key, _ flag: Bool) { + articlesTable.ensureStatuses(articleIDs, defaultRead, statusKey, flag) } // MARK: - Status - public func fetchUnreadArticleIDs(_ callback: @escaping (Set) -> Void) { - articlesTable.fetchUnreadArticleIDs(callback) + public func fetchUnreadArticleIDs() -> Set { + return articlesTable.fetchUnreadArticleIDs() } - public func fetchStarredArticleIDs(_ callback: @escaping (Set) -> Void) { - articlesTable.fetchStarredArticleIDs(callback) + public func fetchStarredArticleIDs() -> Set { + return articlesTable.fetchStarredArticleIDs() } - public func fetchArticleIDsForStatusesWithoutArticles(_ callback: @escaping (Set) -> Void) { - articlesTable.fetchArticleIDsForStatusesWithoutArticles(callback) + public func fetchArticleIDsForStatusesWithoutArticles() -> Set { + return articlesTable.fetchArticleIDsForStatusesWithoutArticles() } public func mark(_ articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set? { diff --git a/Frameworks/ArticlesDatabase/ArticlesTable.swift b/Frameworks/ArticlesDatabase/ArticlesTable.swift index 444337e20..3ac4de861 100644 --- a/Frameworks/ArticlesDatabase/ArticlesTable.swift +++ b/Frameworks/ArticlesDatabase/ArticlesTable.swift @@ -267,9 +267,9 @@ final class ArticlesTable: DatabaseTable { } } - func ensureStatuses(_ articleIDs: Set, _ statusKey: ArticleStatus.Key, _ flag: Bool) { + func ensureStatuses(_ articleIDs: Set, _ defaultRead: Bool, _ statusKey: ArticleStatus.Key, _ flag: Bool) { self.queue.update { (database) in - let statusesDictionary = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, false, database) + let statusesDictionary = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, defaultRead, database) let statuses = Set(statusesDictionary.values) self.statusesTable.mark(statuses, statusKey, flag, database) } @@ -371,16 +371,16 @@ final class ArticlesTable: DatabaseTable { // MARK: - Statuses - func fetchUnreadArticleIDs(_ callback: @escaping (Set) -> Void) { - statusesTable.fetchUnreadArticleIDs(callback) + func fetchUnreadArticleIDs() -> Set{ + return statusesTable.fetchUnreadArticleIDs() } - func fetchStarredArticleIDs(_ callback: @escaping (Set) -> Void) { - statusesTable.fetchStarredArticleIDs(callback) + func fetchStarredArticleIDs() -> Set { + return statusesTable.fetchStarredArticleIDs() } - func fetchArticleIDsForStatusesWithoutArticles(_ callback: @escaping (Set) -> Void) { - statusesTable.fetchArticleIDsForStatusesWithoutArticles(callback) + func fetchArticleIDsForStatusesWithoutArticles() -> Set { + return statusesTable.fetchArticleIDsForStatusesWithoutArticles() } func mark(_ articles: Set
, _ statusKey: ArticleStatus.Key, _ flag: Bool) -> Set? { diff --git a/Frameworks/ArticlesDatabase/StatusesTable.swift b/Frameworks/ArticlesDatabase/StatusesTable.swift index e8b5078c3..0bb18377d 100644 --- a/Frameworks/ArticlesDatabase/StatusesTable.swift +++ b/Frameworks/ArticlesDatabase/StatusesTable.swift @@ -74,27 +74,27 @@ final class StatusesTable: DatabaseTable { // MARK: - Fetching - func fetchUnreadArticleIDs(_ callback: @escaping (Set) -> Void) { - fetchArticleIDs("select articleID from statuses where read=0 and userDeleted=0;", callback) + func fetchUnreadArticleIDs() -> Set { + return fetchArticleIDs("select articleID from statuses where read=0 and userDeleted=0;") } - func fetchStarredArticleIDs(_ callback: @escaping (Set) -> Void) { - fetchArticleIDs("select articleID from statuses where starred=1 and userDeleted=0;", callback) + func fetchStarredArticleIDs() -> Set { + return fetchArticleIDs("select articleID from statuses where starred=1 and userDeleted=0;") } - func fetchArticleIDsForStatusesWithoutArticles(_ callback: @escaping (Set) -> Void) { - fetchArticleIDs("select articleID from statuses s where (read=0 or starred=1) and userDeleted=0 and not exists (select 1 from articles a where a.articleID = s.articleID);", callback) + func fetchArticleIDsForStatusesWithoutArticles() -> Set { + return fetchArticleIDs("select articleID from statuses s where (read=0 or starred=1) and userDeleted=0 and not exists (select 1 from articles a where a.articleID = s.articleID);") } - func fetchArticleIDs(_ sql: String, _ callback: @escaping (Set) -> Void) { - queue.fetch { (database) in + func fetchArticleIDs(_ sql: String) -> Set { + var articleIDs = Set() + queue.fetchSync { (database) in guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else { - callback(Set()) return } - let statuses = resultSet.mapToSet(self.articleIDWithRow) - callback(statuses) + articleIDs = resultSet.mapToSet(self.articleIDWithRow) } + return articleIDs } func articleIDWithRow(_ row: FMResultSet) -> String? {