Skip to content

Commit

Permalink
Add toggle to disable smart routing
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Petersson committed Oct 11, 2024
1 parent 1a0e107 commit 189959d
Show file tree
Hide file tree
Showing 23 changed files with 407 additions and 197 deletions.
20 changes: 14 additions & 6 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,8 @@
7A1A26472A29CF0800B978AA /* RelayFilterDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1A26462A29CF0800B978AA /* RelayFilterDataSource.swift */; };
7A1A26492A29D48A00B978AA /* RelayFilterCellFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1A26482A29D48A00B978AA /* RelayFilterCellFactory.swift */; };
7A21DACF2A30AA3700A787A9 /* UITextField+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A21DACE2A30AA3700A787A9 /* UITextField+Appearance.swift */; };
7A27E3C92CAE85710088BCFF /* SettingsInfoButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27E3C82CAE85660088BCFF /* SettingsInfoButtonItem.swift */; };
7A27E3CB2CAE861D0088BCFF /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27E3CA2CAE86170088BCFF /* SettingsViewModel.swift */; };
7A28826A2BA8336600FD9F20 /* VPNSettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2882692BA8336600FD9F20 /* VPNSettingsCoordinator.swift */; };
7A2960F62A963F7500389B82 /* AlertCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2960F52A963F7500389B82 /* AlertCoordinator.swift */; };
7A2960FD2A964BB700389B82 /* AlertPresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A2960FC2A964BB700389B82 /* AlertPresentation.swift */; };
Expand Down Expand Up @@ -571,10 +573,10 @@
7A9CCCC22A96302800DD6A34 /* SafariCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9CCCB02A96302800DD6A34 /* SafariCoordinator.swift */; };
7A9CCCC32A96302800DD6A34 /* ApplicationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9CCCB12A96302800DD6A34 /* ApplicationCoordinator.swift */; };
7A9CCCC42A96302800DD6A34 /* TunnelCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9CCCB22A96302800DD6A34 /* TunnelCoordinator.swift */; };
7A9F28FC2CA69D0C005F2089 /* DAITASettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9F28FB2CA69D04005F2089 /* DAITASettingsTests.swift */; };
7A9F29392CABFAFC005F2089 /* InfoHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9F29382CABFAEC005F2089 /* InfoHeaderView.swift */; };
7A9F293B2CAC4443005F2089 /* InfoHeaderConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9F293A2CAC4420005F2089 /* InfoHeaderConfig.swift */; };
7A9F293D2CAD2FD5005F2089 /* InfoModalConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9F293C2CAD2FCF005F2089 /* InfoModalConfig.swift */; };
7A9F28FC2CA69D0C005F2089 /* DAITASettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9F28FB2CA69D04005F2089 /* DAITASettingsTests.swift */; };
7A9FA1422A2E3306000B728D /* CheckboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FA1412A2E3306000B728D /* CheckboxView.swift */; };
7A9FA1442A2E3FE5000B728D /* CheckableSettingsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FA1432A2E3FE5000B728D /* CheckableSettingsCell.swift */; };
7AA513862BC91C6B00D081A4 /* LogRotationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA513852BC91C6B00D081A4 /* LogRotationTests.swift */; };
Expand Down Expand Up @@ -866,7 +868,7 @@
F03580252A13842C00E5DAFD /* IncreasedHitButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03580242A13842C00E5DAFD /* IncreasedHitButton.swift */; };
F03A69F72C2AD2D6000E2E7E /* TimeInterval+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03A69F62C2AD2D5000E2E7E /* TimeInterval+Timeout.swift */; };
F03A69F92C2AD414000E2E7E /* FormsheetPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03A69F82C2AD413000E2E7E /* FormsheetPresentationController.swift */; };
F041BE4F2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F041BE4E2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift */; };
F041BE4F2C983C2B0083EC28 /* DAITASettingsPromptItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F041BE4E2C983C2B0083EC28 /* DAITASettingsPromptItem.swift */; };
F041BE532C9878B60083EC28 /* ConnectionConfigurationBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F041BE522C9878B60083EC28 /* ConnectionConfigurationBuilder.swift */; };
F04413612BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; };
F04413622BA45CE30018A6EE /* CustomListLocationNodeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */; };
Expand Down Expand Up @@ -1797,6 +1799,8 @@
7A1A26482A29D48A00B978AA /* RelayFilterCellFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayFilterCellFactory.swift; sourceTree = "<group>"; };
7A1A264A2A29D65E00B978AA /* SelectableSettingsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectableSettingsCell.swift; sourceTree = "<group>"; };
7A21DACE2A30AA3700A787A9 /* UITextField+Appearance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextField+Appearance.swift"; sourceTree = "<group>"; };
7A27E3C82CAE85660088BCFF /* SettingsInfoButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsInfoButtonItem.swift; sourceTree = "<group>"; };
7A27E3CA2CAE86170088BCFF /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
7A2882692BA8336600FD9F20 /* VPNSettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNSettingsCoordinator.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>"; };
Expand Down Expand Up @@ -1890,10 +1894,10 @@
7A9CCCB02A96302800DD6A34 /* SafariCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SafariCoordinator.swift; sourceTree = "<group>"; };
7A9CCCB12A96302800DD6A34 /* ApplicationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationCoordinator.swift; sourceTree = "<group>"; };
7A9CCCB22A96302800DD6A34 /* TunnelCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelCoordinator.swift; sourceTree = "<group>"; };
7A9F28FB2CA69D04005F2089 /* DAITASettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAITASettingsTests.swift; sourceTree = "<group>"; };
7A9F29382CABFAEC005F2089 /* InfoHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoHeaderView.swift; sourceTree = "<group>"; };
7A9F293A2CAC4420005F2089 /* InfoHeaderConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoHeaderConfig.swift; sourceTree = "<group>"; };
7A9F293C2CAD2FCF005F2089 /* InfoModalConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoModalConfig.swift; sourceTree = "<group>"; };
7A9F28FB2CA69D04005F2089 /* DAITASettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAITASettingsTests.swift; sourceTree = "<group>"; };
7A9FA1412A2E3306000B728D /* CheckboxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxView.swift; sourceTree = "<group>"; };
7A9FA1432A2E3FE5000B728D /* CheckableSettingsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckableSettingsCell.swift; sourceTree = "<group>"; };
7AA513852BC91C6B00D081A4 /* LogRotationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogRotationTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2087,7 +2091,7 @@
F03580242A13842C00E5DAFD /* IncreasedHitButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncreasedHitButton.swift; sourceTree = "<group>"; };
F03A69F62C2AD2D5000E2E7E /* TimeInterval+Timeout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TimeInterval+Timeout.swift"; sourceTree = "<group>"; };
F03A69F82C2AD413000E2E7E /* FormsheetPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormsheetPresentationController.swift; sourceTree = "<group>"; };
F041BE4E2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNSettingsPromptAlertItem.swift; sourceTree = "<group>"; };
F041BE4E2C983C2B0083EC28 /* DAITASettingsPromptItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAITASettingsPromptItem.swift; sourceTree = "<group>"; };
F041BE522C9878B60083EC28 /* ConnectionConfigurationBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionConfigurationBuilder.swift; sourceTree = "<group>"; };
F04413602BA45CD70018A6EE /* CustomListLocationNodeBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomListLocationNodeBuilder.swift; sourceTree = "<group>"; };
F04AF92C2C466013004A8314 /* EphemeralPeerNegotiationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EphemeralPeerNegotiationState.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2793,6 +2797,7 @@
isa = PBXGroup;
children = (
7A9FA1432A2E3FE5000B728D /* CheckableSettingsCell.swift */,
F041BE4E2C983C2B0083EC28 /* DAITASettingsPromptItem.swift */,
7A1A264A2A29D65E00B978AA /* SelectableSettingsCell.swift */,
5819C2162729595500D6EC38 /* SettingsAddDNSEntryCell.swift */,
582BB1AE229566420055B6EF /* SettingsCell.swift */,
Expand All @@ -2802,11 +2807,13 @@
7A83C4012A57FAA800DFB83A /* SettingsDNSInfoCell.swift */,
584D26C5270C8741004EA533 /* SettingsDNSTextCell.swift */,
7AC8A3AD2ABC6FBB00DC4939 /* SettingsHeaderView.swift */,
7A27E3C82CAE85660088BCFF /* SettingsInfoButtonItem.swift */,
7A42DEC82A05164100B209BE /* SettingsInputCell.swift */,
58677711290976FB006F721F /* SettingsInteractor.swift */,
5867770F290975E8006F721F /* SettingsInteractorFactory.swift */,
58ACF64A26553C3F00ACE4B7 /* SettingsSwitchCell.swift */,
58CCA01122424D11004F3011 /* SettingsViewController.swift */,
7A27E3CA2CAE86170088BCFF /* SettingsViewModel.swift */,
);
path = Settings;
sourceTree = "<group>";
Expand Down Expand Up @@ -2835,7 +2842,6 @@
587EB6732714520600123C75 /* VPNSettingsDataSourceDelegate.swift */,
7A6F2FAE2AFE36E7006D0856 /* VPNSettingsInfoButtonItem.swift */,
5871167E2910035700D41AAC /* VPNSettingsInteractor.swift */,
F041BE4E2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift */,
58ACF6482655365700ACE4B7 /* VPNSettingsViewController.swift */,
587EB671271451E300123C75 /* VPNSettingsViewModel.swift */,
);
Expand Down Expand Up @@ -5606,7 +5612,7 @@
7AC8A3AF2ABC71D600DC4939 /* TermsOfServiceCoordinator.swift in Sources */,
58FF9FE22B075BA600E4C97D /* EditAccessMethodSectionIdentifier.swift in Sources */,
F0C2AEFD2A0BB5CC00986207 /* NotificationProviderIdentifier.swift in Sources */,
F041BE4F2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift in Sources */,
F041BE4F2C983C2B0083EC28 /* DAITASettingsPromptItem.swift in Sources */,
7A58699B2B482FE200640D27 /* UITableViewCell+Disable.swift in Sources */,
7AB2B6702BA1EB8C00B03E3B /* ListCustomListViewController.swift in Sources */,
7A9CCCB72A96302800DD6A34 /* RevokedCoordinator.swift in Sources */,
Expand Down Expand Up @@ -5644,6 +5650,7 @@
A91614D62B10B26B00F416EB /* TunnelControlViewModel.swift in Sources */,
7A5869972B32EA4500640D27 /* AppButton.swift in Sources */,
586C0D8F2B03D88100E7CDD7 /* ProxyProtocolConfigurationItemIdentifier.swift in Sources */,
7A27E3CB2CAE861D0088BCFF /* SettingsViewModel.swift in Sources */,
588527B2276B3F0700BAA373 /* LoadTunnelConfigurationOperation.swift in Sources */,
7A9F29392CABFAFC005F2089 /* InfoHeaderView.swift in Sources */,
58DFF7D22B0256A300F864E0 /* MarkdownStylingOptions.swift in Sources */,
Expand Down Expand Up @@ -5880,6 +5887,7 @@
58293FAE2510CA58005D0BB5 /* ProblemReportViewController.swift in Sources */,
58B9EB152489139B00095626 /* RESTError+Display.swift in Sources */,
587B753F2668E5A700DEF7E9 /* NotificationContainerView.swift in Sources */,
7A27E3C92CAE85710088BCFF /* SettingsInfoButtonItem.swift in Sources */,
58F2E144276A13F300A79513 /* StartTunnelOperation.swift in Sources */,
58CCA01E2242787B004F3011 /* AccountTextField.swift in Sources */,
586E54FB27A2DF6D0029B88B /* SendTunnelProviderMessageOperation.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ public enum AccessibilityIdentifier: String {
// DAITA
case daitaSwitch
case daitaPromptAlert
case daitaDirectOnlySwitch

// Quantum resistance
case quantumResistanceAutomatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ final class SettingsCoordinator: Coordinator, Presentable, Presenting, SettingsV
switch route {
case .root:
let controller = SettingsViewController(
interactor: interactorFactory.makeSettingsInteractor()
interactor: interactorFactory.makeSettingsInteractor(),
alertPresenter: AlertPresenter(context: self)
)
controller.delegate = self
return .viewController(controller)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ extension UIListContentConfiguration {
var configuration = cell()
configuration.textProperties.font = .systemFont(ofSize: 17)
configuration.textProperties.color = .Cell.titleTextColor.withAlphaComponent(isEnabled ? 1 : 0.8)
configuration.axesPreservingSuperviewLayoutMargins = .vertical

applyMargins(to: &configuration, tableStyle: tableStyle)

Expand Down
2 changes: 1 addition & 1 deletion ios/MullvadVPN/UI appearance/UIMetrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ enum UIMetrics {
/// Cell layout margins used in table views that use inset style.
static let insetLayoutMargins = NSDirectionalEdgeInsets(top: 16, leading: 24, bottom: 16, trailing: 24)

static let apiAccessLayoutMargins = NSDirectionalEdgeInsets(top: 20, leading: 16, bottom: 20, trailing: 16)
static let apiAccessLayoutMargins = NSDirectionalEdgeInsets(top: 8, leading: 24, bottom: 24, trailing: 24)
static let apiAccessInsetLayoutMargins = NSDirectionalEdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16)
static let settingsValidationErrorLayoutMargins = NSDirectionalEdgeInsets(
top: 8,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// DAITASettingsPromptItem.swift
// MullvadVPN
//
// Created by Mojgan on 2024-09-16.
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

import Foundation
enum DAITASettingsPromptItem: CustomStringConvertible {
case daitaSettingIncompatibleWithSinglehop(Setting)
case daitaSettingIncompatibleWithMultihop(Setting)

enum Setting {
case daita
case directOnly
}

var title: String {
switch self {
case let .daitaSettingIncompatibleWithSinglehop(setting), let .daitaSettingIncompatibleWithMultihop(setting):
switch setting {
case .daita:
"DAITA"
case .directOnly:
"direct only"
}
}
}

var description: String {
switch self {
case .daitaSettingIncompatibleWithSinglehop:
"""
Not all our servers are DAITA-enabled. In order to use the internet, you might have to \
select a new location after enabling.
"""
case .daitaSettingIncompatibleWithMultihop:
"""
Not all our servers are DAITA-enabled. In order to use the internet, you might have to \
select a new entry location after enabling.
"""
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,26 @@
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
//

import MullvadSettings
import UIKit

struct SettingsCellFactory: CellFactoryProtocol {
protocol SettingsCellEventHandler {
func showInfo(for button: SettingsInfoButtonItem)
func switchDaitaState(_ settings: DAITASettings)
func switchDaitaDirectOnlyState(_ settings: DAITASettings)
}

final class SettingsCellFactory: CellFactoryProtocol {
let tableView: UITableView
var delegate: SettingsCellEventHandler?
var viewModel: SettingsViewModel
private let interactor: SettingsInteractor

init(tableView: UITableView, interactor: SettingsInteractor) {
self.tableView = tableView
self.interactor = interactor

viewModel = SettingsViewModel(from: interactor.tunnelSettings)
}

func makeCell(for item: SettingsDataSource.Item, indexPath: IndexPath) -> UITableViewCell {
Expand Down Expand Up @@ -92,6 +103,59 @@ struct SettingsCellFactory: CellFactoryProtocol {
cell.detailTitleLabel.text = nil
cell.accessibilityIdentifier = item.accessibilityIdentifier
cell.disclosureType = .chevron

case .daita:
guard let cell = cell as? SettingsSwitchCell else { return }

cell.titleLabel.text = NSLocalizedString(
"DAITA_LABEL",
tableName: "Settings",
value: "DAITA",
comment: ""
)
cell.accessibilityIdentifier = item.accessibilityIdentifier
cell.setOn(viewModel.daitaSettings.daitaState.isEnabled, animated: false)

cell.infoButtonHandler = { [weak self] in
self?.delegate?.showInfo(for: .daita)
}

cell.action = { [weak self] isEnabled in
guard let self else { return }

let state: DAITAState = isEnabled ? .on : .off
delegate?.switchDaitaState(DAITASettings(
daitaState: state,
directOnlyState: viewModel.daitaSettings.directOnlyState
))
}

case .daitaDirectOnly:
guard let cell = cell as? SettingsSwitchCell else { return }

cell.titleLabel.text = NSLocalizedString(
"DAITA_DIRECT_ONLY_LABEL",
tableName: "Settings",
value: "Direct only",
comment: ""
)
cell.accessibilityIdentifier = item.accessibilityIdentifier
cell.setOn(viewModel.daitaSettings.directOnlyState.isEnabled, animated: false)
cell.setSwitchEnabled(viewModel.daitaSettings.daitaState.isEnabled)

cell.infoButtonHandler = { [weak self] in
self?.delegate?.showInfo(for: .daitaDirectOnly)
}

cell.action = { [weak self] isEnabled in
guard let self else { return }

let state: DirectOnlyState = isEnabled ? .on : .off
delegate?.switchDaitaDirectOnlyState(DAITASettings(
daitaState: viewModel.daitaSettings.daitaState,
directOnlyState: state
))
}
}
}
}
Loading

0 comments on commit 189959d

Please sign in to comment.