From 9d9ea565f1bb290c2f4e06c5a8e0d24519fcded2 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Wed, 16 Sep 2020 17:52:00 -0400 Subject: [PATCH] Fix crash opening Preferences with deleted accounts --- Tusker/Controllers/MastodonController.swift | 29 +++++++++++-------- .../Onboarding/OnboardingViewController.swift | 20 +++++++++---- .../Preferences/LocalAccountAvatarView.swift | 3 +- .../Profile/MyProfileViewController.swift | 4 ++- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/Tusker/Controllers/MastodonController.swift b/Tusker/Controllers/MastodonController.swift index e7ee37f623..5723f4df9e 100644 --- a/Tusker/Controllers/MastodonController.swift +++ b/Tusker/Controllers/MastodonController.swift @@ -84,23 +84,28 @@ class MastodonController { } } - func getOwnAccount(completion: ((Account) -> Void)? = nil) { + func getOwnAccount(completion: ((Result) -> Void)? = nil) { if account != nil { - completion?(account) + completion?(.success(account)) } else { let request = Client.getSelfAccount() run(request) { response in - guard case let .success(account, _) = response else { fatalError() } - self.account = account - self.persistentContainer.backgroundContext.perform { - if let accountMO = self.persistentContainer.account(for: account.id, in: self.persistentContainer.backgroundContext) { - accountMO.updateFrom(apiAccount: account, container: self.persistentContainer) - } else { - // the first time the user's account is added to the store, - // increment its reference count so that it's never removed - self.persistentContainer.addOrUpdate(account: account, incrementReferenceCount: true) + switch response { + case let .failure(error): + completion?(.failure(error)) + + case let .success(account, _): + self.account = account + self.persistentContainer.backgroundContext.perform { + if let accountMO = self.persistentContainer.account(for: account.id, in: self.persistentContainer.backgroundContext) { + accountMO.updateFrom(apiAccount: account, container: self.persistentContainer) + } else { + // the first time the user's account is added to the store, + // increment its reference count so that it's never removed + self.persistentContainer.addOrUpdate(account: account, incrementReferenceCount: true) + } + completion?(.success(account)) } - completion?(account) } } } diff --git a/Tusker/Screens/Onboarding/OnboardingViewController.swift b/Tusker/Screens/Onboarding/OnboardingViewController.swift index acc44658a2..e660fba6f6 100644 --- a/Tusker/Screens/Onboarding/OnboardingViewController.swift +++ b/Tusker/Screens/Onboarding/OnboardingViewController.swift @@ -70,13 +70,21 @@ extension OnboardingViewController: InstanceSelectorTableViewControllerDelegate let tempAccountInfo = LocalData.UserAccountInfo(id: "temp", instanceURL: instanceURL, clientID: clientID, clientSecret: clientSecret, username: nil, accessToken: accessToken) mastodonController.accountInfo = tempAccountInfo - mastodonController.getOwnAccount { (account) in + mastodonController.getOwnAccount { (result) in DispatchQueue.main.async { - // this needs to happen on the main thread because it publishes a new value for the ObservableObject - let accountInfo = LocalData.shared.addAccount(instanceURL: instanceURL, clientID: clientID, clientSecret: clientSecret, username: account.username, accessToken: accessToken) - mastodonController.accountInfo = accountInfo - - self.onboardingDelegate?.didFinishOnboarding(account: accountInfo) + switch result { + case let .failure(error): + let alert = UIAlertController(title: "Unable to Verify Credentials", message: "Your account could not be fetched at this time: \(error.localizedDescription)", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil)) + self.present(alert, animated: true) + + case let .success(account): + // this needs to happen on the main thread because it publishes a new value for the ObservableObject + let accountInfo = LocalData.shared.addAccount(instanceURL: instanceURL, clientID: clientID, clientSecret: clientSecret, username: account.username, accessToken: accessToken) + mastodonController.accountInfo = accountInfo + + self.onboardingDelegate?.didFinishOnboarding(account: accountInfo) + } } } } diff --git a/Tusker/Screens/Preferences/LocalAccountAvatarView.swift b/Tusker/Screens/Preferences/LocalAccountAvatarView.swift index 19acc9ce29..d039b2a538 100644 --- a/Tusker/Screens/Preferences/LocalAccountAvatarView.swift +++ b/Tusker/Screens/Preferences/LocalAccountAvatarView.swift @@ -36,7 +36,8 @@ struct LocalAccountAvatarView: View { func loadImage() { let controller = MastodonController.getForAccount(localAccountInfo) - controller.getOwnAccount { (account) in + controller.getOwnAccount { (result) in + guard case let .success(account) = result else { return } _ = ImageCache.avatars.get(account.avatar) { (data) in if let data = data, let image = UIImage(data: data) { DispatchQueue.main.async { diff --git a/Tusker/Screens/Profile/MyProfileViewController.swift b/Tusker/Screens/Profile/MyProfileViewController.swift index c229c8b9ad..1417cd1ba7 100644 --- a/Tusker/Screens/Profile/MyProfileViewController.swift +++ b/Tusker/Screens/Profile/MyProfileViewController.swift @@ -16,7 +16,9 @@ class MyProfileViewController: ProfileViewController { title = "My Profile" tabBarItem.image = UIImage(systemName: "person.fill") - mastodonController.getOwnAccount { (account) in + mastodonController.getOwnAccount { (result) in + guard case let .success(account) = result else { return } + DispatchQueue.main.async { self.accountID = account.id }