summaryrefslogtreecommitdiffhomepage
path: root/ios
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-11-01 06:56:18 +0100
committerAndrej Mihajlov <and@mullvad.net>2022-11-02 14:05:28 +0100
commit6127bb3da472abb5bcc37e52d935383ea0ef9569 (patch)
treeb881bc261044c74bf15c006b8a3840c76fee9f70 /ios
parentb989773b5496365a1174d359ef48433629f948e3 (diff)
downloadmullvadvpn-6127bb3da472abb5bcc37e52d935383ea0ef9569.tar.xz
mullvadvpn-6127bb3da472abb5bcc37e52d935383ea0ef9569.zip
Refactor out of time controller and add interactor
Diffstat (limited to 'ios')
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj4
-rw-r--r--ios/MullvadVPN/OutOfTimeInteractor.swift84
-rw-r--r--ios/MullvadVPN/OutOfTimeViewController.swift364
-rw-r--r--ios/MullvadVPN/SceneDelegate.swift27
4 files changed, 261 insertions, 218 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index b092636d2d..24e2e0448c 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -136,6 +136,7 @@
585CA70F25F8C44600B47C62 /* UIMetrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585CA70E25F8C44600B47C62 /* UIMetrics.swift */; };
585E820327F3285E00939F0E /* SendStoreReceiptOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585E820227F3285E00939F0E /* SendStoreReceiptOperation.swift */; };
5862805422428EF100F5A6E1 /* TranslucentButtonBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */; };
+ 5867770E29096984006F721F /* OutOfTimeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5867770D29096984006F721F /* OutOfTimeInteractor.swift */; };
5867771429097BCD006F721F /* PaymentState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5867771329097BCD006F721F /* PaymentState.swift */; };
5867771629097C5B006F721F /* ProductState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5867771529097C5B006F721F /* ProductState.swift */; };
5868585524054096000B8131 /* AppButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5868585424054096000B8131 /* AppButton.swift */; };
@@ -623,6 +624,7 @@
585E820227F3285E00939F0E /* SendStoreReceiptOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendStoreReceiptOperation.swift; sourceTree = "<group>"; };
5862805322428EF100F5A6E1 /* TranslucentButtonBlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranslucentButtonBlurView.swift; sourceTree = "<group>"; };
5866F39B2243B82D00168AE5 /* MullvadVPN.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MullvadVPN.entitlements; sourceTree = "<group>"; };
+ 5867770D29096984006F721F /* OutOfTimeInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutOfTimeInteractor.swift; sourceTree = "<group>"; };
5867771329097BCD006F721F /* PaymentState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentState.swift; sourceTree = "<group>"; };
5867771529097C5B006F721F /* ProductState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductState.swift; sourceTree = "<group>"; };
5868585424054096000B8131 /* AppButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppButton.swift; sourceTree = "<group>"; };
@@ -1282,6 +1284,7 @@
586A950B2901250A007BAF2B /* Operations */,
E1187ABB289BBB850024E748 /* OutOfTimeContentView.swift */,
E1187ABA289BBB850024E748 /* OutOfTimeViewController.swift */,
+ 5867770D29096984006F721F /* OutOfTimeInteractor.swift */,
584D26C3270C855A004EA533 /* PreferencesDataSource.swift */,
587EB6732714520600123C75 /* PreferencesDataSourceDelegate.swift */,
58ACF6482655365700ACE4B7 /* PreferencesViewController.swift */,
@@ -2075,6 +2078,7 @@
582BB1B3229574F40055B6EF /* SettingsAccountCell.swift in Sources */,
588527B2276B3F0700BAA373 /* LoadTunnelConfigurationOperation.swift in Sources */,
58F1311527E0B2AB007AC5BC /* Result+Extensions.swift in Sources */,
+ 5867770E29096984006F721F /* OutOfTimeInteractor.swift in Sources */,
5872631B283F6EAB00E14ADF /* Intents.intentdefinition in Sources */,
58F8AC0E25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift in Sources */,
58CCA010224249A1004F3011 /* ConnectViewController.swift in Sources */,
diff --git a/ios/MullvadVPN/OutOfTimeInteractor.swift b/ios/MullvadVPN/OutOfTimeInteractor.swift
new file mode 100644
index 0000000000..068a299c3e
--- /dev/null
+++ b/ios/MullvadVPN/OutOfTimeInteractor.swift
@@ -0,0 +1,84 @@
+//
+// OutOfTimeInteractor.swift
+// MullvadVPN
+//
+// Created by pronebird on 26/10/2022.
+// Copyright © 2022 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import MullvadREST
+import MullvadTypes
+import Operations
+import StoreKit
+
+final class OutOfTimeInteractor {
+ private let storePaymentManager: StorePaymentManager
+ private let tunnelManager: TunnelManager
+
+ var didReceivePaymentEvent: ((StorePaymentEvent) -> Void)?
+ var didReceiveTunnelStatus: ((TunnelStatus) -> Void)?
+
+ private var tunnelObserver: TunnelObserver?
+ private var paymentObserver: StorePaymentObserver?
+
+ init(storePaymentManager: StorePaymentManager, tunnelManager: TunnelManager) {
+ self.storePaymentManager = storePaymentManager
+ self.tunnelManager = tunnelManager
+
+ let tunnelObserver = TunnelBlockObserver(
+ didUpdateTunnelStatus: { [weak self] manager, tunnelStatus in
+ self?.didReceiveTunnelStatus?(tunnelStatus)
+ }
+ )
+
+ let paymentObserver = StorePaymentBlockObserver { [weak self] manager, event in
+ self?.didReceivePaymentEvent?(event)
+ }
+
+ tunnelManager.addObserver(tunnelObserver)
+ storePaymentManager.addPaymentObserver(paymentObserver)
+
+ self.tunnelObserver = tunnelObserver
+ self.paymentObserver = paymentObserver
+ }
+
+ var tunnelStatus: TunnelStatus {
+ return tunnelManager.tunnelStatus
+ }
+
+ var deviceState: DeviceState {
+ return tunnelManager.deviceState
+ }
+
+ func stopTunnel() {
+ tunnelManager.stopTunnel()
+ }
+
+ func addPayment(_ payment: SKPayment, for accountNumber: String) {
+ storePaymentManager.addPayment(payment, for: accountNumber)
+ }
+
+ func restorePurchases(
+ for accountNumber: String,
+ completionHandler: @escaping (OperationCompletion<
+ REST.CreateApplePaymentResponse,
+ StorePaymentManagerError
+ >) -> Void
+ ) -> Cancellable {
+ return storePaymentManager.restorePurchases(
+ for: accountNumber,
+ completionHandler: completionHandler
+ )
+ }
+
+ func requestProducts(
+ with productIdentifiers: Set<StoreSubscription>,
+ completionHandler: @escaping (OperationCompletion<SKProductsResponse, Swift.Error>) -> Void
+ ) -> Cancellable {
+ return storePaymentManager.requestProducts(
+ with: productIdentifiers,
+ completionHandler: completionHandler
+ )
+ }
+}
diff --git a/ios/MullvadVPN/OutOfTimeViewController.swift b/ios/MullvadVPN/OutOfTimeViewController.swift
index 0a037bf281..1de9fde687 100644
--- a/ios/MullvadVPN/OutOfTimeViewController.swift
+++ b/ios/MullvadVPN/OutOfTimeViewController.swift
@@ -12,40 +12,62 @@ import Operations
import StoreKit
import UIKit
-class OutOfTimeViewController: UIViewController {
- weak var delegate: SettingsButtonInteractionDelegate?
+protocol OutOfTimeViewControllerDelegate: AnyObject {
+ func outOfTimeViewControllerDidBeginPayment(_ controller: OutOfTimeViewController)
+ func outOfTimeViewControllerDidEndPayment(_ controller: OutOfTimeViewController)
+}
- private var productState: ProductState = .none
- private var paymentState: PaymentState = .none
+class OutOfTimeViewController: UIViewController, RootContainment {
+ weak var delegate: OutOfTimeViewControllerDelegate?
+ private let interactor: OutOfTimeInteractor
private let alertPresenter = AlertPresenter()
+ private var productState: ProductState = .none {
+ didSet {
+ applyViewState()
+ }
+ }
+
+ private var paymentState: PaymentState = .none {
+ didSet {
+ applyViewState()
+ notifyDelegate(oldValue)
+ }
+ }
+
private lazy var contentView = OutOfTimeContentView()
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
- private var tunnelState: TunnelState = .disconnected {
- didSet {
- setNeedsHeaderBarStyleAppearanceUpdate()
- applyViewState(animated: true)
- }
+ var preferredHeaderBarPresentation: HeaderBarPresentation {
+ let tunnelState = interactor.tunnelStatus.state
+
+ return HeaderBarPresentation(
+ style: tunnelState.isSecured ? .secured : .unsecured,
+ showsDivider: false
+ )
}
- override func viewDidLoad() {
- setUpContentView()
- setUpButtonTargets()
- setUpInAppPurchases()
- addObservers()
- tunnelState = TunnelManager.shared.tunnelStatus.state
+ var prefersHeaderBarHidden: Bool {
+ return false
+ }
+
+ init(interactor: OutOfTimeInteractor) {
+ self.interactor = interactor
+
+ super.init(nibName: nil, bundle: nil)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
}
-}
-// MARK: - Private Functions
+ override func viewDidLoad() {
+ super.viewDidLoad()
-private extension OutOfTimeViewController {
- func setUpContentView() {
view.addSubview(contentView)
NSLayoutConstraint.activate([
@@ -54,15 +76,12 @@ private extension OutOfTimeViewController {
contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
- }
- func setUpButtonTargets() {
contentView.disconnectButton.addTarget(
self,
action: #selector(handleDisconnect(_:)),
for: .touchUpInside
)
-
contentView.purchaseButton.addTarget(
self,
action: #selector(doPurchase),
@@ -73,187 +92,139 @@ private extension OutOfTimeViewController {
action: #selector(restorePurchases),
for: .touchUpInside
)
- }
- @objc func handleDisconnect(_ sender: Any) {
- TunnelManager.shared.stopTunnel()
- }
-
- func addObservers() {
- StorePaymentManager.shared.addPaymentObserver(self)
- TunnelManager.shared.addObserver(self)
- }
-
- func setEnableUserInteraction(_ enableUserInteraction: Bool) {
- [contentView.purchaseButton, contentView.restoreButton]
- .forEach { button in
- button?.isEnabled = enableUserInteraction
- }
-
- view.isUserInteractionEnabled = enableUserInteraction
- }
-
- func bodyText(for tunnelState: TunnelState) -> String {
- if tunnelState.isSecured {
- return NSLocalizedString(
- "OUT_OF_TIME_BODY_CONNECTED",
- tableName: "OutOfTime",
- value: "You have no more VPN time left on this account. To add more, you will need to disconnect and access the Internet with an unsecure connection.",
- comment: ""
- )
- } else {
- return NSLocalizedString(
- "OUT_OF_TIME_BODY_DISCONNECTED",
- tableName: "OutOfTime",
- value: "You have no more VPN time left on this account. Either buy credit on our website or redeem a voucher.",
- comment: ""
- )
+ interactor.didReceivePaymentEvent = { [weak self] event in
+ self?.didReceivePaymentEvent(event)
}
- }
-}
-// MARK: - In App Purchases
+ interactor.didReceiveTunnelStatus = { [weak self] tunnelStatus in
+ self?.setNeedsHeaderBarStyleAppearanceUpdate()
+ }
-private extension OutOfTimeViewController {
- func setUpInAppPurchases() {
if StorePaymentManager.canMakePayments {
requestStoreProducts()
} else {
- setProductState(.cannotMakePurchases, animated: false)
+ productState = .cannotMakePurchases
}
}
- func requestStoreProducts() {
- let productKind = StoreSubscription.thirtyDays
-
- setProductState(.fetching(productKind), animated: true)
+ // MARK: - Private
- _ = StorePaymentManager.shared
- .requestProducts(with: [productKind]) { [weak self] completion in
- let productState: ProductState = completion.value?.products.first
- .map { .received($0) } ?? .failed
-
- self?.setProductState(productState, animated: true)
- }
- }
-
- func setPaymentState(_ newState: PaymentState, animated: Bool) {
- paymentState = newState
+ private func requestStoreProducts() {
+ let productKind = StoreSubscription.thirtyDays
- applyViewState(animated: animated)
- }
+ productState = .fetching(productKind)
- func setProductState(_ newState: ProductState, animated: Bool) {
- productState = newState
+ _ = interactor.requestProducts(with: [productKind]) { [weak self] completion in
+ let productState: ProductState = completion.value?.products.first
+ .map { .received($0) } ?? .failed
- applyViewState(animated: animated)
+ self?.productState = productState
+ }
}
- func applyViewState(animated: Bool) {
+ private func applyViewState() {
+ let tunnelState = interactor.tunnelStatus.state
let isInteractionEnabled = paymentState.allowsViewInteraction
let purchaseButton = contentView.purchaseButton
- let isOutOfTime = TunnelManager.shared.deviceState.accountData
- .map { $0.expiry < Date() } ?? false
-
- let actions = { [weak self] in
- guard let self = self else { return }
+ let isOutOfTime = interactor.deviceState.accountData.map { $0.expiry < Date() } ?? false
- purchaseButton.setTitle(self.productState.purchaseButtonTitle, for: .normal)
- self.contentView.purchaseButton.isLoading = self.productState.isFetching
+ purchaseButton.setTitle(productState.purchaseButtonTitle, for: .normal)
+ contentView.purchaseButton.isLoading = productState.isFetching
- purchaseButton.isEnabled = self.productState.isReceived && isInteractionEnabled && !self
- .tunnelState.isSecured
- self.contentView.restoreButton.isEnabled = isInteractionEnabled
- self.contentView.disconnectButton.isEnabled = self.tunnelState.isSecured
- self.contentView.disconnectButton.alpha = self.tunnelState.isSecured ? 1 : 0
- self.contentView.bodyLabel.text = self.bodyText(for: self.tunnelState)
+ purchaseButton.isEnabled = productState.isReceived && isInteractionEnabled && !tunnelState
+ .isSecured
+ contentView.restoreButton.isEnabled = isInteractionEnabled
+ contentView.disconnectButton.isEnabled = tunnelState.isSecured
+ contentView.disconnectButton.alpha = tunnelState.isSecured ? 1 : 0
- if !isInteractionEnabled {
- self.contentView.statusActivityView.state = .activity
- } else {
- self.contentView.statusActivityView.state = isOutOfTime ? .failure : .success
- }
-
- self.delegate?.viewController(
- self,
- didRequestSettingsButtonEnabled: isInteractionEnabled
+ if tunnelState.isSecured {
+ contentView.bodyLabel.text = NSLocalizedString(
+ "OUT_OF_TIME_BODY_CONNECTED",
+ tableName: "OutOfTime",
+ value: "You have no more VPN time left on this account. To add more, you will need to disconnect and access the Internet with an unsecure connection.",
+ comment: ""
+ )
+ } else {
+ contentView.bodyLabel.text = NSLocalizedString(
+ "OUT_OF_TIME_BODY_DISCONNECTED",
+ tableName: "OutOfTime",
+ value: "You have no more VPN time left on this account. Either buy credit on our website or redeem a voucher.",
+ comment: ""
)
}
- if animated {
- UIView.animate(withDuration: 0.25, animations: actions)
+
+ if !isInteractionEnabled {
+ contentView.statusActivityView.state = .activity
} else {
- actions()
+ contentView.statusActivityView.state = isOutOfTime ? .failure : .success
}
view.isUserInteractionEnabled = isInteractionEnabled
- isModalInPresentation = !isInteractionEnabled
-
- navigationItem.setHidesBackButton(!isInteractionEnabled, animated: animated)
}
- @objc private func doPurchase() {
- guard case let .received(product) = productState,
- let accountData = TunnelManager.shared.deviceState.accountData
- else {
- return
- }
-
- let payment = SKPayment(product: product)
- StorePaymentManager.shared.addPayment(payment, for: accountData.number)
+ private func notifyDelegate(_ oldPaymentState: PaymentState) {
+ switch (oldPaymentState, paymentState) {
+ case (.none, .makingPayment), (.none, .restoringPurchases):
+ delegate?.outOfTimeViewControllerDidBeginPayment(self)
- setPaymentState(.makingPayment(payment), animated: true)
- }
+ case (.makingPayment, .none), (.restoringPurchases, .none):
+ delegate?.outOfTimeViewControllerDidEndPayment(self)
- @objc func restorePurchases() {
- guard let accountData = TunnelManager.shared.deviceState.accountData else {
- return
+ default:
+ break
}
+ }
- setPaymentState(.restoringPurchases, animated: true)
+ private func didReceivePaymentEvent(_ event: StorePaymentEvent) {
+ guard case let .makingPayment(payment) = paymentState,
+ payment == event.payment else { return }
- _ = StorePaymentManager.shared.restorePurchases(for: accountData.number) { completion in
- switch completion {
- case let .success(response):
- self.showAlertIfNoTimeAdded(with: response, context: .restoration)
- case let .failure(error):
- self.showRestorePurchasesErrorAlert(error: error)
+ switch event {
+ case .finished:
+ break
- case .cancelled:
+ case let .failure(paymentFailure):
+ switch paymentFailure.error {
+ case .storePayment(SKError.paymentCancelled):
break
- }
- self.setPaymentState(.none, animated: true)
+ default:
+ showPaymentErrorAlert(error: paymentFailure.error)
+ }
}
- }
- private func showAlertIfNoTimeAdded(
- with response: REST.CreateApplePaymentResponse,
- context: REST.CreateApplePaymentResponse.Context
- ) {
- guard case .noTimeAdded = response else { return }
+ paymentState = .none
+ }
+ private func showPaymentErrorAlert(error: StorePaymentManagerError) {
let alertController = UIAlertController(
- title: response.alertTitle(context: context),
- message: response.alertMessage(context: context),
+ title: NSLocalizedString(
+ "CANNOT_COMPLETE_PURCHASE_ALERT_TITLE",
+ tableName: "OutOfTime",
+ value: "Cannot complete the purchase",
+ comment: ""
+ ),
+ message: error.errorChainDescription,
preferredStyle: .alert
)
+
alertController.addAction(
UIAlertAction(
title: NSLocalizedString(
- "TIME_ADDED_ALERT_OK_ACTION",
+ "CANNOT_COMPLETE_PURCHASE_ALERT_OK_ACTION",
tableName: "OutOfTime",
value: "OK",
comment: ""
- ),
- style: .cancel
+ ), style: .cancel
)
)
alertPresenter.enqueue(alertController, presentingController: self)
}
- func showRestorePurchasesErrorAlert(error: StorePaymentManagerError) {
+ private func showRestorePurchasesErrorAlert(error: StorePaymentManagerError) {
let alertController = UIAlertController(
title: NSLocalizedString(
"RESTORE_PURCHASES_FAILURE_ALERT_TITLE",
@@ -264,6 +235,7 @@ private extension OutOfTimeViewController {
message: error.errorChainDescription,
preferredStyle: .alert
)
+
alertController.addAction(
UIAlertAction(title: NSLocalizedString(
"RESTORE_PURCHASES_FAILURE_ALERT_OK_ACTION",
@@ -272,94 +244,78 @@ private extension OutOfTimeViewController {
comment: ""
), style: .cancel)
)
+
alertPresenter.enqueue(alertController, presentingController: self)
}
- func showPaymentErrorAlert(error: StorePaymentManagerError) {
+ private func showAlertIfNoTimeAdded(
+ with response: REST.CreateApplePaymentResponse,
+ context: REST.CreateApplePaymentResponse.Context
+ ) {
+ guard case .noTimeAdded = response else { return }
+
let alertController = UIAlertController(
- title: NSLocalizedString(
- "CANNOT_COMPLETE_PURCHASE_ALERT_TITLE",
- tableName: "OutOfTime",
- value: "Cannot complete the purchase",
- comment: ""
- ),
- message: error.errorChainDescription,
+ title: response.alertTitle(context: context),
+ message: response.alertMessage(context: context),
preferredStyle: .alert
)
alertController.addAction(
UIAlertAction(
title: NSLocalizedString(
- "CANNOT_COMPLETE_PURCHASE_ALERT_OK_ACTION",
+ "TIME_ADDED_ALERT_OK_ACTION",
tableName: "OutOfTime",
value: "OK",
comment: ""
- ), style: .cancel
+ ),
+ style: .cancel
)
)
alertPresenter.enqueue(alertController, presentingController: self)
}
-}
-// MARK: - StorePaymentObserver
+ // MARK: - Actions
-extension OutOfTimeViewController: StorePaymentObserver {
- func storePaymentManager(
- _ manager: StorePaymentManager,
- didReceiveEvent event: StorePaymentEvent
- ) {
- guard case let .makingPayment(payment) = paymentState,
- payment == event.payment else { return }
-
- switch event {
- case .finished:
- break
-
- case let .failure(paymentFailure):
- switch paymentFailure.error {
- case .storePayment(SKError.paymentCancelled):
- break
-
- default:
- showPaymentErrorAlert(error: paymentFailure.error)
- }
+ @objc private func doPurchase() {
+ guard case let .received(product) = productState,
+ let accountData = interactor.deviceState.accountData
+ else {
+ return
}
- setPaymentState(.none, animated: true)
- }
-}
+ let payment = SKPayment(product: product)
+ interactor.addPayment(payment, for: accountData.number)
-// MARK: - TunnelObserver
+ paymentState = .makingPayment(payment)
+ }
-extension OutOfTimeViewController: TunnelObserver {
- func tunnelManagerDidLoadConfiguration(_ manager: TunnelManager) {}
+ @objc func restorePurchases() {
+ guard let accountData = interactor.deviceState.accountData else {
+ return
+ }
- func tunnelManager(_ manager: TunnelManager, didUpdateTunnelStatus tunnelStatus: TunnelStatus) {
- tunnelState = tunnelStatus.state
- }
+ paymentState = .restoringPurchases
- func tunnelManager(_ manager: TunnelManager, didUpdateDeviceState deviceState: DeviceState) {}
+ _ = interactor.restorePurchases(for: accountData.number) { [weak self] completion in
+ guard let self = self else { return }
- func tunnelManager(
- _ manager: TunnelManager,
- didUpdateTunnelSettings tunnelSettings: TunnelSettingsV2
- ) {}
+ switch completion {
+ case let .success(response):
+ self.showAlertIfNoTimeAdded(with: response, context: .restoration)
- func tunnelManager(_ manager: TunnelManager, didFailWithError error: Error) {}
-}
+ case let .failure(error):
+ self.showRestorePurchasesErrorAlert(error: error)
-// MARK: - Header Bar
+ case .cancelled:
+ break
+ }
-extension OutOfTimeViewController: RootContainment {
- var preferredHeaderBarPresentation: HeaderBarPresentation {
- return HeaderBarPresentation(
- style: tunnelState.isSecured ? .secured : .unsecured,
- showsDivider: false
- )
+ self.paymentState = .none
+ }
}
- var prefersHeaderBarHidden: Bool {
- false
+ @objc private func handleDisconnect(_ sender: Any) {
+ interactor.stopTunnel()
}
}
diff --git a/ios/MullvadVPN/SceneDelegate.swift b/ios/MullvadVPN/SceneDelegate.swift
index afb431faea..00ac40f33f 100644
--- a/ios/MullvadVPN/SceneDelegate.swift
+++ b/ios/MullvadVPN/SceneDelegate.swift
@@ -141,21 +141,15 @@ extension SceneDelegate: UIWindowSceneDelegate {
func sceneDidEnterBackground(_ scene: UIScene) {}
}
-// MARK: - SettingsButtonInteractionDelegate
+// MARK: - OutOfTimeViewControllerDelegate
-protocol SettingsButtonInteractionDelegate: AnyObject {
- func viewController(
- _ controller: UIViewController,
- didRequestSettingsButtonEnabled isEnabled: Bool
- )
-}
+extension SceneDelegate: OutOfTimeViewControllerDelegate {
+ func outOfTimeViewControllerDidBeginPayment(_ controller: OutOfTimeViewController) {
+ setEnableSettingsButton(isEnabled: false, from: controller)
+ }
-extension SceneDelegate: SettingsButtonInteractionDelegate {
- func viewController(
- _ controller: UIViewController,
- didRequestSettingsButtonEnabled isEnabled: Bool
- ) {
- setEnableSettingsButton(isEnabled: isEnabled, from: controller)
+ func outOfTimeViewControllerDidEndPayment(_ controller: OutOfTimeViewController) {
+ setEnableSettingsButton(isEnabled: true, from: controller)
}
}
@@ -369,7 +363,12 @@ extension SceneDelegate {
}
private func makeOutOfTimeViewController() -> OutOfTimeViewController {
- let viewController = OutOfTimeViewController()
+ let viewController = OutOfTimeViewController(
+ interactor: OutOfTimeInteractor(
+ storePaymentManager: .shared,
+ tunnelManager: .shared
+ )
+ )
viewController.delegate = self
return viewController
}