Add account name to network error messages and prevent background iOS errors from displaying alerts

This commit is contained in:
Maurice Parker 2019-05-26 11:54:32 -05:00
parent b327d82004
commit c61949bc04
17 changed files with 185 additions and 61 deletions

View File

@ -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>) {

View File

@ -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 */,

View File

@ -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))

View File

@ -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
}
}

View File

@ -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) {

View File

@ -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

View File

@ -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)) {

View File

@ -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?) {

18
Mac/ErrorHandler.swift Normal file
View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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 */,

View File

@ -73,7 +73,7 @@ class AccountRefreshTimer {
lastTimedRefresh = Date() lastTimedRefresh = Date()
update() update()
AccountManager.shared.refreshAll() AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
} }

View File

@ -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)

25
iOS/ErrorHandler.swift Normal file
View File

@ -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)
}
}

View File

@ -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()
} }

View File

@ -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()
} }

View File

@ -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)