Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix router getting stuck under certain circumstances #7536

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,9 @@
7AB3BEB52BD7A6CB00E34384 /* LocationViewControllerWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB3BEB42BD7A6CB00E34384 /* LocationViewControllerWrapper.swift */; };
7AB4CCB92B69097E006037F5 /* IPOverrideTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB4CCB82B69097E006037F5 /* IPOverrideTests.swift */; };
7AB4CCBB2B691BBB006037F5 /* IPOverrideInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB4CCBA2B691BBB006037F5 /* IPOverrideInteractor.swift */; };
7AB931282D48FB8B005FCEBA /* DAITASettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB931272D48FB16005FCEBA /* DAITASettingsViewController.swift */; };
7AB9312A2D4A16BE005FCEBA /* MultihopViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB931292D4A16B8005FCEBA /* MultihopViewController.swift */; };
7AB9312C2D4A1732005FCEBA /* ChangeLogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB9312B2D4A172C005FCEBA /* ChangeLogViewController.swift */; };
7ABCA5B32A9349F20044A708 /* Routing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A88DCCE2A8FABBE00D2FF0E /* Routing.framework */; };
7ABCA5B42A9349F20044A708 /* Routing.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7A88DCCE2A8FABBE00D2FF0E /* Routing.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
7ABCA5B72A9353C60044A708 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58CAF9F72983D36800BE19F7 /* Coordinator.swift */; };
Expand Down Expand Up @@ -2025,6 +2028,9 @@
7AB3BEB42BD7A6CB00E34384 /* LocationViewControllerWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationViewControllerWrapper.swift; sourceTree = "<group>"; };
7AB4CCB82B69097E006037F5 /* IPOverrideTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideTests.swift; sourceTree = "<group>"; };
7AB4CCBA2B691BBB006037F5 /* IPOverrideInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideInteractor.swift; sourceTree = "<group>"; };
7AB931272D48FB16005FCEBA /* DAITASettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAITASettingsViewController.swift; sourceTree = "<group>"; };
7AB931292D4A16B8005FCEBA /* MultihopViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultihopViewController.swift; sourceTree = "<group>"; };
7AB9312B2D4A172C005FCEBA /* ChangeLogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeLogViewController.swift; sourceTree = "<group>"; };
7ABE318C2A1CDD4500DF4963 /* UIFont+Weight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Weight.swift"; sourceTree = "<group>"; };
7ABFB09D2BA316220074A49E /* RelayConstraintsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayConstraintsTests.swift; sourceTree = "<group>"; };
7AC8A3AD2ABC6FBB00DC4939 /* SettingsHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsHeaderView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4085,6 +4091,7 @@
isa = PBXGroup;
children = (
7A8A19152CEF2696000BCB5B /* MultihopTunnelSettingsViewModel.swift */,
7AB931292D4A16B8005FCEBA /* MultihopViewController.swift */,
7A8A18F82CE34E9F000BCB5B /* SettingsMultihopView.swift */,
);
path = Multihop;
Expand All @@ -4107,6 +4114,7 @@
children = (
7A3215732D3E5A7B005DF395 /* DAITASettingsCoordinator.swift */,
F041BE4E2C983C2B0083EC28 /* DAITASettingsPromptItem.swift */,
7AB931272D48FB16005FCEBA /* DAITASettingsViewController.swift */,
7A8A19132CEF2527000BCB5B /* DAITATunnelSettingsViewModel.swift */,
7A8A19092CE5FFDF000BCB5B /* SettingsDAITAView.swift */,
);
Expand Down Expand Up @@ -4595,6 +4603,7 @@
F048BFA12D31842B00251CB9 /* ChangeLogModel.swift */,
F09C97222D3122E400ADE747 /* ChangeLogReader.swift */,
F09C97202D311D7A00ADE747 /* ChangeLogView.swift */,
7AB9312B2D4A172C005FCEBA /* ChangeLogViewController.swift */,
F0EF50D42A949F8E0031E8DF /* ChangeLogViewModel.swift */,
);
path = ChangeLog;
Expand Down Expand Up @@ -5920,6 +5929,7 @@
58E511E628DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */,
58C76A0B2A338E4300100D75 /* BackgroundTask.swift in Sources */,
7A9CCCC32A96302800DD6A34 /* ApplicationCoordinator.swift in Sources */,
7AB9312A2D4A16BE005FCEBA /* MultihopViewController.swift in Sources */,
5864AF0729C78843005B0CD9 /* SettingsCellFactory.swift in Sources */,
F0ADC3742CD3C47400A1AD97 /* ChipFlowLayout.swift in Sources */,
587B75412668FD7800DEF7E9 /* AccountExpirySystemNotificationProvider.swift in Sources */,
Expand Down Expand Up @@ -6080,6 +6090,7 @@
7A0EAE9A2D01B41500D3EB8B /* MainButtonStyle.swift in Sources */,
58CEB3022AFD365600E6E088 /* SwitchCellContentConfiguration.swift in Sources */,
7AA130A12D01B1E200640DF9 /* SplitMainButton.swift in Sources */,
7AB931282D48FB8B005FCEBA /* DAITASettingsViewController.swift in Sources */,
7AA1309F2D007B2500640DF9 /* VisualEffectView.swift in Sources */,
7A9CCCB52A96302800DD6A34 /* AddCreditSucceededCoordinator.swift in Sources */,
7A0C0F632A979C4A0058EFCE /* Coordinator+Router.swift in Sources */,
Expand Down Expand Up @@ -6266,6 +6277,7 @@
A9C342C12ACC37E30045F00E /* TunnelStatusBlockObserver.swift in Sources */,
587425C12299833500CA2045 /* RootContainerViewController.swift in Sources */,
7AB3BEB52BD7A6CB00E34384 /* LocationViewControllerWrapper.swift in Sources */,
7AB9312C2D4A1732005FCEBA /* ChangeLogViewController.swift in Sources */,
F09D04BD2AEBB7C5003D4F89 /* OutgoingConnectionService.swift in Sources */,
58FF9FF42B07C61B00E4C97D /* AccessMethodValidationError.swift in Sources */,
5896AE84246D5889005B36CB /* CustomDateComponentsFormatting.swift in Sources */,
Expand Down
33 changes: 0 additions & 33 deletions ios/MullvadVPN/Classes/AppRoutes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,30 +42,6 @@ enum AppRouteGroup: AppRouteGroupProtocol {
Alert group. Alert id should match the id of the alert being contained.
*/
case alert(_ alertId: String)

var isModal: Bool {
switch self {
case .primary:
return false

case .selectLocation, .account, .settings, .changelog, .alert:
return true
}
}

var modalLevel: Int {
switch self {
case .primary:
return 0
case .account, .selectLocation, .changelog:
return 1
case .settings:
return 2
case .alert:
// Alerts should always be topmost.
return .max
}
}
}

