Skip to content

Commit

Permalink
Refactor alerts to be presented on their respective coordinator
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Petersson committed Sep 8, 2023
1 parent d183883 commit a976807
Showing 26 changed files with 199 additions and 85 deletions.
2 changes: 2 additions & 0 deletions ios/.swiftlint.yml
Original file line number Diff line number Diff line change
@@ -31,6 +31,8 @@ line_length:
ignores_interpolated_strings: true
warning: 120
error: 300
cyclomatic_complexity:
ignores_case_statements: true

type_name:
min_length: 4
6 changes: 0 additions & 6 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -395,12 +395,9 @@
7A21DACF2A30AA3700A787A9 /* UITextField+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A21DACE2A30AA3700A787A9 /* UITextField+Appearance.swift */; };
7A307AD92A8CD8DA0017618B /* Duration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A307AD82A8CD8DA0017618B /* Duration.swift */; };
7A307ADB2A8F56DF0017618B /* Duration+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A307ADA2A8F56DF0017618B /* Duration+Extensions.swift */; };
<<<<<<< HEAD
7A3353972AAA0F8600F0A71C /* OperationBlockObserverSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3353962AAA0F8600F0A71C /* OperationBlockObserverSupport.swift */; };
=======
7A2960F62A963F7500389B82 /* AlertCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2960F52A963F7500389B82 /* AlertCoordinator.swift */; };
7A2960FD2A964BB700389B82 /* AlertPresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2960FC2A964BB700389B82 /* AlertPresentation.swift */; };
>>>>>>> 010d1f888 (Coordinate alert presentation by integrating it into routing system)
7A42DEC92A05164100B209BE /* SettingsInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A42DEC82A05164100B209BE /* SettingsInputCell.swift */; };
7A42DECD2A09064C00B209BE /* SelectableSettingsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A42DECC2A09064C00B209BE /* SelectableSettingsCell.swift */; };
7A7AD28D29DC677800480EF1 /* FirstTimeLaunch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7AD28C29DC677800480EF1 /* FirstTimeLaunch.swift */; };
@@ -1317,12 +1314,9 @@
7A21DACE2A30AA3700A787A9 /* UITextField+Appearance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextField+Appearance.swift"; sourceTree = "<group>"; };
7A307AD82A8CD8DA0017618B /* Duration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Duration.swift; sourceTree = "<group>"; };
7A307ADA2A8F56DF0017618B /* Duration+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Duration+Extensions.swift"; sourceTree = "<group>"; };
<<<<<<< HEAD
7A3353962AAA0F8600F0A71C /* OperationBlockObserverSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationBlockObserverSupport.swift; sourceTree = "<group>"; };
=======
7A2960F52A963F7500389B82 /* AlertCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertCoordinator.swift; sourceTree = "<group>"; };
7A2960FC2A964BB700389B82 /* AlertPresentation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresentation.swift; sourceTree = "<group>"; };
>>>>>>> 010d1f888 (Coordinate alert presentation by integrating it into routing system)
7A42DEC82A05164100B209BE /* SettingsInputCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsInputCell.swift; sourceTree = "<group>"; };
7A42DECC2A09064C00B209BE /* SelectableSettingsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableSettingsCell.swift; sourceTree = "<group>"; };
7A7AD28C29DC677800480EF1 /* FirstTimeLaunch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstTimeLaunch.swift; sourceTree = "<group>"; };
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"pins" : [
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "173f567a2dfec11d74588eea82cecea555bdc0bc",
"version" : "1.4.0"
}
},
{
"identity" : "wireguard-apple",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mullvad/wireguard-apple.git",
"state" : {
"revision" : "11a00c20dc03f2751db47e94f585c0778c7bde82"
}
}
],
"version" : 2
}
2 changes: 1 addition & 1 deletion ios/MullvadVPN/Classes/AppRoutes.swift
Original file line number Diff line number Diff line change
@@ -94,7 +94,7 @@ enum AppRoute: AppRouteProtocol {
/**
Alert route.
*/
case alert(AlertPresentation)
case alert(String)

