Add account name to network error messages and prevent background iOS errors from displaying alerts
This commit is contained in:
parent
b327d82004
commit
c61949bc04
|
@ -36,27 +36,6 @@ public enum AccountType: Int {
|
||||||
// TODO: more
|
// TODO: more
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum AccountError: LocalizedError {
|
|
||||||
|
|
||||||
case createErrorNotFound
|
|
||||||
case createErrorAlreadySubscribed
|
|
||||||
case opmlImportInProgress
|
|
||||||
|
|
||||||
public var errorDescription: String? {
|
|
||||||
switch self {
|
|
||||||
case .opmlImportInProgress:
|
|
||||||
return NSLocalizedString("An OPML import for this account is already running.", comment: "Import running")
|
|
||||||
default:
|
|
||||||
return NSLocalizedString("An unknown error occurred.", comment: "Unknown error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var recoverySuggestion: String? {
|
|
||||||
return NSLocalizedString("Please try again later.", comment: "Try later")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class Account: DisplayNameProvider, UnreadCountProvider, Container, Hashable {
|
public final class Account: DisplayNameProvider, UnreadCountProvider, Container, Hashable {
|
||||||
|
|
||||||
public struct UserInfoKey {
|
public struct UserInfoKey {
|
||||||
|
@ -309,7 +288,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func refreshAll(completion: (() -> Void)? = nil) {
|
public func refreshAll(completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
self.delegate.refreshAll(for: self, completion: completion)
|
self.delegate.refreshAll(for: self, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,9 +313,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
// Reset the last fetch date to get the article history for the added feeds.
|
// Reset the last fetch date to get the article history for the added feeds.
|
||||||
self.metadata.lastArticleFetch = nil
|
self.metadata.lastArticleFetch = nil
|
||||||
self.delegate.refreshAll(for: self) {
|
self.delegate.refreshAll(for: self, completion: completion)
|
||||||
completion(.success(()))
|
|
||||||
}
|
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
completion(.failure(error))
|
completion(.failure(error))
|
||||||
}
|
}
|
||||||
|
@ -457,8 +434,9 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||||
structureDidChange()
|
structureDidChange()
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.refreshAll()
|
self.refreshAll() { result in }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateUnreadCounts(for feeds: Set<Feed>) {
|
public func updateUnreadCounts(for feeds: Set<Feed>) {
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
51D5875B227F630B00900287 /* tags_add.json in Resources */ = {isa = PBXBuildFile; fileRef = 51D58758227F630B00900287 /* tags_add.json */; };
|
51D5875B227F630B00900287 /* tags_add.json in Resources */ = {isa = PBXBuildFile; fileRef = 51D58758227F630B00900287 /* tags_add.json */; };
|
||||||
51D5875C227F630B00900287 /* tags_initial.json in Resources */ = {isa = PBXBuildFile; fileRef = 51D58759227F630B00900287 /* tags_initial.json */; };
|
51D5875C227F630B00900287 /* tags_initial.json in Resources */ = {isa = PBXBuildFile; fileRef = 51D58759227F630B00900287 /* tags_initial.json */; };
|
||||||
51D5875E227F643C00900287 /* AccountFolderSyncTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D5875D227F643C00900287 /* AccountFolderSyncTest.swift */; };
|
51D5875E227F643C00900287 /* AccountFolderSyncTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D5875D227F643C00900287 /* AccountFolderSyncTest.swift */; };
|
||||||
|
51E3EB41229AF61B00645299 /* AccountError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E3EB40229AF61B00645299 /* AccountError.swift */; };
|
||||||
51E490362288C37100C791F0 /* FeedbinDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E490352288C37100C791F0 /* FeedbinDate.swift */; };
|
51E490362288C37100C791F0 /* FeedbinDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E490352288C37100C791F0 /* FeedbinDate.swift */; };
|
||||||
51E59599228C77BC00FCC42B /* FeedbinUnreadEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E59598228C77BC00FCC42B /* FeedbinUnreadEntry.swift */; };
|
51E59599228C77BC00FCC42B /* FeedbinUnreadEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E59598228C77BC00FCC42B /* FeedbinUnreadEntry.swift */; };
|
||||||
51E5959B228C781500FCC42B /* FeedbinStarredEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E5959A228C781500FCC42B /* FeedbinStarredEntry.swift */; };
|
51E5959B228C781500FCC42B /* FeedbinStarredEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E5959A228C781500FCC42B /* FeedbinStarredEntry.swift */; };
|
||||||
|
@ -131,6 +132,7 @@
|
||||||
51D58758227F630B00900287 /* tags_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tags_add.json; sourceTree = "<group>"; };
|
51D58758227F630B00900287 /* tags_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tags_add.json; sourceTree = "<group>"; };
|
||||||
51D58759227F630B00900287 /* tags_initial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tags_initial.json; sourceTree = "<group>"; };
|
51D58759227F630B00900287 /* tags_initial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tags_initial.json; sourceTree = "<group>"; };
|
||||||
51D5875D227F643C00900287 /* AccountFolderSyncTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountFolderSyncTest.swift; sourceTree = "<group>"; };
|
51D5875D227F643C00900287 /* AccountFolderSyncTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountFolderSyncTest.swift; sourceTree = "<group>"; };
|
||||||
|
51E3EB40229AF61B00645299 /* AccountError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountError.swift; sourceTree = "<group>"; };
|
||||||
51E490352288C37100C791F0 /* FeedbinDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinDate.swift; sourceTree = "<group>"; };
|
51E490352288C37100C791F0 /* FeedbinDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinDate.swift; sourceTree = "<group>"; };
|
||||||
51E59598228C77BC00FCC42B /* FeedbinUnreadEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinUnreadEntry.swift; sourceTree = "<group>"; };
|
51E59598228C77BC00FCC42B /* FeedbinUnreadEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinUnreadEntry.swift; sourceTree = "<group>"; };
|
||||||
51E5959A228C781500FCC42B /* FeedbinStarredEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinStarredEntry.swift; sourceTree = "<group>"; };
|
51E5959A228C781500FCC42B /* FeedbinStarredEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinStarredEntry.swift; sourceTree = "<group>"; };
|
||||||
|
@ -285,6 +287,7 @@
|
||||||
children = (
|
children = (
|
||||||
848935101F62486800CEBD24 /* Account.swift */,
|
848935101F62486800CEBD24 /* Account.swift */,
|
||||||
841974241F6DDCE4006346C4 /* AccountDelegate.swift */,
|
841974241F6DDCE4006346C4 /* AccountDelegate.swift */,
|
||||||
|
51E3EB40229AF61B00645299 /* AccountError.swift */,
|
||||||
846E77531F6F00E300A165E2 /* AccountManager.swift */,
|
846E77531F6F00E300A165E2 /* AccountManager.swift */,
|
||||||
84AF4EA3222CFDD100F6A800 /* AccountMetadata.swift */,
|
84AF4EA3222CFDD100F6A800 /* AccountMetadata.swift */,
|
||||||
84F73CF0202788D80000BCEF /* ArticleFetcher.swift */,
|
84F73CF0202788D80000BCEF /* ArticleFetcher.swift */,
|
||||||
|
@ -530,6 +533,7 @@
|
||||||
84B99C9F1FAE8D3200ECDEDB /* ContainerPath.swift in Sources */,
|
84B99C9F1FAE8D3200ECDEDB /* ContainerPath.swift in Sources */,
|
||||||
5133231122810EB200C30F19 /* FeedbinIcon.swift in Sources */,
|
5133231122810EB200C30F19 /* FeedbinIcon.swift in Sources */,
|
||||||
846E77501F6EF9C400A165E2 /* LocalAccountRefresher.swift in Sources */,
|
846E77501F6EF9C400A165E2 /* LocalAccountRefresher.swift in Sources */,
|
||||||
|
51E3EB41229AF61B00645299 /* AccountError.swift in Sources */,
|
||||||
51E59599228C77BC00FCC42B /* FeedbinUnreadEntry.swift in Sources */,
|
51E59599228C77BC00FCC42B /* FeedbinUnreadEntry.swift in Sources */,
|
||||||
5165D72822835F7800D9D53D /* FeedFinder.swift in Sources */,
|
5165D72822835F7800D9D53D /* FeedFinder.swift in Sources */,
|
||||||
51D58755227F53BE00900287 /* FeedbinTag.swift in Sources */,
|
51D58755227F53BE00900287 /* FeedbinTag.swift in Sources */,
|
||||||
|
|
|
@ -22,7 +22,7 @@ protocol AccountDelegate {
|
||||||
|
|
||||||
var refreshProgress: DownloadProgress { get }
|
var refreshProgress: DownloadProgress { get }
|
||||||
|
|
||||||
func refreshAll(for account: Account, completion: (() -> Void)?)
|
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void)
|
||||||
func sendArticleStatus(for account: Account, completion: @escaping (() -> Void))
|
func sendArticleStatus(for account: Account, completion: @escaping (() -> Void))
|
||||||
func refreshArticleStatus(for account: Account, completion: @escaping (() -> Void))
|
func refreshArticleStatus(for account: Account, completion: @escaping (() -> Void))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
//
|
||||||
|
// AccountError.swift
|
||||||
|
// Account
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 5/26/19.
|
||||||
|
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import RSWeb
|
||||||
|
|
||||||
|
public enum AccountError: LocalizedError {
|
||||||
|
|
||||||
|
case createErrorNotFound
|
||||||
|
case createErrorAlreadySubscribed
|
||||||
|
case opmlImportInProgress
|
||||||
|
case wrappedError(error: Error, account: Account)
|
||||||
|
|
||||||
|
public var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .opmlImportInProgress:
|
||||||
|
return NSLocalizedString("An OPML import for this account is already running.", comment: "Import running")
|
||||||
|
case .wrappedError(let error, let account):
|
||||||
|
switch error {
|
||||||
|
case TransportError.httpError(let status):
|
||||||
|
if status == 401 {
|
||||||
|
let localizedText = NSLocalizedString("Your \"%@\" credentials are invalid or expired.", comment: "Invalid or expired")
|
||||||
|
return NSString.localizedStringWithFormat(localizedText as NSString, account.nameForDisplay) as String
|
||||||
|
} else {
|
||||||
|
return unknownError(error, account)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return unknownError(error, account)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return NSLocalizedString("An unknown error occurred.", comment: "Unknown error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var recoverySuggestion: String? {
|
||||||
|
switch self {
|
||||||
|
case .wrappedError(let error, _):
|
||||||
|
switch error {
|
||||||
|
case TransportError.httpError(let status):
|
||||||
|
if status == 401 {
|
||||||
|
return NSLocalizedString("Please update your credentials for this account.", comment: "Try later")
|
||||||
|
} else {
|
||||||
|
return NSLocalizedString("Please try again later.", comment: "Try later")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return NSLocalizedString("Please try again later.", comment: "Try later")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return NSLocalizedString("Please try again later.", comment: "Try later")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func unknownError(_ error: Error, _ account: Account) -> String {
|
||||||
|
let localizedText = NSLocalizedString("An error occurred while processing the \"%@\" account: %@", comment: "Unknown error")
|
||||||
|
return NSString.localizedStringWithFormat(localizedText as NSString, account.nameForDisplay, error.localizedDescription) as String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ public final class AccountManager: UnreadCountProvider {
|
||||||
|
|
||||||
public static let shared = AccountManager()
|
public static let shared = AccountManager()
|
||||||
public let defaultAccount: Account
|
public let defaultAccount: Account
|
||||||
|
|
||||||
private let accountsFolder = RSDataSubfolder(nil, "Accounts")!
|
private let accountsFolder = RSDataSubfolder(nil, "Accounts")!
|
||||||
private var accountsDictionary = [String: Account]()
|
private var accountsDictionary = [String: Account]()
|
||||||
|
|
||||||
|
@ -145,9 +146,19 @@ public final class AccountManager: UnreadCountProvider {
|
||||||
return accountsDictionary[accountID]
|
return accountsDictionary[accountID]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func refreshAll() {
|
public func refreshAll(errorHandler: @escaping (Error) -> Void) {
|
||||||
|
|
||||||
activeAccounts.forEach { $0.refreshAll() }
|
activeAccounts.forEach { account in
|
||||||
|
account.refreshAll() { result in
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
break
|
||||||
|
case .failure(let error):
|
||||||
|
errorHandler(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func syncArticleStatusAll(completion: (() -> Void)? = nil) {
|
public func syncArticleStatusAll(completion: (() -> Void)? = nil) {
|
||||||
|
|
|
@ -78,7 +78,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
|
|
||||||
var refreshProgress = DownloadProgress(numberOfTasks: 0)
|
var refreshProgress = DownloadProgress(numberOfTasks: 0)
|
||||||
|
|
||||||
func refreshAll(for account: Account, completion: (() -> Void)? = nil) {
|
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
|
||||||
refreshProgress.addToNumberOfTasksAndRemaining(6)
|
refreshProgress.addToNumberOfTasksAndRemaining(6)
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
self.refreshMissingArticles(account) {
|
self.refreshMissingArticles(account) {
|
||||||
self.refreshProgress.clear()
|
self.refreshProgress.clear()
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion?()
|
completion(.success(()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,9 +99,9 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
|
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion?()
|
|
||||||
self.refreshProgress.clear()
|
self.refreshProgress.clear()
|
||||||
self.handleError(error)
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,8 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
os_log(.debug, log: self.log, "Import OPML failed.")
|
os_log(.debug, log: self.log, "Import OPML failed.")
|
||||||
self.opmlImportInProgress = false
|
self.opmlImportInProgress = false
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.failure(error))
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +241,8 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.failure(error))
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,7 +276,8 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
self.syncTaggings(account, taggings)
|
self.syncTaggings(account, taggings)
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.failure(error))
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,7 +305,8 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.failure(error))
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,7 +331,8 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.failure(error))
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,7 +361,8 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.failure(error))
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,7 +383,8 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.failure(error))
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,7 +411,8 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.failure(error))
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,7 +435,8 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
self.processRestoredFeed(for: account, feed: feed, editedName: editedName, folder: folder, completion: completion)
|
self.processRestoredFeed(for: account, feed: feed, editedName: editedName, folder: folder, completion: completion)
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.failure(error))
|
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||||
|
completion(.failure(wrappedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,14 +500,6 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
|
|
||||||
private extension FeedbinAccountDelegate {
|
private extension FeedbinAccountDelegate {
|
||||||
|
|
||||||
func handleError(_ error: Error) {
|
|
||||||
#if os(macOS)
|
|
||||||
NSApplication.shared.presentError(error)
|
|
||||||
#else
|
|
||||||
UIApplication.shared.presentError(error)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshAccount(_ account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
func refreshAccount(_ account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
|
||||||
caller.retrieveTags { result in
|
caller.retrieveTags { result in
|
||||||
|
|
|
@ -35,9 +35,9 @@ final class LocalAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalAccountDelegate doesn't wait for completion before calling the completion block
|
// LocalAccountDelegate doesn't wait for completion before calling the completion block
|
||||||
func refreshAll(for account: Account, completion: (() -> Void)? = nil) {
|
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
refresher.refreshFeeds(account.flattenedFeeds())
|
refresher.refreshFeeds(account.flattenedFeeds())
|
||||||
completion?()
|
completion(.success(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
func sendArticleStatus(for account: Account, completion: @escaping (() -> Void)) {
|
||||||
|
|
|
@ -334,7 +334,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
|
||||||
|
|
||||||
@IBAction func refreshAll(_ sender: Any?) {
|
@IBAction func refreshAll(_ sender: Any?) {
|
||||||
|
|
||||||
AccountManager.shared.refreshAll()
|
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func showAddFeedWindow(_ sender: Any?) {
|
@IBAction func showAddFeedWindow(_ sender: Any?) {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// ErrorHandler.swift
|
||||||
|
// NetNewsWire
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 5/26/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppKit
|
||||||
|
import Account
|
||||||
|
|
||||||
|
struct ErrorHandler {
|
||||||
|
|
||||||
|
public static func present(_ error: Error) {
|
||||||
|
NSApplication.shared.presentError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -88,7 +88,14 @@ class AccountsFeedbinWindowController: NSWindowController {
|
||||||
try self.account?.removeBasicCredentials()
|
try self.account?.removeBasicCredentials()
|
||||||
try self.account?.storeCredentials(credentials)
|
try self.account?.storeCredentials(credentials)
|
||||||
if newAccount {
|
if newAccount {
|
||||||
self.account?.refreshAll()
|
self.account?.refreshAll() { result in
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
break
|
||||||
|
case .failure(let error):
|
||||||
|
NSApplication.shared.presentError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -118,6 +118,8 @@
|
||||||
51C452B42265141B00C03939 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51C452B32265141B00C03939 /* WebKit.framework */; };
|
51C452B42265141B00C03939 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51C452B32265141B00C03939 /* WebKit.framework */; };
|
||||||
51C452B82265178500C03939 /* styleSheet.css in Resources */ = {isa = PBXBuildFile; fileRef = 51C452B72265178500C03939 /* styleSheet.css */; };
|
51C452B82265178500C03939 /* styleSheet.css in Resources */ = {isa = PBXBuildFile; fileRef = 51C452B72265178500C03939 /* styleSheet.css */; };
|
||||||
51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84702AA31FA27AC0006B8943 /* MarkStatusCommand.swift */; };
|
51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84702AA31FA27AC0006B8943 /* MarkStatusCommand.swift */; };
|
||||||
|
51E3EB33229AB02C00645299 /* ErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E3EB32229AB02C00645299 /* ErrorHandler.swift */; };
|
||||||
|
51E3EB3D229AB08300645299 /* ErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E3EB3C229AB08300645299 /* ErrorHandler.swift */; };
|
||||||
51E595A5228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */; };
|
51E595A5228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */; };
|
||||||
51E595A6228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */; };
|
51E595A6228CC36500FCC42B /* ArticleStatusSyncTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */; };
|
||||||
51E595AB228DF94C00FCC42B /* SettingsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51E595AA228DF94C00FCC42B /* SettingsTableViewCell.xib */; };
|
51E595AB228DF94C00FCC42B /* SettingsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51E595AA228DF94C00FCC42B /* SettingsTableViewCell.xib */; };
|
||||||
|
@ -711,6 +713,8 @@
|
||||||
51C4528B2265095F00C03939 /* AddFolderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderViewController.swift; sourceTree = "<group>"; };
|
51C4528B2265095F00C03939 /* AddFolderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderViewController.swift; sourceTree = "<group>"; };
|
||||||
51C452B32265141B00C03939 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; };
|
51C452B32265141B00C03939 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||||
51C452B72265178500C03939 /* styleSheet.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = styleSheet.css; sourceTree = "<group>"; };
|
51C452B72265178500C03939 /* styleSheet.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = styleSheet.css; sourceTree = "<group>"; };
|
||||||
|
51E3EB32229AB02C00645299 /* ErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorHandler.swift; sourceTree = "<group>"; };
|
||||||
|
51E3EB3C229AB08300645299 /* ErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorHandler.swift; sourceTree = "<group>"; };
|
||||||
51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleStatusSyncTimer.swift; sourceTree = "<group>"; };
|
51E595A4228CC36500FCC42B /* ArticleStatusSyncTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleStatusSyncTimer.swift; sourceTree = "<group>"; };
|
||||||
51E595AA228DF94C00FCC42B /* SettingsTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SettingsTableViewCell.xib; sourceTree = "<group>"; };
|
51E595AA228DF94C00FCC42B /* SettingsTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SettingsTableViewCell.xib; sourceTree = "<group>"; };
|
||||||
51E595AC228E1C2100FCC42B /* AddAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountViewController.swift; sourceTree = "<group>"; };
|
51E595AC228E1C2100FCC42B /* AddAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1550,6 +1554,7 @@
|
||||||
84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */,
|
84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */,
|
||||||
849EE70E203919360082A1EA /* AppAssets.swift */,
|
849EE70E203919360082A1EA /* AppAssets.swift */,
|
||||||
842E45DC1ED8C54B000A8B52 /* Browser.swift */,
|
842E45DC1ED8C54B000A8B52 /* Browser.swift */,
|
||||||
|
51E3EB32229AB02C00645299 /* ErrorHandler.swift */,
|
||||||
842E45E11ED8C681000A8B52 /* MainWindow */,
|
842E45E11ED8C681000A8B52 /* MainWindow */,
|
||||||
84BBB12A20142A4700F054F5 /* Inspector */,
|
84BBB12A20142A4700F054F5 /* Inspector */,
|
||||||
84C9FC6922629E1200D921D6 /* Preferences */,
|
84C9FC6922629E1200D921D6 /* Preferences */,
|
||||||
|
@ -1665,6 +1670,7 @@
|
||||||
840D617E2029031C009BC708 /* AppDelegate.swift */,
|
840D617E2029031C009BC708 /* AppDelegate.swift */,
|
||||||
51C45254226507D200C03939 /* AppAssets.swift */,
|
51C45254226507D200C03939 /* AppAssets.swift */,
|
||||||
51C45255226507D200C03939 /* AppDefaults.swift */,
|
51C45255226507D200C03939 /* AppDefaults.swift */,
|
||||||
|
51E3EB3C229AB08300645299 /* ErrorHandler.swift */,
|
||||||
5126EE96226CB48A00C22AFC /* NavigationStateController.swift */,
|
5126EE96226CB48A00C22AFC /* NavigationStateController.swift */,
|
||||||
51C4525D226508F600C03939 /* MasterFeed */,
|
51C4525D226508F600C03939 /* MasterFeed */,
|
||||||
51C4526D2265091600C03939 /* MasterTimeline */,
|
51C4526D2265091600C03939 /* MasterTimeline */,
|
||||||
|
@ -2344,6 +2350,7 @@
|
||||||
51C4529E22650A1900C03939 /* ImageDownloader.swift in Sources */,
|
51C4529E22650A1900C03939 /* ImageDownloader.swift in Sources */,
|
||||||
51C45292226509C800C03939 /* TodayFeedDelegate.swift in Sources */,
|
51C45292226509C800C03939 /* TodayFeedDelegate.swift in Sources */,
|
||||||
51C452A222650A1900C03939 /* RSHTMLMetadata+Extension.swift in Sources */,
|
51C452A222650A1900C03939 /* RSHTMLMetadata+Extension.swift in Sources */,
|
||||||
|
51E3EB3D229AB08300645299 /* ErrorHandler.swift in Sources */,
|
||||||
5183CCE5226F4DFA0010922C /* RefreshInterval.swift in Sources */,
|
5183CCE5226F4DFA0010922C /* RefreshInterval.swift in Sources */,
|
||||||
51EF0F7C2277919E0050506E /* TimelineNumberOfLinesViewController.swift in Sources */,
|
51EF0F7C2277919E0050506E /* TimelineNumberOfLinesViewController.swift in Sources */,
|
||||||
51C4529D22650A1000C03939 /* FaviconURLFinder.swift in Sources */,
|
51C4529D22650A1000C03939 /* FaviconURLFinder.swift in Sources */,
|
||||||
|
@ -2458,6 +2465,7 @@
|
||||||
849A97791ED9EC04007D329B /* TimelineStringFormatter.swift in Sources */,
|
849A97791ED9EC04007D329B /* TimelineStringFormatter.swift in Sources */,
|
||||||
84E185C3203BB12600F69BFA /* MultilineTextFieldSizer.swift in Sources */,
|
84E185C3203BB12600F69BFA /* MultilineTextFieldSizer.swift in Sources */,
|
||||||
8477ACBE22238E9500DF7F37 /* SearchFeedDelegate.swift in Sources */,
|
8477ACBE22238E9500DF7F37 /* SearchFeedDelegate.swift in Sources */,
|
||||||
|
51E3EB33229AB02C00645299 /* ErrorHandler.swift in Sources */,
|
||||||
8472058120142E8900AD578B /* FeedInspectorViewController.swift in Sources */,
|
8472058120142E8900AD578B /* FeedInspectorViewController.swift in Sources */,
|
||||||
5144EA382279FC6200D19003 /* AccountsAddLocalWindowController.swift in Sources */,
|
5144EA382279FC6200D19003 /* AccountsAddLocalWindowController.swift in Sources */,
|
||||||
84AD1EAA2031617300BC20B7 /* FolderPasteboardWriter.swift in Sources */,
|
84AD1EAA2031617300BC20B7 /* FolderPasteboardWriter.swift in Sources */,
|
||||||
|
|
|
@ -73,7 +73,7 @@ class AccountRefreshTimer {
|
||||||
lastTimedRefresh = Date()
|
lastTimedRefresh = Date()
|
||||||
update()
|
update()
|
||||||
|
|
||||||
AccountManager.shared.refreshAll()
|
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,10 +175,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
|
||||||
// If we haven't refreshed the database for 15 minutes, run a refresh automatically
|
// If we haven't refreshed the database for 15 minutes, run a refresh automatically
|
||||||
if let lastRefresh = AppDefaults.lastRefresh {
|
if let lastRefresh = AppDefaults.lastRefresh {
|
||||||
if Date() > lastRefresh.addingTimeInterval(15 * 60) {
|
if Date() > lastRefresh.addingTimeInterval(15 * 60) {
|
||||||
AccountManager.shared.refreshAll()
|
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AccountManager.shared.refreshAll()
|
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
|
||||||
startingUnreadCount = self.unreadCount
|
startingUnreadCount = self.unreadCount
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
AccountManager.shared.refreshAll()
|
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.log)
|
||||||
}
|
}
|
||||||
|
|
||||||
os_log("Accounts requested to begin refresh.", log: self.log, type: .debug)
|
os_log("Accounts requested to begin refresh.", log: self.log, type: .debug)
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
//
|
||||||
|
// ErrorHandler.swift
|
||||||
|
// NetNewsWire-iOS
|
||||||
|
//
|
||||||
|
// Created by Maurice Parker on 5/26/19.
|
||||||
|
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import RSCore
|
||||||
|
import os.log
|
||||||
|
|
||||||
|
struct ErrorHandler {
|
||||||
|
|
||||||
|
private static var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Account")
|
||||||
|
|
||||||
|
public static func present(_ error: Error) {
|
||||||
|
UIApplication.shared.presentError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func log(_ error: Error) {
|
||||||
|
os_log(.error, log: self.log, "%@", error.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -603,7 +603,7 @@ extension MasterFeedViewController: MasterFeedTableViewCellDelegate {
|
||||||
private extension MasterFeedViewController {
|
private extension MasterFeedViewController {
|
||||||
|
|
||||||
@objc private func refreshAccounts(_ sender: Any) {
|
@objc private func refreshAccounts(_ sender: Any) {
|
||||||
AccountManager.shared.refreshAll()
|
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
|
||||||
refreshControl?.endRefreshing()
|
refreshControl?.endRefreshing()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -351,7 +351,7 @@ class MasterTimelineViewController: ProgressTableViewController, UndoableCommand
|
||||||
private extension MasterTimelineViewController {
|
private extension MasterTimelineViewController {
|
||||||
|
|
||||||
@objc private func refreshAccounts(_ sender: Any) {
|
@objc private func refreshAccounts(_ sender: Any) {
|
||||||
AccountManager.shared.refreshAll()
|
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
|
||||||
refreshControl?.endRefreshing()
|
refreshControl?.endRefreshing()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,10 +72,19 @@ class FeedbinAccountViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
try self.account?.removeBasicCredentials()
|
try self.account?.removeBasicCredentials()
|
||||||
try self.account?.storeCredentials(credentials)
|
try self.account?.storeCredentials(credentials)
|
||||||
|
|
||||||
if newAccount {
|
if newAccount {
|
||||||
self.account?.refreshAll()
|
self.account?.refreshAll() { result in
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
break
|
||||||
|
case .failure(let error):
|
||||||
|
UIApplication.shared.presentError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.delegate?.dismiss(self)
|
self.delegate?.dismiss(self)
|
||||||
|
|
Loading…
Reference in New Issue