Merge branch 'mac-release'

This commit is contained in:
Maurice Parker 2019-08-30 11:28:16 -05:00
commit ea1f21797c
6 changed files with 93 additions and 96 deletions

View File

@ -564,16 +564,16 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
database.fetchStarredAndUnreadCount(for: flattenedFeeds().feedIDs(), callback: callback) database.fetchStarredAndUnreadCount(for: flattenedFeeds().feedIDs(), callback: callback)
} }
public func fetchUnreadArticleIDs(_ callback: @escaping (Set<String>) -> Void) { public func fetchUnreadArticleIDs() -> Set<String> {
database.fetchUnreadArticleIDs(callback) return database.fetchUnreadArticleIDs()
} }
public func fetchStarredArticleIDs(_ callback: @escaping (Set<String>) -> Void) { public func fetchStarredArticleIDs() -> Set<String> {
database.fetchStarredArticleIDs(callback) return database.fetchStarredArticleIDs()
} }
public func fetchArticleIDsForStatusesWithoutArticles(_ callback: @escaping (Set<String>) -> Void) { public func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
database.fetchArticleIDsForStatusesWithoutArticles(callback) return database.fetchArticleIDsForStatusesWithoutArticles()
} }
public func opmlDocument() -> String { public func opmlDocument() -> String {
@ -657,9 +657,9 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
return updatedArticles return updatedArticles
} }
func ensureStatuses(_ articleIDs: Set<String>, _ statusKey: ArticleStatus.Key, _ flag: Bool) { func ensureStatuses(_ articleIDs: Set<String>, _ defaultRead: Bool, _ statusKey: ArticleStatus.Key, _ flag: Bool) {
if !articleIDs.isEmpty { if !articleIDs.isEmpty {
database.ensureStatuses(articleIDs, statusKey, flag) database.ensureStatuses(articleIDs, defaultRead, statusKey, flag)
} }
} }

View File

