This commit is contained in:
Maurice Parker 2019-11-14 20:11:50 -06:00
commit afd9783711
16 changed files with 104 additions and 22 deletions

View File

@ -399,6 +399,10 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
opmlFile.save()
}
public func prepareForDeletion() {
delegate.accountWillBeDeleted(self)
}
func loadOPMLItems(_ items: [RSOPMLItem], parentFolder: Folder?) {
var feedsToAdd = Set<WebFeed>()

View File

@ -46,6 +46,8 @@ protocol AccountDelegate {
// Called at the end of accounts init method.
func accountDidInitialize(_ account: Account)
func accountWillBeDeleted(_ account: Account)
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void)

View File

@ -138,6 +138,8 @@ public final class AccountManager: UnreadCountProvider {
return
}
account.prepareForDeletion()
accountsDictionary.removeValue(forKey: account.accountID)
account.isDeleted = true

View File

@ -102,6 +102,7 @@ class FeedlyOperationTests: XCTestCase {
func testOperationCancellationFlags() {
let testOperation = TestOperation()
testOperation.didCallMainExpectation = expectation(description: "Did Call Main")
testOperation.didCallMainExpectation?.isInverted = true
let completionExpectation = expectation(description: "Operation Completed")
testOperation.completionBlock = {

View File

@ -67,11 +67,13 @@ class FeedlySyncAllOperationTests: XCTestCase {
}
let syncCompletionExpectation = expectation(description: "Did Finish Sync")
syncCompletionExpectation.isInverted = true
syncAll.syncCompletionHandler = { result in
switch result {
case .success:
XCTFail("Expected failure.")
XCTFail("Sync operation was cancelled, not successful.")
case .failure:
XCTFail("Sync operation should cancel silently.")
break
}
syncCompletionExpectation.fulfill()

View File

@ -541,6 +541,9 @@ final class FeedbinAccountDelegate: AccountDelegate {
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) {
let caller = FeedbinAPICaller(transport: transport)

View File

@ -486,6 +486,10 @@ final class FeedlyAccountDelegate: AccountDelegate {
operationQueue.addOperation(refreshAccessToken)
}
func accountWillBeDeleted(_ account: Account) {
}
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.")
completion(.success(credentials))

View File

@ -21,8 +21,8 @@ class FeedlyOperation: Operation {
func didFinish() {
assert(Thread.isMainThread)
assert(!isFinished, "Finished operation is attempting to finish again.")
self.isExecutingOperation = false
self.isFinishedOperation = true
isExecutingOperation = false
isFinishedOperation = true
}
func didFinish(_ error: Error) {
@ -33,16 +33,18 @@ class FeedlyOperation: Operation {
}
override func start() {
guard !isCancelled else {
isExecutingOperation = false
isFinishedOperation = true
return
}
isExecutingOperation = true
DispatchQueue.main.async {
self.main()
}
}
override func cancel() {
super.cancel()
}
override var isExecuting: Bool {
return isExecutingOperation
}

View File

@ -94,10 +94,12 @@ final class FeedlySyncAllOperation: FeedlyOperation {
os_log(.debug, log: log, "Cancelling sync %{public}@", syncUUID.uuidString)
self.operationQueue.cancelAllOperations()
syncCompletionHandler?(.failure(URLError(.cancelled)))
syncCompletionHandler = nil
super.cancel()
self.didFinish()
didFinish()
// Operation should silently cancel.
syncCompletionHandler = nil
}
override func main() {

View File

@ -96,13 +96,15 @@ final class FeedlySyncStarredArticlesOperation: FeedlyOperation, FeedlyOperation
}
override func cancel() {
os_log(.debug, log: log, "Canceling sync starred articles")
operationQueue.cancelAllOperations()
super.cancel()
didFinish()
}
override func main() {
guard !isCancelled else {
didFinish()
// override of cancel calls didFinish().
return
}
@ -110,6 +112,11 @@ final class FeedlySyncStarredArticlesOperation: FeedlyOperation, FeedlyOperation
}
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)
os_log(.debug, log: log, "Collecting %i items from %@", stream.items.count, stream.id)

View File

@ -42,13 +42,15 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
}
override func cancel() {
os_log(.debug, log: log, "Canceling sync stream contents")
operationQueue.cancelAllOperations()
super.cancel()
didFinish()
}
override func main() {
guard !isCancelled else {
didFinish()
// override of cancel calls didFinish().
return
}
@ -92,6 +94,11 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
}
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)
guard let continuation = stream.continuation else {

View File

@ -77,13 +77,15 @@ final class FeedlySyncUnreadStatusesOperation: FeedlyOperation, FeedlyOperationD
}
override func cancel() {
os_log(.debug, log: log, "Canceling sync unread statuses")
operationQueue.cancelAllOperations()
super.cancel()
didFinish()
}
override func main() {
guard !isCancelled else {
didFinish()
// override of cancel calls didFinish().
return
}
@ -91,6 +93,11 @@ final class FeedlySyncUnreadStatusesOperation: FeedlyOperation, FeedlyOperationD
}
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)
unreadEntryIdsProvider.addEntryIds(from: operation)

View File

@ -195,6 +195,9 @@ final class LocalAccountDelegate: AccountDelegate {
func accountDidInitialize(_ account: Account) {
}
func accountWillBeDeleted(_ account: Account) {
}
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: (Result<Credentials?, Error>) -> Void) {
return completion(.success(nil))

View File

@ -418,6 +418,9 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
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) {
guard let endpoint = endpoint else {
completion(.failure(TransportError.noURL))

View File

@ -28,6 +28,19 @@ final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate
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() {
super.viewDidLoad()
@ -35,7 +48,7 @@ final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate
typeLabel.stringValue = account?.defaultName ?? ""
nameTextField.stringValue = account?.name ?? ""
activeButton.state = account?.isActive ?? false ? .on : .off
credentialsButton.isHidden = account?.type ?? .onMyMac == .onMyMac
credentialsButton.isHidden = hidesCredentialsButton
}
func controlTextDidEndEditing(_ obj: Notification) {
@ -66,8 +79,6 @@ final class AccountsDetailViewController: NSViewController, NSTextFieldDelegate
accountsFreshRSSWindowController.account = account
accountsFreshRSSWindowController.runSheetOnWindow(self.view.window!)
accountsWindowController = accountsFreshRSSWindowController
case .feedly:
assertionFailure("Implement feedly logout window controller")
break
default:
break

View File

@ -64,10 +64,20 @@ class AccountInspectorViewController: UITableViewController {
}
@IBAction func deleteAccount(_ sender: Any) {
let title = NSLocalizedString("Delete Account", comment: "Delete Account")
let message = 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)
guard let account = account else {
return
}
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 cancelAction = UIAlertAction(title: cancelTitle, style: .cancel)
alertController.addAction(cancelAction)
@ -86,19 +96,31 @@ class AccountInspectorViewController: UITableViewController {
present(alertController, animated: true)
}
}
// MARK: Table View
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 {
guard let account = account else { return 0 }
if account == AccountManager.shared.defaultAccount {
return 1
} else if account.type == .onMyMac {
} else if hidesCredentialsSection {
return 2
} else {
return super.numberOfSections(in: tableView)
@ -124,7 +146,7 @@ extension AccountInspectorViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> 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))
} else {
cell = super.tableView(tableView, cellForRowAt: indexPath)