Skip to content

Commit

Permalink
Implement changed retention policy. Now matches iOS.
Browse files Browse the repository at this point in the history
  • Loading branch information
brentsimmons committed Aug 3, 2020
1 parent 314987e commit 010abbd
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 31 deletions.
75 changes: 56 additions & 19 deletions Frameworks/Account/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
}
Expand Down
2 changes: 1 addition & 1 deletion Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
13 changes: 10 additions & 3 deletions Frameworks/ArticlesDatabase/ArticlesDatabase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand All @@ -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>? {
Expand Down
4 changes: 2 additions & 2 deletions Frameworks/ArticlesDatabase/ArticlesTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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>? {
Expand Down
15 changes: 11 additions & 4 deletions Frameworks/ArticlesDatabase/StatusesTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion Mac/MainWindow/Timeline/ArticlePasteboardWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ private extension ArticlePasteboardWriter {
d[Key.externalURL] = article.externalURL ?? nil
d[Key.summary] = article.summary ?? nil
d[Key.imageURL] = article.imageURL ?? nil
d[Key.bannerImageURL] = article.bannerImageURL ?? nil
d[Key.datePublished] = article.datePublished ?? nil
d[Key.dateModified] = article.dateModified ?? nil
d[Key.dateArrived] = article.status.dateArrived
Expand Down
2 changes: 1 addition & 1 deletion Mac/MainWindow/Timeline/TimelineViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
let longTitle = "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
let prototypeID = "prototype"
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, dateArrived: Date())
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, feedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, status: status)
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, feedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, datePublished: nil, dateModified: nil, authors: nil, status: status)

let prototypeCellData = TimelineCellData(article: prototypeArticle, showFeedName: showingFeedNames, feedName: "Prototype Feed Name", avatar: nil, showAvatar: false, featuredImage: nil)
let height = TimelineCellLayout.height(for: 100, cellData: prototypeCellData, appearance: cellAppearance)
Expand Down

0 comments on commit 010abbd

Please sign in to comment.