diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2021-04-08 12:25:59 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2021-04-28 10:25:01 +0200 |
| commit | fb6e9174c1a3fdafe145d70b54001b1875e2974e (patch) | |
| tree | 180e89d730497c0c3e437d17b68be4ced8eee54b | |
| parent | 65c5103bdd5c3a31fbf06d222351b3b8dcc8b2ea (diff) | |
| download | mullvadvpn-fb6e9174c1a3fdafe145d70b54001b1875e2974e.tar.xz mullvadvpn-fb6e9174c1a3fdafe145d70b54001b1875e2974e.zip | |
Account: add AccountObserver
| -rw-r--r-- | ios/MullvadVPN/Account.swift | 71 | ||||
| -rw-r--r-- | ios/MullvadVPN/AccountViewController.swift | 28 |
2 files changed, 74 insertions, 25 deletions
diff --git a/ios/MullvadVPN/Account.swift b/ios/MullvadVPN/Account.swift index 2146c65a2f..a3eea5157c 100644 --- a/ios/MullvadVPN/Account.swift +++ b/ios/MullvadVPN/Account.swift @@ -18,6 +18,37 @@ private enum UserDefaultsKeys: String { case accountExpiry = "accountExpiry" } +protocol AccountObserver: class { + func account(_ account: Account, didUpdateExpiry expiry: Date) + func account(_ account: Account, didLoginWithToken token: String, expiry: Date) + func accountDidLogout(_ account: Account) +} + +/// A type-erasing weak container for `AccountObserver` +private class AnyAccountObserver: AccountObserver, WeakObserverBox, Equatable { + private(set) weak var inner: AccountObserver? + + init<T: AccountObserver>(_ inner: T) { + self.inner = inner + } + + func account(_ account: Account, didUpdateExpiry expiry: Date) { + inner?.account(account, didUpdateExpiry: expiry) + } + + func account(_ account: Account, didLoginWithToken token: String, expiry: Date) { + inner?.account(account, didLoginWithToken: token, expiry: expiry) + } + + func accountDidLogout(_ account: Account) { + inner?.accountDidLogout(account) + } + + static func == (lhs: AnyAccountObserver, rhs: AnyAccountObserver) -> Bool { + return lhs.inner === rhs.inner + } +} + /// A class that groups the account related operations class Account { @@ -32,16 +63,11 @@ class Account { case tunnelConfiguration(TunnelManager.Error) } - /// A notification name used to broadcast the changes to account expiry - static let didUpdateAccountExpiryNotification = Notification.Name("didUpdateAccountExpiry") - - /// A notification userInfo key that holds the `Date` with the new account expiry - static let newAccountExpiryUserInfoKey = "newAccountExpiry" - /// A shared instance of `Account` static let shared = Account() private let logger = Logger(label: "Account") + private var observerList = ObserverList<AnyAccountObserver>() /// Returns true if user agreed to terms of service, otherwise false var isAgreedToTermsOfService: Bool { @@ -96,6 +122,11 @@ class Account { switch result { case .success(let response): self.setupTunnel(accountToken: response.token, expiry: response.expires) { (result) in + if case .success = result { + self.observerList.forEach { (observer) in + observer.account(self, didLoginWithToken: response.token, expiry: response.expires) + } + } completionHandler(result.map { response }) } @@ -117,6 +148,11 @@ class Account { switch result { case .success(let response): self.setupTunnel(accountToken: response.token, expiry: response.expires) { (result) in + if case .success = result { + self.observerList.forEach { (observer) in + observer.account(self, didLoginWithToken: response.token, expiry: response.expires) + } + } completionHandler(result.map { response }) } @@ -136,6 +172,9 @@ class Account { switch result { case .success: self.removeFromPreferences() + self.observerList.forEach { (observer) in + observer.accountDidLogout(self) + } finish(.success(())) @@ -168,7 +207,9 @@ class Account { switch result { case .success(let response): self.expiry = response.expires - self.postExpiryUpdateNotification(newExpiry: response.expires) + self.observerList.forEach { (observer) in + observer.account(self, didUpdateExpiry: response.expires) + } case .failure(let error): self.logger.error(chainedError: error, message: "Failed to update account expiry") @@ -200,14 +241,16 @@ class Account { preferences.removeObject(forKey: UserDefaultsKeys.accountToken.rawValue) preferences.removeObject(forKey: UserDefaultsKeys.accountExpiry.rawValue) + } + // MARK: - Account observation + + func addObserver<T: AccountObserver>(_ observer: T) { + observerList.append(AnyAccountObserver(observer)) } - fileprivate func postExpiryUpdateNotification(newExpiry: Date) { - NotificationCenter.default.post( - name: Self.didUpdateAccountExpiryNotification, - object: self, userInfo: [Self.newAccountExpiryUserInfoKey: newExpiry] - ) + func removeObserver<T: AccountObserver>(_ observer: T) { + observerList.remove(AnyAccountObserver(observer)) } } @@ -229,7 +272,9 @@ extension Account: AppStorePaymentObserver { // Make sure that payment corresponds to the active account token if self.token == accountToken { self.expiry = newExpiry - self.postExpiryUpdateNotification(newExpiry: newExpiry) + self.observerList.forEach { (observer) in + observer.account(self, didUpdateExpiry: newExpiry) + } } finish() diff --git a/ios/MullvadVPN/AccountViewController.swift b/ios/MullvadVPN/AccountViewController.swift index 03263ff6f1..dffa1cda48 100644 --- a/ios/MullvadVPN/AccountViewController.swift +++ b/ios/MullvadVPN/AccountViewController.swift @@ -14,7 +14,7 @@ protocol AccountViewControllerDelegate: class { func accountViewControllerDidLogout(_ controller: AccountViewController) } -class AccountViewController: UIViewController, AppStorePaymentObserver { +class AccountViewController: UIViewController, AppStorePaymentObserver, AccountObserver { @IBOutlet var accountTokenButton: UIButton! @IBOutlet var purchaseButton: InAppPurchaseButton! @@ -24,7 +24,6 @@ class AccountViewController: UIViewController, AppStorePaymentObserver { @IBOutlet var activityIndicator: SpinnerActivityIndicatorView! private var copyToPasteboardWork: DispatchWorkItem? - private var accountExpiryObserver: NSObjectProtocol? private var pendingPayment: SKPayment? private let alertPresenter = AlertPresenter() @@ -59,16 +58,7 @@ class AccountViewController: UIViewController, AppStorePaymentObserver { navigationItem.title = NSLocalizedString("Account", comment: "Navigation title") AppStorePaymentManager.shared.addPaymentObserver(self) - - accountExpiryObserver = NotificationCenter.default.addObserver( - forName: Account.didUpdateAccountExpiryNotification, - object: Account.shared, - queue: OperationQueue.main) { [weak self] (note) in - guard let newExpiryDate = note - .userInfo?[Account.newAccountExpiryUserInfoKey] as? Date else { return } - - self?.updateAccountExpiry(expiryDate: newExpiryDate) - } + Account.shared.addObserver(self) accountTokenButton.setTitle(Account.shared.formattedToken, for: .normal) @@ -266,6 +256,20 @@ class AccountViewController: UIViewController, AppStorePaymentObserver { } } + // MARK: - AccountObserver + + func account(_ account: Account, didUpdateExpiry expiry: Date) { + updateAccountExpiry(expiryDate: expiry) + } + + func account(_ account: Account, didLoginWithToken token: String, expiry: Date) { + // no-op + } + + func accountDidLogout(_ account: Account) { + // no-op + } + // MARK: - AppStorePaymentObserver func appStorePaymentManager(_ manager: AppStorePaymentManager, transaction: SKPaymentTransaction, accountToken: String?, didFailWithError error: AppStorePaymentManager.Error) { |
