Merge branch 'master' of https://github.com/brentsimmons/NetNewsWire
This commit is contained in:
commit
afd9783711
@ -399,6 +399,10 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||||||
opmlFile.save()
|
opmlFile.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func prepareForDeletion() {
|
||||||
|
delegate.accountWillBeDeleted(self)
|
||||||
|
}
|
||||||
|
|
||||||
func loadOPMLItems(_ items: [RSOPMLItem], parentFolder: Folder?) {
|
func loadOPMLItems(_ items: [RSOPMLItem], parentFolder: Folder?) {
|
||||||
var feedsToAdd = Set<WebFeed>()
|
var feedsToAdd = Set<WebFeed>()
|
||||||
|
|
||||||
|
@ -47,6 +47,8 @@ protocol AccountDelegate {
|
|||||||
// Called at the end of account’s init method.
|
// Called at the end of account’s init method.
|
||||||
func accountDidInitialize(_ account: Account)
|
func accountDidInitialize(_ account: Account)
|
||||||
|
|
||||||
|
func accountWillBeDeleted(_ account: Account)
|
||||||
|
|
||||||
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void)
|
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,8 @@ public final class AccountManager: UnreadCountProvider {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
account.prepareForDeletion()
|
||||||
|
|
||||||
accountsDictionary.removeValue(forKey: account.accountID)
|
accountsDictionary.removeValue(forKey: account.accountID)
|
||||||
account.isDeleted = true
|
account.isDeleted = true
|
||||||
|
|
||||||
|
@ -102,6 +102,7 @@ class FeedlyOperationTests: XCTestCase {
|
|||||||
func testOperationCancellationFlags() {
|
func testOperationCancellationFlags() {
|
||||||
let testOperation = TestOperation()
|
let testOperation = TestOperation()
|
||||||
testOperation.didCallMainExpectation = expectation(description: "Did Call Main")
|
testOperation.didCallMainExpectation = expectation(description: "Did Call Main")
|
||||||
|
testOperation.didCallMainExpectation?.isInverted = true
|
||||||
|
|
||||||
let completionExpectation = expectation(description: "Operation Completed")
|
let completionExpectation = expectation(description: "Operation Completed")
|
||||||
testOperation.completionBlock = {
|
testOperation.completionBlock = {
|
||||||
|
@ -67,11 +67,13 @@ class FeedlySyncAllOperationTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let syncCompletionExpectation = expectation(description: "Did Finish Sync")
|
let syncCompletionExpectation = expectation(description: "Did Finish Sync")
|
||||||
|
syncCompletionExpectation.isInverted = true
|
||||||
syncAll.syncCompletionHandler = { result in
|
syncAll.syncCompletionHandler = { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .success:
|
case .success:
|
||||||
XCTFail("Expected failure.")
|
XCTFail("Sync operation was cancelled, not successful.")
|
||||||
case .failure:
|
case .failure:
|
||||||
|
XCTFail("Sync operation should cancel silently.")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
syncCompletionExpectation.fulfill()
|
syncCompletionExpectation.fulfill()
|
||||||
|
@ -541,6 +541,9 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||||||
credentials = try? account.retrieveCredentials(type: .basic)
|
credentials = try? account.retrieveCredentials(type: .basic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func accountWillBeDeleted(_ account: Account) {
|
||||||
|
}
|
||||||
|
|
||||||
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||||
|
|
||||||
let caller = FeedbinAPICaller(transport: transport)
|
let caller = FeedbinAPICaller(transport: transport)
|
||||||
|
@ -486,6 +486,10 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||||||
operationQueue.addOperation(refreshAccessToken)
|
operationQueue.addOperation(refreshAccessToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func accountWillBeDeleted(_ account: Account) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||||
assertionFailure("An `account` instance should enqueue an \(FeedlyRefreshAccessTokenOperation.self) instead.")
|
assertionFailure("An `account` instance should enqueue an \(FeedlyRefreshAccessTokenOperation.self) instead.")
|
||||||
completion(.success(credentials))
|
completion(.success(credentials))
|
||||||
|
@ -21,8 +21,8 @@ class FeedlyOperation: Operation {
|
|||||||
func didFinish() {
|
func didFinish() {
|
||||||
assert(Thread.isMainThread)
|
assert(Thread.isMainThread)
|
||||||
assert(!isFinished, "Finished operation is attempting to finish again.")
|
assert(!isFinished, "Finished operation is attempting to finish again.")
|
||||||
self.isExecutingOperation = false
|
isExecutingOperation = false
|
||||||
self.isFinishedOperation = true
|
isFinishedOperation = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func didFinish(_ error: Error) {
|
func didFinish(_ error: Error) {
|
||||||
@ -33,16 +33,18 @@ class FeedlyOperation: Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func start() {
|
override func start() {
|
||||||
|
guard !isCancelled else {
|
||||||
|
isExecutingOperation = false
|
||||||
|
isFinishedOperation = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
isExecutingOperation = true
|
isExecutingOperation = true
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.main()
|
self.main()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func cancel() {
|
|
||||||
super.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
override var isExecuting: Bool {
|
override var isExecuting: Bool {
|
||||||
return isExecutingOperation
|
return isExecutingOperation
|
||||||
}
|
}
|
||||||
|
@ -94,10 +94,12 @@ final class FeedlySyncAllOperation: FeedlyOperation {
|
|||||||
os_log(.debug, log: log, "Cancelling sync %{public}@", syncUUID.uuidString)
|
os_log(.debug, log: log, "Cancelling sync %{public}@", syncUUID.uuidString)
|
||||||
self.operationQueue.cancelAllOperations()
|
self.operationQueue.cancelAllOperations()
|
||||||
|
|
||||||
syncCompletionHandler?(.failure(URLError(.cancelled)))
|
super.cancel()
|
||||||
syncCompletionHandler = nil
|
|
||||||
|
|
||||||
self.didFinish()
|
didFinish()
|
||||||
|
|
||||||
|
// Operation should silently cancel.
|
||||||
|
syncCompletionHandler = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
override func main() {
|
override func main() {
|
||||||
|
@ -96,13 +96,15 @@ final class FeedlySyncStarredArticlesOperation: FeedlyOperation, FeedlyOperation
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func cancel() {
|
override func cancel() {
|
||||||
|
os_log(.debug, log: log, "Canceling sync starred articles")
|
||||||
operationQueue.cancelAllOperations()
|
operationQueue.cancelAllOperations()
|
||||||
super.cancel()
|
super.cancel()
|
||||||
|
didFinish()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func main() {
|
override func main() {
|
||||||
guard !isCancelled else {
|
guard !isCancelled else {
|
||||||
didFinish()
|
// override of cancel calls didFinish().
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +112,11 @@ final class FeedlySyncStarredArticlesOperation: FeedlyOperation, FeedlyOperation
|
|||||||
}
|
}
|
||||||
|
|
||||||
func feedlyGetStreamContentsOperation(_ operation: FeedlyGetStreamContentsOperation, didGetContentsOf stream: FeedlyStream) {
|
func feedlyGetStreamContentsOperation(_ operation: FeedlyGetStreamContentsOperation, didGetContentsOf stream: FeedlyStream) {
|
||||||
|
guard !isCancelled else {
|
||||||
|
os_log(.debug, log: log, "Cancelled starred stream contents for %@", stream.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
entryProvider.addEntries(from: operation)
|
entryProvider.addEntries(from: operation)
|
||||||
os_log(.debug, log: log, "Collecting %i items from %@", stream.items.count, stream.id)
|
os_log(.debug, log: log, "Collecting %i items from %@", stream.items.count, stream.id)
|
||||||
|
|
||||||
|
@ -42,13 +42,15 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func cancel() {
|
override func cancel() {
|
||||||
|
os_log(.debug, log: log, "Canceling sync stream contents")
|
||||||
operationQueue.cancelAllOperations()
|
operationQueue.cancelAllOperations()
|
||||||
super.cancel()
|
super.cancel()
|
||||||
|
didFinish()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func main() {
|
override func main() {
|
||||||
guard !isCancelled else {
|
guard !isCancelled else {
|
||||||
didFinish()
|
// override of cancel calls didFinish().
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +94,11 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
|
|||||||
}
|
}
|
||||||
|
|
||||||
func feedlyGetStreamContentsOperation(_ operation: FeedlyGetStreamContentsOperation, didGetContentsOf stream: FeedlyStream) {
|
func feedlyGetStreamContentsOperation(_ operation: FeedlyGetStreamContentsOperation, didGetContentsOf stream: FeedlyStream) {
|
||||||
|
guard !isCancelled else {
|
||||||
|
os_log(.debug, log: log, "Cancelled requesting page for %@", resource.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
os_log(.debug, log: log, "Ingesting %i items from %@", stream.items.count, stream.id)
|
os_log(.debug, log: log, "Ingesting %i items from %@", stream.items.count, stream.id)
|
||||||
|
|
||||||
guard let continuation = stream.continuation else {
|
guard let continuation = stream.continuation else {
|
||||||
|
@ -77,13 +77,15 @@ final class FeedlySyncUnreadStatusesOperation: FeedlyOperation, FeedlyOperationD
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func cancel() {
|
override func cancel() {
|
||||||
|
os_log(.debug, log: log, "Canceling sync unread statuses")
|
||||||
operationQueue.cancelAllOperations()
|
operationQueue.cancelAllOperations()
|
||||||
super.cancel()
|
super.cancel()
|
||||||
|
didFinish()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func main() {
|
override func main() {
|
||||||
guard !isCancelled else {
|
guard !isCancelled else {
|
||||||
didFinish()
|
// override of cancel calls didFinish().
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +93,11 @@ final class FeedlySyncUnreadStatusesOperation: FeedlyOperation, FeedlyOperationD
|
|||||||
}
|
}
|
||||||
|
|
||||||
func feedlyGetStreamIdsOperation(_ operation: FeedlyGetStreamIdsOperation, didGet streamIds: FeedlyStreamIds) {
|
func feedlyGetStreamIdsOperation(_ operation: FeedlyGetStreamIdsOperation, didGet streamIds: FeedlyStreamIds) {
|
||||||
|
guard !isCancelled else {
|
||||||
|
os_log(.debug, log: log, "Cancelled unread stream ids.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
os_log(.debug, log: log, "Collecting %i unread article ids from %@", streamIds.ids.count, resource.id)
|
os_log(.debug, log: log, "Collecting %i unread article ids from %@", streamIds.ids.count, resource.id)
|
||||||
unreadEntryIdsProvider.addEntryIds(from: operation)
|
unreadEntryIdsProvider.addEntryIds(from: operation)
|
||||||
|
|
||||||
|
@ -196,6 +196,9 @@ final class LocalAccountDelegate: AccountDelegate {
|
|||||||
func accountDidInitialize(_ account: Account) {
|
func accountDidInitialize(_ account: Account) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func accountWillBeDeleted(_ account: Account) {
|
||||||
|
}
|
||||||
|
|
||||||
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: (Result<Credentials?, Error>) -> Void) {
|
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: (Result<Credentials?, Error>) -> Void) {
|
||||||
return completion(.success(nil))
|
return completion(.success(nil))
|
||||||
}
|
}
|
||||||
|
@ -418,6 +418,9 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
|||||||
credentials = try? account.retrieveCredentials(type: .readerAPIKey)
|
credentials = try? account.retrieveCredentials(type: .readerAPIKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func accountWillBeDeleted(_ account: Account) {
|
||||||
|
}
|
||||||
|
|
||||||
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||||
guard let endpoint = endpoint else {
|
guard let endpoint = endpoint else {
|
||||||
completion(.failure(TransportError.noURL))
|
completion(.failure(TransportError.noURL))
|
||||||
|
@ -28,6 +28,19 @@ final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate
|
|||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var hidesCredentialsButton: Bool {
|
||||||
|
guard let account = account else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
switch account.type {
|
||||||
|
case .onMyMac,
|
||||||
|
.feedly:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
@ -35,7 +48,7 @@ final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate
|
|||||||
typeLabel.stringValue = account?.defaultName ?? ""
|
typeLabel.stringValue = account?.defaultName ?? ""
|
||||||
nameTextField.stringValue = account?.name ?? ""
|
nameTextField.stringValue = account?.name ?? ""
|
||||||
activeButton.state = account?.isActive ?? false ? .on : .off
|
activeButton.state = account?.isActive ?? false ? .on : .off
|
||||||
credentialsButton.isHidden = account?.type ?? .onMyMac == .onMyMac
|
credentialsButton.isHidden = hidesCredentialsButton
|
||||||
}
|
}
|
||||||
|
|
||||||
func controlTextDidEndEditing(_ obj: Notification) {
|
func controlTextDidEndEditing(_ obj: Notification) {
|
||||||
@ -66,8 +79,6 @@ final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate
|
|||||||
accountsFreshRSSWindowController.account = account
|
accountsFreshRSSWindowController.account = account
|
||||||
accountsFreshRSSWindowController.runSheetOnWindow(self.view.window!)
|
accountsFreshRSSWindowController.runSheetOnWindow(self.view.window!)
|
||||||
accountsWindowController = accountsFreshRSSWindowController
|
accountsWindowController = accountsFreshRSSWindowController
|
||||||
case .feedly:
|
|
||||||
assertionFailure("Implement feedly logout window controller")
|
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -64,10 +64,20 @@ class AccountInspectorViewController: UITableViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func deleteAccount(_ sender: Any) {
|
@IBAction func deleteAccount(_ sender: Any) {
|
||||||
let title = NSLocalizedString("Delete Account", comment: "Delete Account")
|
guard let account = account else {
|
||||||
let message = NSLocalizedString("Are you sure you want to delete this account? This can not be undone.", comment: "Delete Account")
|
return
|
||||||
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
}
|
||||||
|
|
||||||
|
let title = NSLocalizedString("Delete Account", comment: "Delete Account")
|
||||||
|
let message: String = {
|
||||||
|
switch account.type {
|
||||||
|
case .feedly:
|
||||||
|
return NSLocalizedString("Are you sure you want to delete this account? NetNewsWire will no longer be able to access articles and feeds unless the account is added again.", comment: "Log Out and Delete Account")
|
||||||
|
default:
|
||||||
|
return NSLocalizedString("Are you sure you want to delete this account? This can not be undone.", comment: "Delete Account")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||||
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
|
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
|
||||||
let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel)
|
let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel)
|
||||||
alertController.addAction(cancelAction)
|
alertController.addAction(cancelAction)
|
||||||
@ -86,19 +96,31 @@ class AccountInspectorViewController: UITableViewController {
|
|||||||
|
|
||||||
present(alertController, animated: true)
|
present(alertController, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Table View
|
// MARK: Table View
|
||||||
|
|
||||||
extension AccountInspectorViewController {
|
extension AccountInspectorViewController {
|
||||||
|
|
||||||
|
var hidesCredentialsSection: Bool {
|
||||||
|
guard let account = account else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
switch account.type {
|
||||||
|
case .onMyMac,
|
||||||
|
.feedly:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||||
guard let account = account else { return 0 }
|
guard let account = account else { return 0 }
|
||||||
|
|
||||||
if account == AccountManager.shared.defaultAccount {
|
if account == AccountManager.shared.defaultAccount {
|
||||||
return 1
|
return 1
|
||||||
} else if account.type == .onMyMac {
|
} else if hidesCredentialsSection {
|
||||||
return 2
|
return 2
|
||||||
} else {
|
} else {
|
||||||
return super.numberOfSections(in: tableView)
|
return super.numberOfSections(in: tableView)
|
||||||
@ -124,7 +146,7 @@ extension AccountInspectorViewController {
|
|||||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
let cell: UITableViewCell
|
let cell: UITableViewCell
|
||||||
|
|
||||||
if indexPath.section == 1, let account = account, account.type == .onMyMac {
|
if indexPath.section == 1, hidesCredentialsSection {
|
||||||
cell = super.tableView(tableView, cellForRowAt: IndexPath(row: 0, section: 2))
|
cell = super.tableView(tableView, cellForRowAt: IndexPath(row: 0, section: 2))
|
||||||
} else {
|
} else {
|
||||||
cell = super.tableView(tableView, cellForRowAt: indexPath)
|
cell = super.tableView(tableView, cellForRowAt: indexPath)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user