Implement changed retention policy. Now matches iOS.

This commit is contained in:
Brent Simmons
2020-08-02 21:06:50 -07:00
parent 314987e484
commit 010abbdf55
7 changed files with 81 additions and 31 deletions

View File

@@ -543,8 +543,8 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
return database.fetchStarredArticleIDs()
}
public func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
return database.fetchArticleIDsForStatusesWithoutArticles()
public func fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate() -> Set<String> {
return database.fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate()
}
public func opmlDocument() -> String {
@@ -593,33 +593,70 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
func update(_ feed: Feed, with parsedFeed: ParsedFeed, _ completion: @escaping (() -> Void)) {
// Used only by an On My Mac account.
precondition(Thread.isMainThread)
precondition(type == .onMyMac) // TODO: allow iCloud
feed.takeSettings(from: parsedFeed)
let feedIDsAndItems = [feed.feedID: parsedFeed.items]
update(feedIDsAndItems: feedIDsAndItems, defaultRead: false, completion: completion)
let parsedItems = parsedFeed.items
guard !parsedItems.isEmpty else {
completion()
return
}
database.update(with: parsedItems, feedID: feed.feedID) { articleChanges in
self.sendNotificationAbout(articleChanges)
completion()
}
}
func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool, completion: @escaping (() -> Void)) {
assert(Thread.isMainThread)
// Used only by syncing systems.
precondition(Thread.isMainThread)
precondition(type != .onMyMac) // TODO: also make sure type != iCloud
guard !feedIDsAndItems.isEmpty else {
completion()
return
}
database.update(feedIDsAndItems: feedIDsAndItems, defaultRead: defaultRead) { (newArticles, updatedArticles) in
var userInfo = [String: Any]()
let feeds = Set(feedIDsAndItems.compactMap { (key, _) -> Feed? in
self.existingFeed(withFeedID: key)
})
if let newArticles = newArticles, !newArticles.isEmpty {
self.updateUnreadCounts(for: feeds)
userInfo[UserInfoKey.newArticles] = newArticles
}
if let updatedArticles = updatedArticles, !updatedArticles.isEmpty {
userInfo[UserInfoKey.updatedArticles] = updatedArticles
}
userInfo[UserInfoKey.feeds] = feeds
database.update(feedIDsAndItems: feedIDsAndItems, defaultRead: defaultRead) { articleChanges in
self.sendNotificationAbout(articleChanges)
completion()
}
}
func sendNotificationAbout(_ articleChanges: ArticleChanges) {
var webFeeds = Set<Feed>()
if let newArticles = articleChanges.newArticles {
webFeeds.formUnion(Set(newArticles.compactMap { $0.feed }))
}
if let updatedArticles = articleChanges.updatedArticles {
webFeeds.formUnion(Set(updatedArticles.compactMap { $0.feed }))
}
var shouldSendNotification = false
var shouldUpdateUnreadCounts = false
var userInfo = [String: Any]()
if let newArticles = articleChanges.newArticles, !newArticles.isEmpty {
shouldSendNotification = true
shouldUpdateUnreadCounts = true
userInfo[UserInfoKey.newArticles] = newArticles
}
if let updatedArticles = articleChanges.updatedArticles, !updatedArticles.isEmpty {
shouldSendNotification = true
userInfo[UserInfoKey.updatedArticles] = updatedArticles
}
if let deletedArticles = articleChanges.deletedArticles, !deletedArticles.isEmpty {
shouldUpdateUnreadCounts = true
}
if shouldUpdateUnreadCounts {
self.updateUnreadCounts(for: webFeeds)
}
if shouldSendNotification {
userInfo[UserInfoKey.feeds] = webFeeds
NotificationCenter.default.post(name: .AccountDidDownloadArticles, object: self, userInfo: userInfo)
}
}

View File

@@ -996,7 +996,7 @@ private extension FeedbinAccountDelegate {
os_log(.debug, log: log, "Refreshing missing articles...")
let group = DispatchGroup()
let fetchedArticleIDs = account.fetchArticleIDsForStatusesWithoutArticles()
let fetchedArticleIDs = account.fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate()
let articleIDs = Array(fetchedArticleIDs)
let chunkedArticleIDs = articleIDs.chunked(into: 100)

View File

@@ -139,8 +139,15 @@ public final class ArticlesDatabase {
// MARK: - Saving and Updating Articles
/// Update articles and save new ones. The key for feedIDsAndItems is feedID.
/// Update articles and save new ones  for feed-based systems (local and iCloud).
public func update(with parsedItems: Set<ParsedItem>, feedID: String, completion: @escaping UpdateArticlesCompletionBlock) {
precondition(retentionStyle == .feedBased)
articlesTable.update(parsedItems, feedID, completion)
}
/// Update articles and save new ones for sync systems (Feedbin, Feedly, etc.).
public func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool, completion: @escaping UpdateArticlesCompletionBlock) {
precondition(retentionStyle == .syncSystem)
articlesTable.update(feedIDsAndItems, defaultRead, completion)
}
@@ -158,8 +165,8 @@ public final class ArticlesDatabase {
return articlesTable.fetchStarredArticleIDs()
}
public func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
return articlesTable.fetchArticleIDsForStatusesWithoutArticles()
public func fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate() -> Set<String> {
return articlesTable.fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate()
}
public func mark(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<ArticleStatus>? {

View File

@@ -393,8 +393,8 @@ final class ArticlesTable: DatabaseTable {
return statusesTable.fetchStarredArticleIDs()
}
func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
return statusesTable.fetchArticleIDsForStatusesWithoutArticles()
func fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate() -> Set<String> {
return statusesTable.fetchArticleIDsForStatusesWithoutArticlesNewerThan(articleCutoffDate)
}
func mark(_ articles: Set<Article>, _ statusKey: ArticleStatus.Key, _ flag: Bool) -> Set<ArticleStatus>? {

View File

@@ -100,11 +100,18 @@ final class StatusesTable: DatabaseTable {
func fetchStarredArticleIDs() -> Set<String> {
return fetchArticleIDs("select articleID from statuses where starred=1;")
}
func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
return fetchArticleIDs("select articleID from statuses s where (read=0 or starred=1) and not exists (select 1 from articles a where a.articleID = s.articleID);")
func fetchArticleIDsForStatusesWithoutArticlesNewerThan(_ cutoffDate: Date) -> Set<String> {
var articleIDs = Set<String>()
queue.runInDatabaseSync { database in
let sql = "select articleID from statuses s where (starred=1 or dateArrived>?) and not exists (select 1 from articles a where a.articleID = s.articleID);"
if let resultSet = database.executeQuery(sql, withArgumentsIn: [cutoffDate]) {
articleIDs = resultSet.mapToSet(self.articleIDWithRow)
}
}
return articleIDs
}
func fetchArticleIDs(_ sql: String) -> Set<String> {
var articleIDs = Set<String>()
queue.runInDatabaseSync { (database) in