@ -83,9 +83,9 @@ final class FeedbinAccountDelegate: AccountDelegate {
switch result { switch result {
case .success(): case .success():
self.refreshArticles(account) { self.sendArticleStatus(for: account) {
self.sendArticleStatus(for: account) { self.refreshArticleStatus(for: account) {
self.refreshArticleStatus(for: account) { self.refreshArticles(account) {
self.refreshMissingArticles(account) { self.refreshMissingArticles(account) {
self.refreshProgress.clear() self.refreshProgress.clear()
DispatchQueue.main.async { DispatchQueue.main.async {
@ -948,8 +948,8 @@ private extension FeedbinAccountDelegate {
case .success(let (entries, page)): case .success(let (entries, page)):
self.processEntries(account: account, entries: entries) { 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.refreshProgress.completeTask()
self.refreshMissingArticles(account) { self.refreshMissingArticles(account) {
self.refreshProgress.completeTask() self.refreshProgress.completeTask()
@ -1005,24 +1005,24 @@ private extension FeedbinAccountDelegate {
os_log(.debug, log: log, "Refreshing missing articles...") os_log(.debug, log: log, "Refreshing missing articles...")
let group = DispatchGroup() let group = DispatchGroup()
account.fetchArticleIDsForStatusesWithoutArticles { (fetchedArticleIDs) in let fetchedArticleIDs = account.fetchArticleIDsForStatusesWithoutArticles()
let articleIDs = Array(fetchedArticleIDs) let articleIDs = Array(fetchedArticleIDs)
let chunkedArticleIDs = articleIDs.chunked(into: 100) let chunkedArticleIDs = articleIDs.chunked(into: 100)
for chunk in chunkedArticleIDs {
group.enter()
self.caller.retrieveEntries(articleIDs: chunk) { result in
switch result { for chunk in chunkedArticleIDs {
case .success(let entries): group.enter()
self.caller.retrieveEntries(articleIDs: chunk) { result in
self.processEntries(account: account, entries: entries) { switch result {
group.leave() case .success(let entries):
}
case .failure(let error): self.processEntries(account: account, entries: entries) {
os_log(.error, log: self.log, "Refresh missing articles failed: %@.", error.localizedDescription)
group.leave() group.leave()
} }
case .failure(let error):
os_log(.error, log: self.log, "Refresh missing articles failed: %@.", error.localizedDescription)
group.leave()
} }
} }
} }
@ -1110,29 +1110,28 @@ private extension FeedbinAccountDelegate {
} }
let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } ) let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } )
account.fetchUnreadArticleIDs { (currentUnreadArticleIDs) in let currentUnreadArticleIDs = account.fetchUnreadArticleIDs()
// Mark articles as unread
let deltaUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) // Mark articles as unread
account.fetchArticlesAsync(.articleIDs(deltaUnreadArticleIDs)) { (markUnreadArticles) in let deltaUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs)
account.update(markUnreadArticles, statusKey: .read, flag: false) let markUnreadArticles = account.fetchArticles(.articleIDs(deltaUnreadArticleIDs))
account.update(markUnreadArticles, statusKey: .read, flag: false)
// Save any unread statuses for articles we haven't yet received // Save any unread statuses for articles we haven't yet received
let markUnreadArticleIDs = Set(markUnreadArticles.map { $0.articleID }) let markUnreadArticleIDs = Set(markUnreadArticles.map { $0.articleID })
let missingUnreadArticleIDs = deltaUnreadArticleIDs.subtracting(markUnreadArticleIDs) let missingUnreadArticleIDs = deltaUnreadArticleIDs.subtracting(markUnreadArticleIDs)
account.ensureStatuses(missingUnreadArticleIDs, .read, false) account.ensureStatuses(missingUnreadArticleIDs, true, .read, false)
}
// Mark articles as read // Mark articles as read
let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(feedbinUnreadArticleIDs) let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(feedbinUnreadArticleIDs)
account.fetchArticlesAsync(.articleIDs(deltaReadArticleIDs)) { (markReadArticles) in let markReadArticles = account.fetchArticles(.articleIDs(deltaReadArticleIDs))
account.update(markReadArticles, statusKey: .read, flag: true) 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]?) { func syncArticleStarredState(account: Account, articleIDs: [Int]?) {
@ -1141,29 +1140,27 @@ private extension FeedbinAccountDelegate {
} }
let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } ) let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } )
account.fetchStarredArticleIDs { (currentStarredArticleIDs) in let currentStarredArticleIDs = account.fetchStarredArticleIDs()
// Mark articles as starred
let deltaStarredArticleIDs = feedbinStarredArticleIDs.subtracting(currentStarredArticleIDs) // Mark articles as starred
account.fetchArticlesAsync(.articleIDs(deltaStarredArticleIDs)) { (markStarredArticles) in let deltaStarredArticleIDs = feedbinStarredArticleIDs.subtracting(currentStarredArticleIDs)
account.update(markStarredArticles, statusKey: .starred, flag: true) let markStarredArticles = account.fetchArticles(.articleIDs(deltaStarredArticleIDs))
account.update(markStarredArticles, statusKey: .starred, flag: true)
// Save any starred statuses for articles we haven't yet received // Save any starred statuses for articles we haven't yet received
let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID }) let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID })
let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs) let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs)
account.ensureStatuses(missingStarredArticleIDs, .starred, true) account.ensureStatuses(missingStarredArticleIDs, true, .starred, true)
}
// Mark articles as unstarred // Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(feedbinStarredArticleIDs) let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(feedbinStarredArticleIDs)
account.fetchArticlesAsync(.articleIDs(deltaUnstarredArticleIDs)) { (markUnstarredArticles) in let markUnstarredArticles = account.fetchArticles(.articleIDs(deltaUnstarredArticleIDs))
account.update(markUnstarredArticles, statusKey: .starred, flag: false) account.update(markUnstarredArticles, statusKey: .starred, flag: false)
// Save any unstarred statuses for articles we haven't yet received // Save any unstarred statuses for articles we haven't yet received
let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID }) let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID })
let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs) let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs)
account.ensureStatuses(missingUnstarredArticleIDs, .starred, false) account.ensureStatuses(missingUnstarredArticleIDs, true, .starred, false)
}
}
} }
func deleteTagging(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) { func deleteTagging(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {

View File

@ -122,22 +122,22 @@ public final class ArticlesDatabase {
return articlesTable.update(feedID, parsedItems, defaultRead, completion) return articlesTable.update(feedID, parsedItems, defaultRead, completion)
} }
public func ensureStatuses(_ articleIDs: Set<String>, _ statusKey: ArticleStatus.Key, _ flag: Bool) { public func ensureStatuses(_ articleIDs: Set<String>, _ defaultRead: Bool, _ statusKey: ArticleStatus.Key, _ flag: Bool) {
articlesTable.ensureStatuses(articleIDs, statusKey, flag) articlesTable.ensureStatuses(articleIDs, defaultRead, statusKey, flag)
} }
// MARK: - Status // MARK: - Status
public func fetchUnreadArticleIDs(_ callback: @escaping (Set<String>) -> Void) { public func fetchUnreadArticleIDs() -> Set<String> {
articlesTable.fetchUnreadArticleIDs(callback) return articlesTable.fetchUnreadArticleIDs()
} }
public func fetchStarredArticleIDs(_ callback: @escaping (Set<String>) -> Void) { public func fetchStarredArticleIDs() -> Set<String> {
articlesTable.fetchStarredArticleIDs(callback) return articlesTable.fetchStarredArticleIDs()
} }
public func fetchArticleIDsForStatusesWithoutArticles(_ callback: @escaping (Set<String>) -> Void) { public func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
articlesTable.fetchArticleIDsForStatusesWithoutArticles(callback) return articlesTable.fetchArticleIDsForStatusesWithoutArticles()
} }
public func mark(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<ArticleStatus>? { public func mark(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<ArticleStatus>? {

View File

@ -267,9 +267,9 @@ final class ArticlesTable: DatabaseTable {
} }
} }
func ensureStatuses(_ articleIDs: Set<String>, _ statusKey: ArticleStatus.Key, _ flag: Bool) { func ensureStatuses(_ articleIDs: Set<String>, _ defaultRead: Bool, _ statusKey: ArticleStatus.Key, _ flag: Bool) {
self.queue.update { (database) in 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) let statuses = Set(statusesDictionary.values)
self.statusesTable.mark(statuses, statusKey, flag, database) self.statusesTable.mark(statuses, statusKey, flag, database)
} }
@ -371,16 +371,16 @@ final class ArticlesTable: DatabaseTable {
// MARK: - Statuses // MARK: - Statuses
func fetchUnreadArticleIDs(_ callback: @escaping (Set<String>) -> Void) { func fetchUnreadArticleIDs() -> Set<String>{
statusesTable.fetchUnreadArticleIDs(callback) return statusesTable.fetchUnreadArticleIDs()
} }
func fetchStarredArticleIDs(_ callback: @escaping (Set<String>) -> Void) { func fetchStarredArticleIDs() -> Set<String> {
statusesTable.fetchStarredArticleIDs(callback) return statusesTable.fetchStarredArticleIDs()
} }
func fetchArticleIDsForStatusesWithoutArticles(_ callback: @escaping (Set<String>) -> Void) { func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
statusesTable.fetchArticleIDsForStatusesWithoutArticles(callback) return statusesTable.fetchArticleIDsForStatusesWithoutArticles()
} }
func mark(_ articles: Set<Article>, _ statusKey: ArticleStatus.Key, _ flag: Bool) -> Set<ArticleStatus>? { func mark(_ articles: Set<Article>, _ statusKey: ArticleStatus.Key, _ flag: Bool) -> Set<ArticleStatus>? {

View File

@ -74,27 +74,27 @@ final class StatusesTable: DatabaseTable {
// MARK: - Fetching // MARK: - Fetching
func fetchUnreadArticleIDs(_ callback: @escaping (Set<String>) -> Void) { func fetchUnreadArticleIDs() -> Set<String> {
fetchArticleIDs("select articleID from statuses where read=0 and userDeleted=0;", callback) return fetchArticleIDs("select articleID from statuses where read=0 and userDeleted=0;")
} }
func fetchStarredArticleIDs(_ callback: @escaping (Set<String>) -> Void) { func fetchStarredArticleIDs() -> Set<String> {
fetchArticleIDs("select articleID from statuses where starred=1 and userDeleted=0;", callback) return fetchArticleIDs("select articleID from statuses where starred=1 and userDeleted=0;")
} }
func fetchArticleIDsForStatusesWithoutArticles(_ callback: @escaping (Set<String>) -> Void) { func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
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) 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<String>) -> Void) { func fetchArticleIDs(_ sql: String) -> Set<String> {
queue.fetch { (database) in var articleIDs = Set<String>()
queue.fetchSync { (database) in
guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else { guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else {
callback(Set<String>())
return return
} }
let statuses = resultSet.mapToSet(self.articleIDWithRow) articleIDs = resultSet.mapToSet(self.articleIDWithRow)
callback(statuses)
} }
return articleIDs
} }
func articleIDWithRow(_ row: FMResultSet) -> String? { func articleIDWithRow(_ row: FMResultSet) -> String? {

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>5.0</string> <string>5.0.1a</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
<array> <array>
<dict> <dict>
@ -33,7 +33,7 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>2609</string> <string>2610</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.news</string> <string>public.app-category.news</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
@ -44,7 +44,7 @@
<true/> <true/>
</dict> </dict>
<key>NSAppleEventsUsageDescription</key> <key>NSAppleEventsUsageDescription</key>
<string>NetNewsWire communicates with other apps on your Mac when you choose to share a news item.</string> <string>NetNewsWire communicates with other apps on your Mac when you choose to share an article.</string>
<key>NSAppleScriptEnabled</key> <key>NSAppleScriptEnabled</key>
<true/> <true/>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>