summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBug Magnet <marco.nikic@mullvad.net>2024-10-11 14:38:40 +0200
committerBug Magnet <marco.nikic@mullvad.net>2024-10-11 14:38:40 +0200
commitc28b2226ca73de6cd8ebaabda46ad51ad5d18cf1 (patch)
tree08a1de0b12010dbc6d67189d68f7b730b71e3123
parent4fdeaa153a30f522a5f1e387a08fa56e33164379 (diff)
parentbfee139a46c79549a56159df8c05d9dda5f3071a (diff)
downloadmullvadvpn-c28b2226ca73de6cd8ebaabda46ad51ad5d18cf1.tar.xz
mullvadvpn-c28b2226ca73de6cd8ebaabda46ad51ad5d18cf1.zip
Merge branch 'add-toggle-to-enable-smart-routing-ios-831'
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj20
-rw-r--r--ios/MullvadVPN/Classes/AccessbilityIdentifier.swift1
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift3
-rw-r--r--ios/MullvadVPN/Extensions/UIListContentConfiguration+Extensions.swift1
-rw-r--r--ios/MullvadVPN/UI appearance/UIMetrics.swift2
-rw-r--r--ios/MullvadVPN/View controllers/Settings/DAITASettingsPromptItem.swift45
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift66
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsDataSource.swift113
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsDataSourceDelegate.swift10
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsInfoButtonItem.swift46
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsInteractor.swift22
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsSwitchCell.swift4
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift82
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsViewModel.swift21
-rw-r--r--ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift2
-rw-r--r--ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift22
-rw-r--r--ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift33
-rw-r--r--ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSourceDelegate.swift2
-rw-r--r--ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift16
-rw-r--r--ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInteractor.swift16
-rw-r--r--ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsPromptAlertItem.swift32
-rw-r--r--ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift47
-rw-r--r--ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewModel.swift6
23 files changed, 400 insertions, 212 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index 8f382e0c30..b09c0452aa 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -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 */; };
@@ -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 */; };
@@ -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 */; };
@@ -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>"; };
@@ -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>"; };
@@ -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>"; };
@@ -2793,6 +2797,7 @@
isa = PBXGroup;
children = (
7A9FA1432A2E3FE5000B728D /* CheckableSettingsCell.swift */,
+ F041BE4E2C983C2B0083EC28 /* DAITASettingsPromptItem.swift */,
7A1A264A2A29D65E00B978AA /* SelectableSettingsCell.swift */,
5819C2162729595500D6EC38 /* SettingsAddDNSEntryCell.swift */,
582BB1AE229566420055B6EF /* SettingsCell.swift */,
@@ -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>";
@@ -2835,7 +2842,6 @@
587EB6732714520600123C75 /* VPNSettingsDataSourceDelegate.swift */,
7A6F2FAE2AFE36E7006D0856 /* VPNSettingsInfoButtonItem.swift */,
5871167E2910035700D41AAC /* VPNSettingsInteractor.swift */,
- F041BE4E2C983C2B0083EC28 /* VPNSettingsPromptAlertItem.swift */,
58ACF6482655365700ACE4B7 /* VPNSettingsViewController.swift */,
587EB671271451E300123C75 /* VPNSettingsViewModel.swift */,
);
@@ -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 */,
@@ -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 */,
@@ -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 */,
diff --git a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
index 95fc438805..6cfbce70a1 100644
--- a/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
+++ b/ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
@@ -193,6 +193,7 @@ public enum AccessibilityIdentifier: String {
// DAITA
case daitaSwitch
case daitaPromptAlert
+ case daitaDirectOnlySwitch
// Quantum resistance
case quantumResistanceAutomatic
diff --git a/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift b/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift
index c9a44223ff..2e9501f25a 100644
--- a/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/SettingsCoordinator.swift
@@ -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)
diff --git a/ios/MullvadVPN/Extensions/UIListContentConfiguration+Extensions.swift b/ios/MullvadVPN/Extensions/UIListContentConfiguration+Extensions.swift
index 3eefba09fb..385e9a1f6c 100644
--- a/ios/MullvadVPN/Extensions/UIListContentConfiguration+Extensions.swift
+++ b/ios/MullvadVPN/Extensions/UIListContentConfiguration+Extensions.swift
@@ -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)
diff --git a/ios/MullvadVPN/UI appearance/UIMetrics.swift b/ios/MullvadVPN/UI appearance/UIMetrics.swift
index aa6502d126..9e4997da1e 100644
--- a/ios/MullvadVPN/UI appearance/UIMetrics.swift
+++ b/ios/MullvadVPN/UI appearance/UIMetrics.swift
@@ -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,
diff --git a/ios/MullvadVPN/View controllers/Settings/DAITASettingsPromptItem.swift b/ios/MullvadVPN/View controllers/Settings/DAITASettingsPromptItem.swift
new file mode 100644
index 0000000000..c67578027c
--- /dev/null
+++ b/ios/MullvadVPN/View controllers/Settings/DAITASettingsPromptItem.swift
@@ -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.
+ """
+ }
+ }
+}
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift b/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift
index 1085f7f71c..d079501f1f 100644
--- a/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsCellFactory.swift
@@ -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 {
@@ -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
+ ))
+ }
}
}
}
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsDataSource.swift b/ios/MullvadVPN/View controllers/Settings/SettingsDataSource.swift
index 87143fc84f..eb9236bc58 100644
--- a/ios/MullvadVPN/View controllers/Settings/SettingsDataSource.swift
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsDataSource.swift
@@ -12,10 +12,16 @@ import UIKit
final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource.Section, SettingsDataSource.Item>,
UITableViewDelegate {
enum CellReuseIdentifiers: String, CaseIterable {
- case basicCell
+ case basic
+ case daita
var reusableViewClass: AnyClass {
- SettingsCell.self
+ switch self {
+ case .basic:
+ SettingsCell.self
+ case .daita:
+ SettingsSwitchCell.self
+ }
}
}
@@ -28,6 +34,7 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource
}
enum Section: String {
+ case daita
case main
case version
case problemReport
@@ -39,6 +46,8 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource
case problemReport
case faq
case apiAccess
+ case daita
+ case daitaDirectOnly
var accessibilityIdentifier: AccessibilityIdentifier {
switch self {
@@ -52,17 +61,26 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource
return .faqCell
case .apiAccess:
return .apiAccessCell
+ case .daita:
+ return .daitaSwitch
+ case .daitaDirectOnly:
+ return .daitaDirectOnlySwitch
}
}
var reuseIdentifier: CellReuseIdentifiers {
- .basicCell
+ switch self {
+ case .vpnSettings, .version, .problemReport, .faq, .apiAccess:
+ .basic
+ case .daita, .daitaDirectOnly:
+ .daita
+ }
}
}
private let interactor: SettingsInteractor
- private let settingsCellFactory: SettingsCellFactory
private var storedAccountData: StoredAccountData?
+ private let settingsCellFactory: SettingsCellFactory
private weak var tableView: UITableView?
weak var delegate: SettingsDataSourceDelegate?
@@ -79,6 +97,8 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource
}
tableView.delegate = self
+ settingsCellFactory.delegate = self
+
registerClasses()
updateDataSnapshot()
@@ -91,17 +111,17 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource
// MARK: - UITableViewDelegate
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
- if case .version = itemIdentifier(for: indexPath) {
- return false
- } else {
- return true
+ switch itemIdentifier(for: indexPath) {
+ case .vpnSettings, .problemReport, .faq, .apiAccess:
+ true
+ case .version, .daita, .daitaDirectOnly, .none:
+ false
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let item = itemIdentifier(for: indexPath) else { return }
-
- delegate?.settingsDataSource(self, didSelectItem: item)
+ delegate?.didSelectItem(item: item)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
@@ -143,9 +163,11 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource
private func updateDataSnapshot() {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
- snapshot.appendSections([.main])
+ snapshot.appendSections([.daita, .main])
if interactor.deviceState.isLoggedIn {
+ snapshot.appendItems([.daita], toSection: .daita)
+ snapshot.appendItems([.daitaDirectOnly], toSection: .daita)
snapshot.appendItems([.vpnSettings], toSection: .main)
}
@@ -158,3 +180,72 @@ final class SettingsDataSource: UITableViewDiffableDataSource<SettingsDataSource
apply(snapshot)
}
}
+
+extension SettingsDataSource: SettingsCellEventHandler {
+ func showInfo(for button: SettingsInfoButtonItem) {
+ delegate?.showInfo(for: button)
+ }
+
+ func switchDaitaState(_ settings: DAITASettings) {
+ testDaitaCompatibility(for: .daita, settings: settings) { [weak self] in
+ self?.reloadItem(.daitaDirectOnly)
+ } onDiscard: { [weak self] in
+ self?.reloadItem(.daita)
+ }
+ }
+
+ func switchDaitaDirectOnlyState(_ settings: DAITASettings) {
+ testDaitaCompatibility(for: .daitaDirectOnly, settings: settings, onDiscard: { [weak self] in
+ self?.reloadItem(.daitaDirectOnly)
+ })
+ }
+
+ private func reloadItem(_ item: Item) {
+ var snapshot = snapshot()
+ snapshot.reloadItems([item])
+ apply(snapshot, animatingDifferences: false)
+ }
+
+ private func testDaitaCompatibility(
+ for item: Item,
+ settings: DAITASettings,
+ onSave: (() -> Void)? = nil,
+ onDiscard: @escaping () -> Void
+ ) {
+ let updateSettings = { [weak self] in
+ self?.settingsCellFactory.viewModel.setDAITASettings(settings)
+ self?.interactor.updateDAITASettings(settings)
+
+ onSave?()
+ }
+
+ var promptItemSetting: DAITASettingsPromptItem.Setting?
+ switch item {
+ case .daita:
+ promptItemSetting = .daita
+ case .daitaDirectOnly:
+ promptItemSetting = .directOnly
+ default:
+ break
+ }
+
+ if let promptItemSetting, let error = interactor.evaluateDaitaSettingsCompatibility(settings) {
+ switch error {
+ case .singlehop:
+ delegate?.showPrompt(
+ for: .daitaSettingIncompatibleWithSinglehop(promptItemSetting),
+ onSave: { updateSettings() },
+ onDiscard: onDiscard
+ )
+ case .multihop:
+ delegate?.showPrompt(
+ for: .daitaSettingIncompatibleWithMultihop(promptItemSetting),
+ onSave: { updateSettings() },
+ onDiscard: onDiscard
+ )
+ }
+ } else {
+ updateSettings()
+ }
+ }
+}
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsDataSourceDelegate.swift b/ios/MullvadVPN/View controllers/Settings/SettingsDataSourceDelegate.swift
index 30d7e1629a..4800271dc8 100644
--- a/ios/MullvadVPN/View controllers/Settings/SettingsDataSourceDelegate.swift
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsDataSourceDelegate.swift
@@ -6,11 +6,15 @@
// Copyright © 2021 Mullvad VPN AB. All rights reserved.
//
+import MullvadSettings
import UIKit
protocol SettingsDataSourceDelegate: AnyObject {
- func settingsDataSource(
- _ dataSource: SettingsDataSource,
- didSelectItem item: SettingsDataSource.Item
+ func didSelectItem(item: SettingsDataSource.Item)
+ func showInfo(for: SettingsInfoButtonItem)
+ func showPrompt(
+ for: DAITASettingsPromptItem,
+ onSave: @escaping () -> Void,
+ onDiscard: @escaping () -> Void
)
}
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsInfoButtonItem.swift b/ios/MullvadVPN/View controllers/Settings/SettingsInfoButtonItem.swift
new file mode 100644
index 0000000000..2cf1d2d8b1
--- /dev/null
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsInfoButtonItem.swift
@@ -0,0 +1,46 @@
+//
+// SettingsInfoButtonItem.swift
+// MullvadVPN
+//
+// Created by Jon Petersson on 2024-10-03.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+
+enum SettingsInfoButtonItem: CustomStringConvertible {
+ case daita
+ case daitaDirectOnly
+
+ var description: String {
+ switch self {
+ case .daita:
+ NSLocalizedString(
+ "DAITA_INFORMATION_TEXT",
+ tableName: "DAITA",
+ value: """
+ DAITA (Defence against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. \
+ If anyone is monitoring your connection, this makes it significantly harder for them to identify \
+ what websites you are visiting.
+ It does this by carefully adding network noise and making all network packets the same size.
+ Not all our servers are DAITA-enabled. Therefore, we use multihop automatically to enable DAITA \
+ with any server.
+ Attention: Be cautious if you have a limited data plan as this feature will increase your network \
+ traffic.
+ """,
+ comment: ""
+ )
+ case .daitaDirectOnly:
+ NSLocalizedString(
+ "DIRECT_ONLY_INFORMATION_TEXT",
+ tableName: "DAITA",
+ value: """
+ By enabling “Direct only” you will have to manually select a server that is DAITA-enabled. \
+ This can cause you to end up in a blocked state until you have selected a compatible server \
+ in the “Select location” view.
+ """,
+ comment: ""
+ )
+ }
+ }
+}
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsInteractor.swift b/ios/MullvadVPN/View controllers/Settings/SettingsInteractor.swift
index c3f07dc72c..78a5a6dd43 100644
--- a/ios/MullvadVPN/View controllers/Settings/SettingsInteractor.swift
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsInteractor.swift
@@ -15,13 +15,15 @@ final class SettingsInteractor {
var didUpdateDeviceState: ((DeviceState) -> Void)?
+ var tunnelSettings: LatestTunnelSettings {
+ tunnelManager.settings
+ }
+
var deviceState: DeviceState {
tunnelManager.deviceState
}
- init(
- tunnelManager: TunnelManager
- ) {
+ init(tunnelManager: TunnelManager) {
self.tunnelManager = tunnelManager
let tunnelObserver =
@@ -33,4 +35,18 @@ final class SettingsInteractor {
self.tunnelObserver = tunnelObserver
}
+
+ func updateDAITASettings(_ settings: DAITASettings) {
+ tunnelManager.updateSettings([.daita(settings)])
+ }
+
+ func evaluateDaitaSettingsCompatibility(_ settings: DAITASettings) -> DAITASettingsCompatibilityError? {
+ guard settings.daitaState.isEnabled else { return nil }
+
+ var tunnelSettings = tunnelSettings
+ tunnelSettings.daita = settings
+
+ guard let selectedRelays = try? tunnelManager.selectRelays(tunnelSettings: tunnelSettings) else { return nil }
+ return tunnelSettings.tunnelMultihopState.isEnabled ? .multihop : .singlehop
+ }
}
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsSwitchCell.swift b/ios/MullvadVPN/View controllers/Settings/SettingsSwitchCell.swift
index e148756017..83af8f6b05 100644
--- a/ios/MullvadVPN/View controllers/Settings/SettingsSwitchCell.swift
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsSwitchCell.swift
@@ -31,7 +31,7 @@ class SettingsSwitchCell: SettingsCell {
fatalError("init(coder:) has not been implemented")
}
- func setEnabled(_ isEnabled: Bool) {
+ func setSwitchEnabled(_ isEnabled: Bool) {
switchContainer.isEnabled = isEnabled
}
@@ -42,7 +42,7 @@ class SettingsSwitchCell: SettingsCell {
override func prepareForReuse() {
super.prepareForReuse()
- setEnabled(true)
+ setSwitchEnabled(true)
}
// MARK: - Actions
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift b/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift
index 27e89a883b..01b4df8ea6 100644
--- a/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsViewController.swift
@@ -7,6 +7,7 @@
//
import Foundation
+import MullvadSettings
import Routing
import UIKit
@@ -18,17 +19,20 @@ protocol SettingsViewControllerDelegate: AnyObject {
)
}
-class SettingsViewController: UITableViewController, SettingsDataSourceDelegate {
+class SettingsViewController: UITableViewController {
weak var delegate: SettingsViewControllerDelegate?
private var dataSource: SettingsDataSource?
private let interactor: SettingsInteractor
+ private let alertPresenter: AlertPresenter
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
- init(interactor: SettingsInteractor) {
+ init(interactor: SettingsInteractor, alertPresenter: AlertPresenter) {
self.interactor = interactor
+ self.alertPresenter = alertPresenter
+
super.init(style: .grouped)
}
@@ -66,16 +70,76 @@ class SettingsViewController: UITableViewController, SettingsDataSourceDelegate
dataSource = SettingsDataSource(tableView: tableView, interactor: interactor)
dataSource?.delegate = self
}
+}
+
+extension SettingsViewController: SettingsDataSourceDelegate {
+ func didSelectItem(item: SettingsDataSource.Item) {
+ guard let route = item.navigationRoute else { return }
+ delegate?.settingsViewController(self, didRequestRoutePresentation: route)
+ }
- // MARK: - SettingsDataSourceDelegate
+ func showInfo(for item: SettingsInfoButtonItem) {
+ let presentation = AlertPresentation(
+ id: "settings-info-alert",
+ icon: .info,
+ message: item.description,
+ buttons: [
+ AlertAction(
+ title: NSLocalizedString(
+ "SETTINGS_INFO_ALERT_OK_ACTION",
+ tableName: "Settings",
+ value: "Got it!",
+ comment: ""
+ ),
+ style: .default
+ ),
+ ]
+ )
+
+ alertPresenter.showAlert(presentation: presentation, animated: true)
+ }
- func settingsDataSource(
- _ dataSource: SettingsDataSource,
- didSelectItem item: SettingsDataSource.Item
+ func showPrompt(
+ for item: DAITASettingsPromptItem,
+ onSave: @escaping () -> Void,
+ onDiscard: @escaping () -> Void
) {
- guard let route = item.navigationRoute else { return }
+ let presentation = AlertPresentation(
+ id: "settings-daita-prompt",
+ accessibilityIdentifier: .daitaPromptAlert,
+ icon: .info,
+ message: NSLocalizedString(
+ "SETTINGS_DAITA_ENABLE_TEXT",
+ tableName: "DAITA",
+ value: item.description,
+ comment: ""
+ ),
+ buttons: [
+ AlertAction(
+ title: String(format: NSLocalizedString(
+ "SETTINGS_DAITA_ENABLE_OK_ACTION",
+ tableName: "DAITA",
+ value: "Enable %@",
+ comment: ""
+ ), item.title),
+ style: .default,
+ accessibilityId: .daitaConfirmAlertEnableButton,
+ handler: { onSave() }
+ ),
+ AlertAction(
+ title: NSLocalizedString(
+ "SETTINGS_DAITA_ENABLE_CANCEL_ACTION",
+ tableName: "DAITA",
+ value: "Back",
+ comment: ""
+ ),
+ style: .default,
+ handler: { onDiscard() }
+ ),
+ ]
+ )
- delegate?.settingsViewController(self, didRequestRoutePresentation: route)
+ alertPresenter.showAlert(presentation: presentation, animated: true)
}
}
@@ -84,7 +148,7 @@ extension SettingsDataSource.Item {
switch self {
case .vpnSettings:
return .vpnSettings
- case .version:
+ case .version, .daita, .daitaDirectOnly:
return nil
case .problemReport:
return .problemReport
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsViewModel.swift b/ios/MullvadVPN/View controllers/Settings/SettingsViewModel.swift
new file mode 100644
index 0000000000..1e67a4c285
--- /dev/null
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsViewModel.swift
@@ -0,0 +1,21 @@
+//
+// SettingsViewModel.swift
+// MullvadVPN
+//
+// Created by Jon Petersson on 2024-10-03.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import MullvadSettings
+
+struct SettingsViewModel {
+ private(set) var daitaSettings: DAITASettings
+
+ mutating func setDAITASettings(_ newSettings: DAITASettings) {
+ daitaSettings = newSettings
+ }
+
+ init(from tunnelSettings: LatestTunnelSettings = LatestTunnelSettings()) {
+ daitaSettings = tunnelSettings.daita
+ }
+}
diff --git a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift
index 11536c55f3..639fa2d17b 100644
--- a/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift
+++ b/ios/MullvadVPN/View controllers/VPNSettings/CustomDNSCellFactory.swift
@@ -172,7 +172,7 @@ final class CustomDNSCellFactory: CellFactoryProtocol {
value: "Use custom DNS server",
comment: ""
)
- cell.setEnabled(viewModel.customDNSPrecondition == .satisfied)
+ cell.setSwitchEnabled(viewModel.customDNSPrecondition == .satisfied)
cell.setOn(viewModel.effectiveEnableCustomDNS, animated: false)
cell.accessibilityHint = viewModel.customDNSPrecondition
.localizedDescription(isEditing: isEditing)
diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift
index 996e340dc4..16d6ff24a5 100644
--- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift
+++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsCellFactory.swift
@@ -15,7 +15,6 @@ protocol VPNSettingsCellEventHandler {
func selectCustomPortEntry(_ port: UInt16) -> Bool
func selectObfuscationState(_ state: WireGuardObfuscationState)
func switchMultihop(_ state: MultihopState)
- func switchDaitaState(_ settings: DAITASettings)
}
final class VPNSettingsCellFactory: CellFactoryProtocol {
@@ -206,27 +205,6 @@ final class VPNSettingsCellFactory: CellFactoryProtocol {
cell.accessibilityIdentifier = item.accessibilityIdentifier
cell.applySubCellStyling()
- case .daitaSwitch:
- guard let cell = cell as? SettingsSwitchCell else { return }
-
- cell.titleLabel.text = NSLocalizedString(
- "DAITA_LABEL",
- tableName: "VPNSettings",
- 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
- let state: DAITAState = isEnabled ? .on : .off
- self?.delegate?.switchDaitaState(DAITASettings(daitaState: state))
- }
-
case .multihopSwitch:
guard let cell = cell as? SettingsSwitchCell else { return }
diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift
index bd24a10f6d..4113ca8660 100644
--- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift
+++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSource.swift
@@ -80,7 +80,6 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
case quantumResistanceOn
case quantumResistanceOff
case multihopSwitch
- case daitaSwitch
static var wireGuardPorts: [Item] {
let defaultPorts = VPNSettingsViewModel.defaultWireGuardPorts.map {
@@ -125,8 +124,6 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
return .quantumResistanceOn
case .quantumResistanceOff:
return .quantumResistanceOff
- case .daitaSwitch:
- return .daitaSwitch
case .multihopSwitch:
return .multihopSwitch
}
@@ -150,8 +147,6 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
return .quantumResistance
case .multihopSwitch:
return .multihop
- case .daitaSwitch:
- return .daita
}
}
}
@@ -425,7 +420,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
snapshot.appendItems([.dnsSettings], toSection: .dnsSettings)
snapshot.appendItems([.ipOverrides], toSection: .ipOverrides)
- snapshot.appendItems([.daitaSwitch, .multihopSwitch], toSection: .privacyAndSecurity)
+ snapshot.appendItems([.multihopSwitch], toSection: .privacyAndSecurity)
applySnapshot(snapshot, animated: animated, completion: completion)
}
@@ -646,32 +641,6 @@ extension VPNSettingsDataSource: VPNSettingsCellEventHandler {
viewModel.setMultihop(state)
delegate?.didUpdateTunnelSettings(.multihop(viewModel.multihopState))
}
-
- func switchDaitaState(_ settings: DAITASettings) {
- let updateSettings = { [weak self] in
- self?.viewModel.setDAITASettings(settings)
- self?.delegate?.didUpdateTunnelSettings(.daita(settings))
- }
-
- if let error = delegate?.didAttemptToChangeDaitaSettings(settings) {
- switch error {
- case .singlehop:
- delegate?.showPrompt(for: .daitaSettingIncompatibleWithSinglehop) {
- updateSettings()
- } onDiscard: { [weak self] in
- self?.tableView?.reloadData()
- }
- case .multihop:
- delegate?.showPrompt(for: .daitaSettingIncompatibleWithMultihop) {
- updateSettings()
- } onDiscard: { [weak self] in
- self?.tableView?.reloadData()
- }
- }
- } else {
- updateSettings()
- }
- }
}
// swiftlint:disable:this file_length
diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSourceDelegate.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSourceDelegate.swift
index 84bf9795d0..de1a602fce 100644
--- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSourceDelegate.swift
+++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsDataSourceDelegate.swift
@@ -16,11 +16,9 @@ protocol DNSSettingsDataSourceDelegate: AnyObject {
protocol VPNSettingsDataSourceDelegate: AnyObject {
func didUpdateTunnelSettings(_ update: TunnelSettingsUpdate)
- func didAttemptToChangeDaitaSettings(_ settings: DAITASettings) -> DAITASettingsCompatibilityError?
func showInfo(for: VPNSettingsInfoButtonItem)
func showDNSSettings()
func showIPOverrides()
func didSelectWireGuardPort(_ port: UInt16?)
- func showPrompt(for: VPNSettingsPromptAlertItem, onSave: @escaping () -> Void, onDiscard: @escaping () -> Void)
func humanReadablePortRepresentation() -> String
}
diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift
index 1ba6343015..ac57e39db1 100644
--- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift
+++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInfoButtonItem.swift
@@ -16,7 +16,6 @@ enum VPNSettingsInfoButtonItem: CustomStringConvertible {
case wireGuardObfuscationPort
case quantumResistance
case multihop
- case daita
var description: String {
switch self {
@@ -97,21 +96,6 @@ enum VPNSettingsInfoButtonItem: CustomStringConvertible {
""",
comment: ""
)
- case .daita:
- NSLocalizedString(
- "DAITA_INFORMATION_TEXT",
- tableName: "DAITA",
- value: """
- DAITA (Defence against AI-guided Traffic Analysis) hides patterns in your encrypted VPN traffic. \
- If anyone is monitoring your connection, this makes it significantly harder for them to identify \
- what websites you are visiting. It does this by carefully adding network noise and making all \
- network packets the same size.
- Attention: Since this increases your total network traffic, \
- be cautious if you have a limited data plan. \
- It can also negatively impact your network speed and battery usage.
- """,
- comment: ""
- )
}
}
}
diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInteractor.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInteractor.swift
index 8857c46493..e304a8e4b6 100644
--- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInteractor.swift
+++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsInteractor.swift
@@ -51,22 +51,6 @@ final class VPNSettingsInteractor {
tunnelManager.updateSettings([.relayConstraints(relayConstraints)], completionHandler: completion)
}
-
- func evaluateDaitaSettingsCompatibility(_ settings: DAITASettings) -> DAITASettingsCompatibilityError? {
- guard settings.daitaState.isEnabled else { return nil }
-
- var tunnelSettings = tunnelSettings
- tunnelSettings.daita = settings
-
- let selectedRelays = try? tunnelManager.selectRelays(tunnelSettings: tunnelSettings)
- let multihopEnabled = tunnelSettings.tunnelMultihopState.isEnabled
-
- return if multihopEnabled {
- selectedRelays?.entry == nil ? .multihop : nil
- } else {
- selectedRelays?.exit == nil ? .singlehop : nil
- }
- }
}
extension VPNSettingsInteractor: RelayCacheTrackerObserver {
diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsPromptAlertItem.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsPromptAlertItem.swift
deleted file mode 100644
index 74cc90b8d8..0000000000
--- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsPromptAlertItem.swift
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// VPNSettingsPromptAlertItem.swift
-// MullvadVPN
-//
-// Created by Mojgan on 2024-09-16.
-// Copyright © 2024 Mullvad VPN AB. All rights reserved.
-//
-
-import Foundation
-enum VPNSettingsPromptAlertItem: CustomStringConvertible {
- case daitaSettingIncompatibleWithSinglehop
- case daitaSettingIncompatibleWithMultihop
-
- var description: String {
- switch self {
- case .daitaSettingIncompatibleWithSinglehop:
- """
- DAITA isn’t available on the current server. After enabling, please go to the Switch \
- location view and select a location that supports DAITA.
- Attention: Since this increases your total network traffic, be cautious if you have a \
- limited data plan. It can also negatively impact your network speed and battery usage.
- """
- case .daitaSettingIncompatibleWithMultihop:
- """
- DAITA isn’t available on the current entry server. After enabling, please go to the Switch \
- location view and select an entry location that supports DAITA.
- Attention: Since this increases your total network traffic, be cautious if you have a \
- limited data plan. It can also negatively impact your network speed and battery usage.
- """
- }
- }
-}
diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift
index 32facd0eca..c86db1b9d0 100644
--- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift
+++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewController.swift
@@ -123,51 +123,4 @@ extension VPNSettingsViewController: VPNSettingsDataSourceDelegate {
func didSelectWireGuardPort(_ port: UInt16?) {
interactor.setPort(port)
}
-
- func didAttemptToChangeDaitaSettings(_ settings: DAITASettings) -> DAITASettingsCompatibilityError? {
- interactor.evaluateDaitaSettingsCompatibility(settings)
- }
-
- func showPrompt(
- for item: VPNSettingsPromptAlertItem,
- onSave: @escaping () -> Void,
- onDiscard: @escaping () -> Void
- ) {
- let presentation = AlertPresentation(
- id: "vpn-settings-content-blockers-alert",
- accessibilityIdentifier: .daitaPromptAlert,
- icon: .info,
- message: NSLocalizedString(
- "VPN_SETTINGS_VPN_DAITA_ENABLE_TEXT",
- tableName: "DAITA",
- value: item.description,
- comment: ""
- ),
- buttons: [
- AlertAction(
- title: NSLocalizedString(
- "VPN_SETTINGS_VPN_DAITA_OK_ACTION",
- tableName: "DAITA",
- value: "Enable anyway",
- comment: ""
- ),
- style: .default,
- accessibilityId: .daitaConfirmAlertEnableButton,
- handler: { onSave() }
- ),
- AlertAction(
- title: NSLocalizedString(
- "VPN_SETTINGS_VPN_DAITA_CANCEL_ACTION",
- tableName: "DAITA",
- value: "Back",
- comment: ""
- ),
- style: .default,
- handler: { onDiscard() }
- ),
- ]
- )
-
- alertPresenter.showAlert(presentation: presentation, animated: true)
- }
}
diff --git a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewModel.swift b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewModel.swift
index 1c125e19fd..457a8928ca 100644
--- a/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewModel.swift
+++ b/ios/MullvadVPN/View controllers/VPNSettings/VPNSettingsViewModel.swift
@@ -101,7 +101,6 @@ struct VPNSettingsViewModel: Equatable {
private(set) var quantumResistance: TunnelQuantumResistance
private(set) var multihopState: MultihopState
- private(set) var daitaSettings: DAITASettings
static let defaultWireGuardPorts: [UInt16] = [51820, 53]
@@ -191,10 +190,6 @@ struct VPNSettingsViewModel: Equatable {
multihopState = newState
}
- mutating func setDAITASettings(_ newSettings: DAITASettings) {
- daitaSettings = newSettings
- }
-
/// Precondition for enabling Custom DNS.
var customDNSPrecondition: CustomDNSPrecondition {
if blockAdvertising || blockTracking || blockMalware ||
@@ -251,7 +246,6 @@ struct VPNSettingsViewModel: Equatable {
quantumResistance = tunnelSettings.tunnelQuantumResistance
multihopState = tunnelSettings.tunnelMultihopState
- daitaSettings = tunnelSettings.daita
}
/// Produce merged view model keeping entry `identifier` for matching DNS entries.