/**
Routes that are part of primary horizontal navigation group.
23 changes: 14 additions & 9 deletions ios/MullvadVPN/Coordinators/AccountCoordinator.swift
Original file line number Diff line number Diff line change
@@ -29,10 +29,6 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting {
navigationController
}

var presentationContext: UIViewController {
navigationController
}

var didFinish: ((AccountCoordinator, AccountDismissReason) -> Void)?

init(
@@ -48,7 +44,7 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting {

let accountController = AccountViewController(
interactor: interactor,
errorPresenter: PaymentAlertPresenter(coordinator: self)
errorPresenter: PaymentAlertPresenter(alertContext: self)
)

accountController.actionHandler = handleViewControllerAction
@@ -133,18 +129,25 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting {
// MARK: - Alerts

private func logOut() {
let presentation = AlertPresentation(icon: .spinner, message: nil, buttons: [])
let presentation = AlertPresentation(
id: "account-logout-alert",
icon: .spinner,
message: nil,
buttons: []
)

let alertPresenter = AlertPresenter(context: self)

interactor.logout {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { [weak self] in
guard let self else { return }

applicationRouter?.dismiss(.alert(presentation), animated: true)
alertPresenter.dismissAlert(presentation: presentation, animated: true)
self.didFinish?(self, .userLoggedOut)
}
}

applicationRouter?.present(.alert(presentation))
alertPresenter.showAlert(presentation: presentation, animated: true)
}

private func showAccountDeviceInfo() {
@@ -164,6 +167,7 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting {
)

let presentation = AlertPresentation(
id: "account-device-info-alert",
message: message,
buttons: [AlertAction(
title: NSLocalizedString(
@@ -176,6 +180,7 @@ final class AccountCoordinator: Coordinator, Presentable, Presenting {
)]
)

applicationRouter?.present(.alert(presentation), animated: true)
let presenter = AlertPresenter(context: self)
presenter.showAlert(presentation: presentation, animated: true)
}
}
37 changes: 19 additions & 18 deletions ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift
Original file line number Diff line number Diff line change
@@ -16,8 +16,7 @@ import UIKit
Application coordinator managing split view and two navigation contexts.
*/
final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewControllerDelegate,
UISplitViewControllerDelegate, ApplicationRouterDelegate,
NotificationManagerDelegate {
UISplitViewControllerDelegate, ApplicationRouterDelegate, NotificationManagerDelegate {
typealias RouteType = AppRoute

/**
@@ -120,11 +119,11 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo

func applicationRouter(
_ router: ApplicationRouter<RouteType>,
route: AppRoute,
presentWithContext context: RoutePresentationContext<RouteType>,
animated: Bool,
completion: @escaping (Coordinator) -> Void
) {
switch route {
switch context.route {
case .account:
presentAccount(animated: animated, completion: completion)

@@ -155,8 +154,8 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
case .welcome:
presentWelcome(animated: animated, completion: completion)

case let .alert(presentation):
presentAlert(presentation: presentation, animated: animated, completion: completion)
case .alert:
presentAlert(animated: animated, context: context, completion: completion)
}
}

@@ -564,11 +563,10 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
)

coordinator.didFinishPayment = { [weak self] _ in
guard let self else { return }
guard let self = self else { return }

if shouldDismissOutOfTime() {
router.dismiss(.outOfTime, animated: true)

continueFlow(animated: true)
}
}
@@ -589,7 +587,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
)

coordinator.didFinish = { [weak self] _ in
guard let self else { return }
guard let self = self else { return }
appPreferences.isShownOnboarding = true
router.dismiss(.welcome, animated: false)
continueFlow(animated: false)
@@ -607,10 +605,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
!(tunnelManager.deviceState.accountData?.isExpired ?? false)
}

private func presentSelectLocation(
animated: Bool,
completion: @escaping (Coordinator) -> Void
) {
private func presentSelectLocation(animated: Bool, completion: @escaping (Coordinator) -> Void) {
let coordinator = makeSelectLocationCoordinator(forModalPresentation: true)
coordinator.start()

@@ -642,19 +637,24 @@ final class ApplicationCoordinator: Coordinator, Presenting, RootContainerViewCo
}

private func presentAlert(
presentation: AlertPresentation,
animated: Bool,
context: RoutePresentationContext<RouteType>,
completion: @escaping (Coordinator) -> Void
) {
let coordinator = AlertCoordinator(presentation: presentation)
guard let metadata = context.metadata as? AlertMetadata else {
assertionFailure("Could not get AlertMetadata from RoutePresentationContext.")
return
}

let coordinator = AlertCoordinator(presentation: metadata.presentation)

coordinator.didFinish = { [weak self] in
self?.router.dismiss(.alert(presentation))
self?.router.dismiss(context.route)
}

coordinator.start()

presentChild(coordinator, animated: animated) {
metadata.context.presentChild(coordinator, animated: animated) {
completion(coordinator)
}
}
@@ -990,12 +990,13 @@ fileprivate extension AppPreferencesDataSource {
self.lastSeenChangeLogVersion = Bundle.main.shortVersion
}

// swiftlint:disable:next file_length
}

private protocol Poppable: Presentable {
func popFromNavigationStack(
animated: Bool,
completion: () -> Void
)

// swiftlint:disable:next file_length
}
6 changes: 4 additions & 2 deletions ios/MullvadVPN/Coordinators/InAppPurchaseCoordinator.swift
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ import Routing
import StoreKit
import UIKit

class InAppPurchaseCoordinator: Coordinator, Presentable {
class InAppPurchaseCoordinator: Coordinator, Presenting, Presentable {
private let navigationController: RootContainerViewController
private let interactor: InAppPurchaseInteractor

@@ -50,6 +50,7 @@ class InAppPurchaseCoordinator: Coordinator, Presentable {

case let .failure(failure):
let presentation = AlertPresentation(
id: "in-app-purchase-error-alert",
icon: .alert,
message: failure.error.localizedDescription,
buttons: [
@@ -69,7 +70,8 @@ class InAppPurchaseCoordinator: Coordinator, Presentable {
]
)

applicationRouter?.present(.alert(presentation), animated: true)
let presenter = AlertPresenter(context: self)
presenter.showAlert(presentation: presentation, animated: true)
}
}
}
11 changes: 8 additions & 3 deletions ios/MullvadVPN/Coordinators/LoginCoordinator.swift
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ import Operations
import Routing
import UIKit

final class LoginCoordinator: Coordinator, DeviceManagementViewControllerDelegate {
final class LoginCoordinator: Coordinator, Presenting, DeviceManagementViewControllerDelegate {
private let tunnelManager: TunnelManager
private let devicesProxy: REST.DevicesProxy

@@ -22,6 +22,10 @@ final class LoginCoordinator: Coordinator, DeviceManagementViewControllerDelegat
var didFinish: ((LoginCoordinator) -> Void)?
var didCreateAccount: (() -> Void)?

var presentationContext: UIViewController {
navigationController
}

let navigationController: RootContainerViewController

init(
@@ -107,11 +111,12 @@ final class LoginCoordinator: Coordinator, DeviceManagementViewControllerDelegat
)
let controller = DeviceManagementViewController(
interactor: interactor,
alertPresenter: AlertPresenter(coordinator: self)
alertPresenter: AlertPresenter(context: self)
)
controller.delegate = self

controller.fetchDevices(animateUpdates: false) { [weak self] result in
guard let self else { return }
guard let self = self else { return }

switch result {
case .success:
8 changes: 6 additions & 2 deletions ios/MullvadVPN/Coordinators/OutOfTimeCoordinator.swift
Original file line number Diff line number Diff line change
@@ -9,13 +9,17 @@
import Routing
import UIKit

class OutOfTimeCoordinator: Coordinator, OutOfTimeViewControllerDelegate {
class OutOfTimeCoordinator: Coordinator, Presenting, OutOfTimeViewControllerDelegate {
let navigationController: RootContainerViewController
let storePaymentManager: StorePaymentManager
let tunnelManager: TunnelManager

var didFinishPayment: ((OutOfTimeCoordinator) -> Void)?

var presentationContext: UIViewController {
navigationController
}

private(set) var isMakingPayment = false
private var viewController: OutOfTimeViewController?

@@ -42,7 +46,7 @@ class OutOfTimeCoordinator: Coordinator, OutOfTimeViewControllerDelegate {

let controller = OutOfTimeViewController(
interactor: interactor,
errorPresenter: PaymentAlertPresenter(coordinator: self)
errorPresenter: PaymentAlertPresenter(alertContext: self)
)

controller.delegate = self
8 changes: 2 additions & 6 deletions ios/MullvadVPN/Coordinators/SettingsCoordinator.swift
Original file line number Diff line number Diff line change
@@ -32,10 +32,6 @@ final class SettingsCoordinator: Coordinator, Presentable, Presenting, SettingsV
navigationController
}

var presentationContext: UIViewController {
navigationController
}

var willNavigate: ((
_ coordinator: SettingsCoordinator,
_ from: SettingsNavigationRoute?,
@@ -159,13 +155,13 @@ final class SettingsCoordinator: Coordinator, Presentable, Presenting, SettingsV
case .preferences:
return PreferencesViewController(
interactor: interactorFactory.makePreferencesInteractor(),
alertPresenter: AlertPresenter(coordinator: self)
alertPresenter: AlertPresenter(context: self)
)

case .problemReport:
return ProblemReportViewController(
interactor: interactorFactory.makeProblemReportInteractor(),
alertPresenter: AlertPresenter(coordinator: self)
alertPresenter: AlertPresenter(context: self)
)

case .faq:
10 changes: 8 additions & 2 deletions ios/MullvadVPN/Coordinators/TunnelCoordinator.swift
Original file line number Diff line number Diff line change
@@ -9,12 +9,16 @@
import Routing
import UIKit

class TunnelCoordinator: Coordinator {
class TunnelCoordinator: Coordinator, Presenting {
private let tunnelManager: TunnelManager
private let controller: TunnelViewController

private var tunnelObserver: TunnelObserver?

var presentationContext: UIViewController {
controller
}

var rootViewController: UIViewController {
controller
}
@@ -59,6 +63,7 @@ class TunnelCoordinator: Coordinator {

private func showCancelTunnelAlert() {
let presentation = AlertPresentation(
id: "main-cancel-tunnel-alert",
icon: .alert,
message: NSLocalizedString(
"CANCEL_TUNNEL_ALERT_MESSAGE",
@@ -91,6 +96,7 @@ class TunnelCoordinator: Coordinator {
]
)

applicationRouter?.present(.alert(presentation), animated: true)
let presenter = AlertPresenter(context: self)
presenter.showAlert(presentation: presentation, animated: true)
}
}
Loading

0 comments on commit a976807

Please sign in to comment.