summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2021-04-08 12:25:59 +0200
committerAndrej Mihajlov <and@mullvad.net>2021-04-28 10:25:01 +0200
commitfb6e9174c1a3fdafe145d70b54001b1875e2974e (patch)
tree180e89d730497c0c3e437d17b68be4ced8eee54b
parent65c5103bdd5c3a31fbf06d222351b3b8dcc8b2ea (diff)
downloadmullvadvpn-fb6e9174c1a3fdafe145d70b54001b1875e2974e.tar.xz
mullvadvpn-fb6e9174c1a3fdafe145d70b54001b1875e2974e.zip
Account: add AccountObserver
-rw-r--r--ios/MullvadVPN/Account.swift71
-rw-r--r--ios/MullvadVPN/AccountViewController.swift28
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) {