/**
Expand Down Expand Up @@ -108,15 +84,6 @@ enum AppRoute: AppRouteProtocol {
*/
case tos, login, main, revoked, outOfTime, welcome

var isExclusive: Bool {
switch self {
case .account, .settings, .alert:
return true
default:
return false
}
}

var supportsSubNavigation: Bool {
if case .settings = self {
return true
Expand Down
49 changes: 19 additions & 30 deletions ios/MullvadVPN/Coordinators/ApplicationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import UIKit
Application coordinator managing split view and two navigation contexts.
*/
final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency RootContainerViewControllerDelegate,
UISplitViewControllerDelegate, @preconcurrency ApplicationRouterDelegate,
UISplitViewControllerDelegate, ApplicationRouterDelegate,
@preconcurrency NotificationManagerDelegate {
typealias RouteType = AppRoute

Expand Down Expand Up @@ -234,7 +234,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
func applicationRouter(
_ router: ApplicationRouter<RouteType>,
handleSubNavigationWithContext context: RouteSubnavigationContext<RouteType>,
completion: @escaping @Sendable @MainActor () -> Void
completion: @MainActor @escaping @Sendable () -> Void
) {
switch context.route {
case let .settings(subRoute):
Expand Down Expand Up @@ -309,10 +309,10 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo

private func didDismissAccount(_ reason: AccountDismissReason) {
if reason == .userLoggedOut {
router.dismissAll(.primary, animated: false)
router.dismiss(group: .primary, animated: false)
continueFlow(animated: false)
}
router.dismiss(.account, animated: true)
router.dismiss(route: .account, animated: true)
}

private func presentTOS(animated: Bool, completion: @escaping (Coordinator) -> Void) {
Expand All @@ -337,11 +337,10 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
)

coordinator.didFinish = { [weak self] _ in
self?.router.dismiss(.changelog, animated: animated)
self?.router.dismiss(route: .changelog, animated: animated)
}

coordinator.start(animated: false)

presentChild(coordinator, animated: animated) {
completion(coordinator)
}
Expand Down Expand Up @@ -389,7 +388,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo

Task { @MainActor in
if shouldDismissOutOfTime() {
router.dismiss(.outOfTime, animated: true)
router.dismiss(route: .outOfTime, animated: true)
continueFlow(animated: true)
}
}
Expand All @@ -411,12 +410,12 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
coordinator.didFinish = { [weak self] in
guard let self else { return }
appPreferences.isShownOnboarding = true
router.dismiss(.welcome, animated: false)
router.dismiss(route: .welcome, animated: false)
continueFlow(animated: false)
}
coordinator.didLogout = { [weak self] preferredAccountNumber in
guard let self else { return }
router.dismissAll(.primary, animated: true)
router.dismiss(group: .primary, animated: true)
DispatchQueue.main.async {
self.continueFlow(animated: true)
}
Expand All @@ -435,8 +434,8 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo

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

coordinator.start()
presentChild(coordinator, animated: animated) {
completion(coordinator)
}
Expand Down Expand Up @@ -477,11 +476,10 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
let coordinator = AlertCoordinator(presentation: metadata.presentation)

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

coordinator.start()

metadata.context.presentChild(coordinator, animated: animated) {
completion(coordinator)
}
Expand Down Expand Up @@ -515,7 +513,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo

locationCoordinator.didFinish = { [weak self] _ in
if isModalPresentation {
self?.router.dismiss(.selectLocation, animated: true)
self?.router.dismiss(route: .selectLocation, animated: true)
}
}

Expand All @@ -541,13 +539,9 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo

coordinator.start(animated: animated)

presentChild(
coordinator,
animated: animated
) { [weak self] in
completion(coordinator)

presentChild(coordinator, animated: animated) { [weak self] in
self?.onShowAccount?()
completion(coordinator)
}
}

Expand Down Expand Up @@ -579,7 +573,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo

coordinator.didFinish = { [weak self] _ in
Task { @MainActor in
self?.router.dismissAll(.settings, animated: true)
self?.router.dismiss(group: .settings, animated: true)
}
}

Expand All @@ -590,11 +584,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
}

coordinator.start(initialRoute: route)

presentChild(
coordinator,
animated: animated
) {
presentChild(coordinator, animated: animated) {
completion(coordinator)
}
}
Expand All @@ -608,11 +598,10 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
)

coordinator.didFinish = { [weak self] _ in
self?.router.dismiss(.daita, animated: true)
self?.router.dismiss(route: .daita, animated: true)
}

coordinator.start(animated: animated)

presentChild(coordinator, animated: animated) {
completion(coordinator)
}
Expand Down Expand Up @@ -654,7 +643,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
case (true, false):
updateOutOfTimeTimer(accountData: accountData)
continueFlow(animated: true)
router.dismiss(.outOfTime, animated: true)
router.dismiss(route: .outOfTime, animated: true)
// account was expired
case (false, true):
router.present(.outOfTime, animated: true)
Expand Down Expand Up @@ -757,7 +746,7 @@ final class ApplicationCoordinator: Coordinator, Presenting, @preconcurrency Roo
}

func splitViewControllerDidExpand(_ svc: UISplitViewController) {
router.dismissAll(.selectLocation, animated: false)
router.dismiss(group: .selectLocation, animated: false)
}

// MARK: - RootContainerViewControllerDelegate
Expand Down Expand Up @@ -836,4 +825,4 @@ extension DeviceState {
var splitViewMode: UISplitViewController.DisplayMode {
isLoggedIn ? UISplitViewController.DisplayMode.oneBesideSecondary : .secondaryOnly
}
}
} // swiftlint:disable:this file_length
3 changes: 1 addition & 2 deletions ios/MullvadVPN/Coordinators/ChangeLogCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ final class ChangeLogCoordinator: Coordinator, Presentable, SettingsChildCoordin
}

func start(animated: Bool) {
let changeLogViewController = UIHostingController(rootView: ChangeLogView(viewModel: viewModel))
changeLogViewController.view.setAccessibilityIdentifier(.changeLogAlert)
let changeLogViewController = ChangeLogViewController(rootView: ChangeLogView(viewModel: viewModel))
changeLogViewController.navigationItem.title = NSLocalizedString(
"whats_new_title",
tableName: "Changelog",
Expand Down
8 changes: 5 additions & 3 deletions ios/MullvadVPN/Coordinators/LocationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,12 @@ extension LocationCoordinator: @preconcurrency LocationViewControllerWrapperDele
}

func navigateToFilter() {
let coordinator = makeRelayFilterCoordinator(forModalPresentation: true)
coordinator.start()
applicationRouter?.present(.settings(nil))

presentChild(coordinator, animated: true)
// let coordinator = makeRelayFilterCoordinator(forModalPresentation: true)
// coordinator.start()
//
// presentChild(coordinator, animated: true)
}

func navigateToCustomLists(nodes: [LocationNode]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,13 @@ class DAITASettingsCoordinator: Coordinator, SettingsChildCoordinator, Presentab
)
}

let host = UIHostingController(rootView: view)
let host = DAITASettingsViewController(rootView: view)
host.title = NSLocalizedString(
"NAVIGATION_TITLE_DAITA",
tableName: "Settings",
value: "DAITA",
comment: ""
)
host.view.setAccessibilityIdentifier(.daitaView)
customiseNavigation(on: host)

navigationController.pushViewController(host, animated: animated)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// DAITAViewController.swift
// MullvadVPN
//
// Created by Jon Petersson on 2025-01-28.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//

import SwiftUI

class DAITASettingsViewController: UIHostingController<SettingsDAITAView<DAITATunnelSettingsViewModel>> {
override init(rootView: SettingsDAITAView<DAITATunnelSettingsViewModel>) {
super.init(rootView: rootView)
view.setAccessibilityIdentifier(.daitaView)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//
// DAITAViewController.swift
// MullvadVPN
//
// Created by Jon Petersson on 2025-01-28.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// MultihopViewController.swift
// MullvadVPN
//
// Created by Jon Petersson on 2025-01-29.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//

import SwiftUI

class MultihopViewController: UIHostingController<SettingsMultihopView<MultihopTunnelSettingsViewModel>> {
override init(rootView: SettingsMultihopView<MultihopTunnelSettingsViewModel>) {
super.init(rootView: rootView)
view.setAccessibilityIdentifier(.multihopView)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,12 @@ final class SettingsCoordinator: Coordinator, Presentable, Presenting, SettingsV
return .problemReport
case is ListAccessMethodViewController:
return .apiAccess
case is DAITASettingsViewController:
return .daita
case is MultihopViewController:
return .multihop
case is ChangeLogViewController:
return .changelog
default:
return nil
}
Expand Down
Loading
Loading