Cancel network activity when told to shutdown by the OS. Issue #1232
This commit is contained in:
parent
219e5751a1
commit
c6e3ed6692
|
@ -341,10 +341,20 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||
self.delegate.refreshAll(for: self, completion: completion)
|
||||
}
|
||||
|
||||
public func syncArticleStatus(completion: (() -> Void)? = nil) {
|
||||
delegate.sendArticleStatus(for: self) { [unowned self] in
|
||||
self.delegate.refreshArticleStatus(for: self) {
|
||||
completion?()
|
||||
public func syncArticleStatus(completion: ((Result<Void, Error>) -> Void)? = nil) {
|
||||
delegate.sendArticleStatus(for: self) { [unowned self] result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.delegate.refreshArticleStatus(for: self) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
completion?(.success(()))
|
||||
case .failure(let error):
|
||||
completion?(.failure(error))
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
completion?(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -369,6 +379,11 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||
|
||||
}
|
||||
|
||||
public func suspend() {
|
||||
delegate.cancelAll(for: self)
|
||||
save()
|
||||
}
|
||||
|
||||
public func save() {
|
||||
metadataFile.save()
|
||||
feedMetadataFile.save()
|
||||
|
|
|
@ -22,9 +22,10 @@ protocol AccountDelegate {
|
|||
|
||||
var refreshProgress: DownloadProgress { get }
|
||||
|
||||
func cancelAll(for account: Account)
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func sendArticleStatus(for account: Account, completion: @escaping (() -> Void))
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping (() -> Void))
|
||||
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void))
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void))
|
||||
|
||||
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
|
||||
|
|
|
@ -160,6 +160,10 @@ public final class AccountManager: UnreadCountProvider {
|
|||
return accountsDictionary[accountID]
|
||||
}
|
||||
|
||||
public func suspendAll() {
|
||||
accounts.forEach { $0.suspend() }
|
||||
}
|
||||
|
||||
public func refreshAll(errorHandler: @escaping (Error) -> Void, completion: (() ->Void)? = nil) {
|
||||
let group = DispatchGroup()
|
||||
|
||||
|
@ -187,7 +191,7 @@ public final class AccountManager: UnreadCountProvider {
|
|||
|
||||
activeAccounts.forEach {
|
||||
group.enter()
|
||||
$0.syncArticleStatus() {
|
||||
$0.syncArticleStatus() { _ in
|
||||
group.leave()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ final class TestTransport: Transport {
|
|||
return HTTPURLResponse(url: url, statusCode: statusCode, httpVersion: "HTTP/1.1", headerFields: nil)!
|
||||
}
|
||||
|
||||
func cancelAll() { }
|
||||
|
||||
func send(request: URLRequest, completion: @escaping (Result<(HTTPURLResponse, Data?), Error>) -> Void) {
|
||||
|
||||
guard let url = request.url, let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
|
||||
|
|
|
@ -42,6 +42,10 @@ final class FeedbinAPICaller: NSObject {
|
|||
self.transport = transport
|
||||
}
|
||||
|
||||
func cancelAll() {
|
||||
transport.cancelAll()
|
||||
}
|
||||
|
||||
func validateCredentials(completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||
|
||||
let callURL = feedbinBaseURL.appendingPathComponent("authentication.json")
|
||||
|
|
|
@ -15,6 +15,7 @@ import os.log
|
|||
|
||||
public enum FeedbinAccountDelegateError: String, Error {
|
||||
case invalidParameter = "There was an invalid parameter passed."
|
||||
case unknown = "An unknown error occurred."
|
||||
}
|
||||
|
||||
final class FeedbinAccountDelegate: AccountDelegate {
|
||||
|
@ -72,6 +73,10 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||
|
||||
var refreshProgress = DownloadProgress(numberOfTasks: 0)
|
||||
|
||||
func cancelAll(for account: Account) {
|
||||
caller.cancelAll()
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
retrieveCredentialsIfNecessary(account)
|
||||
|
||||
|
@ -80,16 +85,16 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||
refreshAccount(account) { result in
|
||||
switch result {
|
||||
case .success():
|
||||
|
||||
self.sendArticleStatus(for: account) {
|
||||
self.refreshArticleStatus(for: account) {
|
||||
self.refreshArticles(account) {
|
||||
self.refreshMissingArticles(account) {
|
||||
self.refreshProgress.clear()
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
|
||||
self.refreshArticlesAndStatuses(account) { result in
|
||||
switch result {
|
||||
case .success():
|
||||
completion(.success(()))
|
||||
case .failure(let error):
|
||||
DispatchQueue.main.async {
|
||||
self.refreshProgress.clear()
|
||||
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||
completion(.failure(wrappedError))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +111,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||
|
||||
}
|
||||
|
||||
func sendArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
||||
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
retrieveCredentialsIfNecessary(account)
|
||||
|
||||
os_log(.debug, log: log, "Sending article statuses...")
|
||||
|
@ -118,41 +123,59 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||
let deleteStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == false }
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
var errorOccurred = false
|
||||
|
||||
group.enter()
|
||||
sendArticleStatuses(createUnreadStatuses, apiCall: caller.createUnreadEntries) {
|
||||
sendArticleStatuses(createUnreadStatuses, apiCall: caller.createUnreadEntries) { result in
|
||||
group.leave()
|
||||
if case .failure = result {
|
||||
errorOccurred = true
|
||||
}
|
||||
}
|
||||
|
||||
group.enter()
|
||||
sendArticleStatuses(deleteUnreadStatuses, apiCall: caller.deleteUnreadEntries) {
|
||||
sendArticleStatuses(deleteUnreadStatuses, apiCall: caller.deleteUnreadEntries) { result in
|
||||
group.leave()
|
||||
if case .failure = result {
|
||||
errorOccurred = true
|
||||
}
|
||||
}
|
||||
|
||||
group.enter()
|
||||
sendArticleStatuses(createStarredStatuses, apiCall: caller.createStarredEntries) {
|
||||
sendArticleStatuses(createStarredStatuses, apiCall: caller.createStarredEntries) { result in
|
||||
group.leave()
|
||||
if case .failure = result {
|
||||
errorOccurred = true
|
||||
}
|
||||
}
|
||||
|
||||
group.enter()
|
||||
sendArticleStatuses(deleteStarredStatuses, apiCall: caller.deleteStarredEntries) {
|
||||
sendArticleStatuses(deleteStarredStatuses, apiCall: caller.deleteStarredEntries) { result in
|
||||
group.leave()
|
||||
if case .failure = result {
|
||||
errorOccurred = true
|
||||
}
|
||||
}
|
||||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
os_log(.debug, log: self.log, "Done sending article statuses.")
|
||||
completion()
|
||||
if errorOccurred {
|
||||
completion(.failure(FeedbinAccountDelegateError.unknown))
|
||||
} else {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
retrieveCredentialsIfNecessary(account)
|
||||
|
||||
os_log(.debug, log: log, "Refreshing article statuses...")
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
var errorOccurred = false
|
||||
|
||||
group.enter()
|
||||
caller.retrieveUnreadEntries() { result in
|
||||
switch result {
|
||||
|
@ -160,6 +183,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||
self.syncArticleReadState(account: account, articleIDs: articleIDs)
|
||||
group.leave()
|
||||
case .failure(let error):
|
||||
errorOccurred = true
|
||||
os_log(.info, log: self.log, "Retrieving unread entries failed: %@.", error.localizedDescription)
|
||||
group.leave()
|
||||
}
|
||||
|
@ -173,6 +197,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||
self.syncArticleStarredState(account: account, articleIDs: articleIDs)
|
||||
group.leave()
|
||||
case .failure(let error):
|
||||
errorOccurred = true
|
||||
os_log(.info, log: self.log, "Retrieving starred entries failed: %@.", error.localizedDescription)
|
||||
group.leave()
|
||||
}
|
||||
|
@ -181,7 +206,11 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
os_log(.debug, log: self.log, "Done refreshing article statuses.")
|
||||
completion()
|
||||
if errorOccurred {
|
||||
completion(.failure(FeedbinAccountDelegateError.unknown))
|
||||
} else {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -515,7 +544,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||
database.insertStatuses(syncStatuses)
|
||||
|
||||
if database.selectPendingCount() > 100 {
|
||||
sendArticleStatus(for: account) {}
|
||||
sendArticleStatus(for: account) { _ in }
|
||||
}
|
||||
|
||||
return account.update(articles, statusKey: statusKey, flag: flag)
|
||||
|
@ -639,6 +668,49 @@ private extension FeedbinAccountDelegate {
|
|||
|
||||
}
|
||||
|
||||
func refreshArticlesAndStatuses(_ account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
self.sendArticleStatus(for: account) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
|
||||
self.refreshArticleStatus(for: account) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
|
||||
self.refreshArticles(account) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
|
||||
self.refreshMissingArticles(account) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.refreshProgress.clear()
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function can be deleted if Feedbin updates their taggings.json service to
|
||||
// show a change when a tag is renamed.
|
||||
func forceExpireFolderFeedRelationship(_ account: Account, _ tags: [FeedbinTag]?) {
|
||||
|
@ -843,14 +915,15 @@ private extension FeedbinAccountDelegate {
|
|||
|
||||
func sendArticleStatuses(_ statuses: [SyncStatus],
|
||||
apiCall: ([Int], @escaping (Result<Void, Error>) -> Void) -> Void,
|
||||
completion: @escaping (() -> Void)) {
|
||||
completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
|
||||
guard !statuses.isEmpty else {
|
||||
completion()
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
let group = DispatchGroup()
|
||||
var errorOccurred = false
|
||||
|
||||
let articleIDs = statuses.compactMap { Int($0.articleID) }
|
||||
let articleIDGroups = articleIDs.chunked(into: 1000)
|
||||
|
@ -863,6 +936,7 @@ private extension FeedbinAccountDelegate {
|
|||
self.database.deleteSelectedForProcessing(articleIDGroup.map { String($0) } )
|
||||
group.leave()
|
||||
case .failure(let error):
|
||||
errorOccurred = true
|
||||
os_log(.error, log: self.log, "Article status sync call failed: %@.", error.localizedDescription)
|
||||
self.database.resetSelectedForProcessing(articleIDGroup.map { String($0) } )
|
||||
group.leave()
|
||||
|
@ -872,7 +946,11 @@ private extension FeedbinAccountDelegate {
|
|||
}
|
||||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
completion()
|
||||
if errorOccurred {
|
||||
completion(.failure(FeedbinAccountDelegateError.unknown))
|
||||
} else {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -973,15 +1051,38 @@ private extension FeedbinAccountDelegate {
|
|||
case .success(let (entries, page)):
|
||||
|
||||
self.processEntries(account: account, entries: entries) {
|
||||
self.refreshArticleStatus(for: account) {
|
||||
self.refreshArticles(account, page: page, updateFetchDate: nil) {
|
||||
self.refreshProgress.completeTask()
|
||||
self.refreshMissingArticles(account) {
|
||||
self.refreshProgress.completeTask()
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(feed))
|
||||
self.refreshArticleStatus(for: account) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
|
||||
self.refreshArticles(account, page: page, updateFetchDate: nil) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
|
||||
self.refreshProgress.completeTask()
|
||||
self.refreshMissingArticles(account) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
|
||||
self.refreshProgress.completeTask()
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(feed))
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -994,7 +1095,7 @@ private extension FeedbinAccountDelegate {
|
|||
|
||||
}
|
||||
|
||||
func refreshArticles(_ account: Account, completion: @escaping (() -> Void)) {
|
||||
func refreshArticles(_ account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
|
||||
os_log(.debug, log: log, "Refreshing articles...")
|
||||
|
||||
|
@ -1010,25 +1111,30 @@ private extension FeedbinAccountDelegate {
|
|||
self.processEntries(account: account, entries: entries) {
|
||||
|
||||
self.refreshProgress.completeTask()
|
||||
self.refreshArticles(account, page: page, updateFetchDate: updateFetchDate) {
|
||||
self.refreshArticles(account, page: page, updateFetchDate: updateFetchDate) { result in
|
||||
os_log(.debug, log: self.log, "Done refreshing articles.")
|
||||
completion()
|
||||
switch result {
|
||||
case .success:
|
||||
completion(.success(()))
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
os_log(.error, log: self.log, "Refresh articles failed: %@.", error.localizedDescription)
|
||||
completion()
|
||||
completion(.failure(error))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func refreshMissingArticles(_ account: Account, completion: @escaping (() -> Void)) {
|
||||
func refreshMissingArticles(_ account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
os_log(.debug, log: log, "Refreshing missing articles...")
|
||||
let group = DispatchGroup()
|
||||
var errorOccurred = false
|
||||
|
||||
let fetchedArticleIDs = account.fetchArticleIDsForStatusesWithoutArticles()
|
||||
let articleIDs = Array(fetchedArticleIDs)
|
||||
|
@ -1046,6 +1152,7 @@ private extension FeedbinAccountDelegate {
|
|||
}
|
||||
|
||||
case .failure(let error):
|
||||
errorOccurred = true
|
||||
os_log(.error, log: self.log, "Refresh missing articles failed: %@.", error.localizedDescription)
|
||||
group.leave()
|
||||
}
|
||||
|
@ -1055,16 +1162,20 @@ private extension FeedbinAccountDelegate {
|
|||
group.notify(queue: DispatchQueue.main) {
|
||||
self.refreshProgress.completeTask()
|
||||
os_log(.debug, log: self.log, "Done refreshing missing articles.")
|
||||
completion()
|
||||
if errorOccurred {
|
||||
completion(.failure(FeedbinAccountDelegateError.unknown))
|
||||
} else {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func refreshArticles(_ account: Account, page: String?, updateFetchDate: Date?, completion: @escaping (() -> Void)) {
|
||||
func refreshArticles(_ account: Account, page: String?, updateFetchDate: Date?, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
guard let page = page else {
|
||||
if let lastArticleFetch = updateFetchDate {
|
||||
self.accountMetadata?.lastArticleFetch = lastArticleFetch
|
||||
}
|
||||
completion()
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1079,8 +1190,7 @@ private extension FeedbinAccountDelegate {
|
|||
}
|
||||
|
||||
case .failure(let error):
|
||||
os_log(.error, log: self.log, "Refresh articles for additional pages failed: %@.", error.localizedDescription)
|
||||
completion()
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,10 @@ final class FeedlyAPICaller {
|
|||
return baseUrlComponents.host
|
||||
}
|
||||
|
||||
func cancelAll() {
|
||||
transport.cancelAll()
|
||||
}
|
||||
|
||||
func importOpml(_ opmlData: Data, completionHandler: @escaping (Result<Void, Error>) -> ()) {
|
||||
guard let accessToken = credentials?.secret else {
|
||||
return DispatchQueue.main.async {
|
||||
|
|
|
@ -78,6 +78,10 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
|
||||
// MARK: Account API
|
||||
|
||||
func cancelAll(for account: Account) {
|
||||
// TODO: Implement me please
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
assert(Thread.isMainThread)
|
||||
|
||||
|
@ -113,12 +117,12 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
OperationQueue.main.addOperation(operation)
|
||||
}
|
||||
|
||||
func sendArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
||||
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
// Ensure remote articles have the same status as they do locally.
|
||||
let send = FeedlySendArticleStatusesOperation(database: database, service: caller, log: log)
|
||||
send.completionBlock = {
|
||||
DispatchQueue.main.async {
|
||||
completion()
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
OperationQueue.main.addOperation(send)
|
||||
|
@ -134,9 +138,9 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
///
|
||||
/// - Parameter account: The account whose articles have a remote status.
|
||||
/// - Parameter completion: Call on the main queue.
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
guard let credentials = credentials else {
|
||||
return completion()
|
||||
return completion(.success(()))
|
||||
}
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
@ -157,7 +161,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
}
|
||||
|
||||
group.notify(queue: .main) {
|
||||
completion()
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
OperationQueue.main.addOperations([getUnread, getStarred], waitUntilFinished: false)
|
||||
|
@ -448,7 +452,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
os_log(.debug, log: log, "Marking %@ as %@.", articles.map { $0.title }, syncStatuses)
|
||||
|
||||
if database.selectPendingCount() > 100 {
|
||||
sendArticleStatus(for: account) { }
|
||||
sendArticleStatus(for: account) { _ in }
|
||||
}
|
||||
|
||||
return account.update(articles, statusKey: statusKey, flag: flag)
|
||||
|
|
|
@ -31,18 +31,22 @@ final class LocalAccountDelegate: AccountDelegate {
|
|||
return refresher.progress
|
||||
}
|
||||
|
||||
func cancelAll(for account: Account) {
|
||||
// TODO: implement me
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
refresher.refreshFeeds(account.flattenedFeeds()) {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
|
||||
func sendArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
||||
completion()
|
||||
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
||||
completion()
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
|
|
@ -19,7 +19,7 @@ public enum ReaderAPIAccountDelegateError: String, Error {
|
|||
}
|
||||
|
||||
final class ReaderAPIAccountDelegate: AccountDelegate {
|
||||
|
||||
|
||||
private let database: SyncDatabase
|
||||
|
||||
private let caller: ReaderAPICaller
|
||||
|
@ -79,6 +79,10 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
|||
|
||||
var refreshProgress = DownloadProgress(numberOfTasks: 0)
|
||||
|
||||
func cancelAll(for account: Account) {
|
||||
caller.cancelAll()
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(6)
|
||||
|
@ -87,8 +91,8 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
|||
switch result {
|
||||
case .success():
|
||||
|
||||
self.sendArticleStatus(for: account) {
|
||||
self.refreshArticleStatus(for: account) {
|
||||
self.sendArticleStatus(for: account) { _ in
|
||||
self.refreshArticleStatus(for: account) { _ in
|
||||
self.refreshArticles(account) {
|
||||
self.refreshMissingArticles(account) {
|
||||
self.refreshProgress.clear()
|
||||
|
@ -112,7 +116,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
|||
|
||||
}
|
||||
|
||||
func sendArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
||||
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
|
||||
os_log(.debug, log: log, "Sending article statuses...")
|
||||
|
||||
|
@ -146,12 +150,12 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
|||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
os_log(.debug, log: self.log, "Done sending article statuses.")
|
||||
completion()
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
|
||||
os_log(.debug, log: log, "Refreshing article statuses...")
|
||||
|
||||
|
@ -185,7 +189,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
|||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
os_log(.debug, log: self.log, "Done refreshing article statuses.")
|
||||
completion()
|
||||
completion(.success(()))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -403,7 +407,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
|||
database.insertStatuses(syncStatuses)
|
||||
|
||||
if database.selectPendingCount() > 100 {
|
||||
sendArticleStatus(for: account) {}
|
||||
sendArticleStatus(for: account) { _ in }
|
||||
}
|
||||
|
||||
return account.update(articles, statusKey: statusKey, flag: flag)
|
||||
|
@ -755,7 +759,7 @@ private extension ReaderAPIAccountDelegate {
|
|||
case .success(let (entries, page)):
|
||||
|
||||
self.processEntries(account: account, entries: entries) {
|
||||
self.refreshArticleStatus(for: account) {
|
||||
self.refreshArticleStatus(for: account) { _ in
|
||||
self.refreshArticles(account, page: page) {
|
||||
self.refreshMissingArticles(account) {
|
||||
DispatchQueue.main.async {
|
||||
|
|
|
@ -78,6 +78,10 @@ final class ReaderAPICaller: NSObject {
|
|||
self.transport = transport
|
||||
}
|
||||
|
||||
func cancelAll() {
|
||||
transport.cancelAll()
|
||||
}
|
||||
|
||||
func validateCredentials(endpoint: URL, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||
guard let credentials = credentials else {
|
||||
completion(.failure(CredentialsError.incompleteCredentials))
|
||||
|
|
|
@ -109,6 +109,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
shuttingDown = true
|
||||
AccountManager.shared.suspendAll()
|
||||
}
|
||||
|
||||
// MARK: Notifications
|
||||
|
@ -243,7 +244,7 @@ private extension AppDelegate {
|
|||
|
||||
func waitForProgressToFinish() {
|
||||
let completeProcessing = { [unowned self] in
|
||||
AccountManager.shared.saveAll()
|
||||
AccountManager.shared.suspendAll()
|
||||
UIApplication.shared.endBackgroundTask(self.waitBackgroundUpdateTask)
|
||||
self.waitBackgroundUpdateTask = UIBackgroundTaskIdentifier.invalid
|
||||
}
|
||||
|
|
|
@ -16,7 +16,11 @@ struct ErrorHandler {
|
|||
|
||||
public static func present(_ viewController: UIViewController) -> (Error) -> () {
|
||||
return { [weak viewController] error in
|
||||
viewController?.presentError(error)
|
||||
if UIApplication.shared.applicationState == .active {
|
||||
viewController?.presentError(error)
|
||||
} else {
|
||||
ErrorHandler.log(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 1ea5f5ccfc3646ffdf2891abbc5ea63e3d449def
|
||||
Subproject commit 262a220230ef393edb7c003132b6cdc16a17cb5e
|
Loading…
Reference in New Issue