Update unread/starred status

This commit is contained in:
Anh Do 2020-03-14 16:10:05 -04:00
parent b8c7e8c1c6
commit b7e7e17656
No known key found for this signature in database
GPG Key ID: 451E3092F917B62D
2 changed files with 143 additions and 31 deletions

View File

@ -138,38 +138,20 @@ final class NewsBlurAPICaller: NSObject {
}
func retrieveUnreadStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
let url = baseURL
.appendingPathComponent("reader/unread_story_hashes")
.appendingQueryItems([
URLQueryItem(name: "include_timestamps", value: "true"),
])
retrieveStoryHashes(endpoint: "reader/unread_story_hashes", completion: completion)
}
guard let callURL = url else {
completion(.failure(TransportError.noURL))
return
}
let request = URLRequest(url: callURL, credentials: credentials)
transport.send(request: request, resultType: NewsBlurUnreadStoryHashesResponse.self, dateDecoding: .secondsSince1970) { result in
if self.suspended {
completion(.failure(TransportError.suspended))
return
}
switch result {
case .success((_, let payload)):
completion(.success(payload?.feeds.values.flatMap { $0 }))
case .failure(let error):
completion(.failure(error))
}
}
func retrieveStarredStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
retrieveStoryHashes(endpoint: "reader/starred_story_hashes", completion: completion)
}
func retrieveStories(hashes: [NewsBlurStoryHash], completion: @escaping (Result<[NewsBlurStory]?, Error>) -> Void) {
let url = baseURL
.appendingPathComponent("reader/river_stories")
.appendingQueryItem(.init(name: "include_hidden", value: "true"))?
.appendingQueryItems(hashes.map { URLQueryItem(name: "h", value: $0.hash) })
.appendingQueryItems(hashes.map {
URLQueryItem(name: "h", value: $0.hash)
})
guard let callURL = url else {
completion(.failure(TransportError.noURL))
@ -207,7 +189,37 @@ final class NewsBlurAPICaller: NSObject {
func unstar(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
sendStoryStatus(endpoint: "reader/mark_story_hash_as_unstarred", hashes: hashes, completion: completion)
}
}
extension NewsBlurAPICaller {
private func retrieveStoryHashes(endpoint: String, completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
let url = baseURL
.appendingPathComponent(endpoint)
.appendingQueryItems([
URLQueryItem(name: "include_timestamps", value: "true"),
])
guard let callURL = url else {
completion(.failure(TransportError.noURL))
return
}
let request = URLRequest(url: callURL, credentials: credentials)
transport.send(request: request, resultType: NewsBlurUnreadStoryHashesResponse.self, dateDecoding: .secondsSince1970) { result in
if self.suspended {
completion(.failure(TransportError.suspended))
return
}
switch result {
case .success((_, let payload)):
completion(.success(payload?.feeds.values.flatMap { $0 }))
case .failure(let error):
completion(.failure(error))
}
}
}
private func sendStoryStatus(endpoint: String, hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
let callURL = baseURL.appendingPathComponent(endpoint)

View File

@ -181,9 +181,45 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
func refreshArticleStatus(for account: Account, completion: @escaping (Result<Void, Error>) -> ()) {
os_log(.debug, log: log, "Refreshing article statuses...")
os_log(.debug, log: log, "Refreshing story statuses...")
// TODO: Fill this in
let group = DispatchGroup()
var errorOccurred = false
group.enter()
caller.retrieveUnreadStoryHashes { result in
switch result {
case .success(let storyHashes):
self.syncStoryReadState(account: account, hashes: storyHashes)
group.leave()
case .failure(let error):
errorOccurred = true
os_log(.info, log: self.log, "Retrieving unread stories failed: %@.", error.localizedDescription)
group.leave()
}
}
group.enter()
caller.retrieveStarredStoryHashes { result in
switch result {
case .success(let storyHashes):
self.syncStoryStarredState(account: account, hashes: storyHashes)
group.leave()
case .failure(let error):
errorOccurred = true
os_log(.info, log: self.log, "Retrieving starred stories failed: %@.", error.localizedDescription)
group.leave()
}
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done refreshing article statuses.")
if errorOccurred {
completion(.failure(NewsBlurError.unknown))
} else {
completion(.success(()))
}
}
}
func refreshStories(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
@ -548,9 +584,7 @@ extension NewsBlurAccountDelegate {
}
private func mapStoriesToParsedItems(stories: [NewsBlurStory]?) -> Set<ParsedItem> {
guard let stories = stories else {
return Set<ParsedItem>()
}
guard let stories = stories else { return Set<ParsedItem>() }
let parsedItems: [ParsedItem] = stories.map { story in
let author = Set([ParsedAuthor(name: story.authorName, url: nil, avatarURL: nil, emailAddress: nil)])
@ -598,4 +632,70 @@ extension NewsBlurAccountDelegate {
}
}
}
private func syncStoryReadState(account: Account, hashes: [NewsBlurStoryHash]?) {
guard let hashes = hashes else { return }
database.selectPendingReadStatusArticleIDs() { result in
func process(_ pendingStoryHashes: Set<String>) {
let newsBlurUnreadStoryHashes = Set(hashes.map { $0.hash } )
let updatableNewsBlurUnreadStoryHashes = newsBlurUnreadStoryHashes.subtracting(pendingStoryHashes)
account.fetchUnreadArticleIDs { articleIDsResult in
guard let currentUnreadArticleIDs = try? articleIDsResult.get() else {
return
}
// Mark articles as unread
let deltaUnreadArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentUnreadArticleIDs)
account.markAsUnread(deltaUnreadArticleIDs)
// Mark articles as read
let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes)
account.markAsRead(deltaReadArticleIDs)
}
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
os_log(.error, log: self.log, "Sync Story Read Status failed: %@.", error.localizedDescription)
}
}
}
private func syncStoryStarredState(account: Account, hashes: [NewsBlurStoryHash]?) {
guard let hashes = hashes else { return }
database.selectPendingStarredStatusArticleIDs() { result in
func process(_ pendingStoryHashes: Set<String>) {
let newsBlurStarredStoryHashes = Set(hashes.map { $0.hash } )
let updatableNewsBlurUnreadStoryHashes = newsBlurStarredStoryHashes.subtracting(pendingStoryHashes)
account.fetchStarredArticleIDs { articleIDsResult in
guard let currentStarredArticleIDs = try? articleIDsResult.get() else {
return
}
// Mark articles as starred
let deltaStarredArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentStarredArticleIDs)
account.markAsStarred(deltaStarredArticleIDs)
// Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes)
account.markAsUnstarred(deltaUnstarredArticleIDs)
}
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
os_log(.error, log: self.log, "Sync Story Starred Status failed: %@.", error.localizedDescription)
}
}
}
}