summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBug Magnet <marco.nikic@mullvad.net>2024-12-09 16:00:34 +0100
committerBug Magnet <marco.nikic@mullvad.net>2024-12-09 16:42:48 +0100
commitd71e66a93dde36afb192bcf24e40c70596d85e2f (patch)
treea414d1c664125f9d8a19a484928b97a2ddfed575
parentedaf51e5a559112b9547359717a02fc80de1c1f9 (diff)
downloadmullvadvpn-dynamic-include-all-networks.tar.xz
mullvadvpn-dynamic-include-all-networks.zip
Add dynamic toggles for IANdynamic-include-all-networks
-rw-r--r--ios/MullvadTypes/Protocols/EphemeralPeerReceiver.swift2
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj10
-rw-r--r--ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift8
-rw-r--r--ios/MullvadVPN/TunnelManager/Tunnel.swift11
-rw-r--r--ios/MullvadVPN/TunnelManager/TunnelManager.swift36
-rw-r--r--ios/MullvadVPN/TunnelManager/UpdateTunnelConfigurationOperation.swift122
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift97
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift3
-rw-r--r--ios/MullvadVPN/View controllers/Tunnel/TunnelViewControllerInteractor.swift4
9 files changed, 284 insertions, 9 deletions
diff --git a/ios/MullvadTypes/Protocols/EphemeralPeerReceiver.swift b/ios/MullvadTypes/Protocols/EphemeralPeerReceiver.swift
index 6f208bc869..bd60aebc62 100644
--- a/ios/MullvadTypes/Protocols/EphemeralPeerReceiver.swift
+++ b/ios/MullvadTypes/Protocols/EphemeralPeerReceiver.swift
@@ -22,7 +22,7 @@ public class EphemeralPeerReceiver: EphemeralPeerReceiving, TunnelProvider {
unowned let tunnelProvider: any TunnelProvider
let keyReceiver: any EphemeralPeerReceiving
- public init(tunnelProvider: TunnelProvider, keyReceiver: any EphemeralPeerReceiving ) {
+ public init(tunnelProvider: TunnelProvider, keyReceiver: any EphemeralPeerReceiving) {
self.tunnelProvider = tunnelProvider
self.keyReceiver = keyReceiver
}
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index fd58a53daf..11284db6fe 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -850,6 +850,8 @@
A9B6AC182ADE8F4300F7802A /* MigrationManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B6AC172ADE8F4300F7802A /* MigrationManagerTests.swift */; };
A9B6AC1A2ADE8FBB00F7802A /* InMemorySettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B6AC192ADE8FBB00F7802A /* InMemorySettingsStore.swift */; };
A9B6AC1B2ADEA3AD00F7802A /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BDEB9C2A98F69E00F578F2 /* MemoryCache.swift */; };
+ A9B97ECD2D072CB70001A3ED /* UpdateTunnelConfigurationOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B97ECC2D072CB70001A3ED /* UpdateTunnelConfigurationOperation.swift */; };
+ A9B97ECE2D072CB70001A3ED /* UpdateTunnelConfigurationOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B97ECC2D072CB70001A3ED /* UpdateTunnelConfigurationOperation.swift */; };
A9BA08312BA32FA9005A7A2D /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A92962582B1F4FDB00DFB93B /* PrivacyInfo.xcprivacy */; };
A9BA08322BA32FB6005A7A2D /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = A92962582B1F4FDB00DFB93B /* PrivacyInfo.xcprivacy */; };
A9BD4D552CA58C3700C8A0E6 /* RESTTransportStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = A932D9F42B5EBB9D00999395 /* RESTTransportStub.swift */; };
@@ -2119,6 +2121,7 @@
A9A8A8EA2A262AB30086D569 /* FileCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileCache.swift; sourceTree = "<group>"; };
A9B6AC172ADE8F4300F7802A /* MigrationManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationManagerTests.swift; sourceTree = "<group>"; };
A9B6AC192ADE8FBB00F7802A /* InMemorySettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InMemorySettingsStore.swift; sourceTree = "<group>"; };
+ A9B97ECC2D072CB70001A3ED /* UpdateTunnelConfigurationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateTunnelConfigurationOperation.swift; sourceTree = "<group>"; };
A9BFAFFE2BD004ED00F2BCA1 /* CustomListsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomListsTests.swift; sourceTree = "<group>"; };
A9BFB0002BD00B7F00F2BCA1 /* CustomListPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomListPage.swift; sourceTree = "<group>"; };
A9C308392C19DDA7008715F1 /* MullvadPostQuantum+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MullvadPostQuantum+Stubs.swift"; sourceTree = "<group>"; };
@@ -2780,6 +2783,7 @@
58421031282E42B000F24E46 /* UpdateDeviceDataOperation.swift */,
A9F360332AAB626300F53531 /* VPNConnectionProtocol.swift */,
581DA2742A1E283E0046ED47 /* WgKeyRotation.swift */,
+ A9B97ECC2D072CB70001A3ED /* UpdateTunnelConfigurationOperation.swift */,
);
path = TunnelManager;
sourceTree = "<group>";
@@ -5589,6 +5593,7 @@
A9A5FA2B2ACB05160083449F /* CustomDateComponentsFormattingTests.swift in Sources */,
A9A5FA2C2ACB05160083449F /* DeviceCheckOperationTests.swift in Sources */,
A9A5FA2D2ACB05160083449F /* DurationTests.swift in Sources */,
+ A9B97ECE2D072CB70001A3ED /* UpdateTunnelConfigurationOperation.swift in Sources */,
A9A5FA2E2ACB05160083449F /* FileCacheTests.swift in Sources */,
7A9F28FC2CA69D0C005F2089 /* DAITASettingsTests.swift in Sources */,
A9A5FA2F2ACB05160083449F /* FixedWidthIntegerArithmeticsTests.swift in Sources */,
@@ -6083,6 +6088,7 @@
7AF10EB22ADE859200C090B9 /* AlertViewController.swift in Sources */,
587D9676288989DB00CD8F1C /* NSLayoutConstraint+Helpers.swift in Sources */,
F028A56C2A34D8E600C0CAA3 /* AddCreditSucceededViewController.swift in Sources */,
+ A9B97ECD2D072CB70001A3ED /* UpdateTunnelConfigurationOperation.swift in Sources */,
58293FAE2510CA58005D0BB5 /* ProblemReportViewController.swift in Sources */,
58B9EB152489139B00095626 /* RESTError+Display.swift in Sources */,
587B753F2668E5A700DEF7E9 /* NotificationContainerView.swift in Sources */,
@@ -7300,6 +7306,7 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSION_INFO_PREFIX = "";
};
@@ -7335,6 +7342,7 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSION_INFO_PREFIX = "";
};
@@ -7978,6 +7986,7 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSION_INFO_PREFIX = "";
};
@@ -8808,6 +8817,7 @@
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSION_INFO_PREFIX = "";
};
diff --git a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift
index 6a32e1192f..6871c024f9 100644
--- a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift
+++ b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift
@@ -115,8 +115,12 @@ class StartTunnelOperation: ResultOperation<Void> {
let protocolConfig = NETunnelProviderProtocol()
protocolConfig.providerBundleIdentifier = ApplicationTarget.packetTunnel.bundleIdentifier
protocolConfig.serverAddress = ""
- protocolConfig.includeAllNetworks = true
- protocolConfig.excludeLocalNetworks = false
+
+ let includeAllNetworks = UserDefaults.standard.bool(forKey: "includeAllNetworks")
+ let excludeLocalNetworks = UserDefaults.standard.bool(forKey: "excludeLocalNetworks")
+
+ protocolConfig.includeAllNetworks = includeAllNetworks
+ protocolConfig.excludeLocalNetworks = excludeLocalNetworks
let alwaysOnRule = NEOnDemandRuleConnect()
alwaysOnRule.interfaceTypeMatch = .any
diff --git a/ios/MullvadVPN/TunnelManager/Tunnel.swift b/ios/MullvadVPN/TunnelManager/Tunnel.swift
index 9489998ef6..f7cd642172 100644
--- a/ios/MullvadVPN/TunnelManager/Tunnel.swift
+++ b/ios/MullvadVPN/TunnelManager/Tunnel.swift
@@ -41,6 +41,7 @@ protocol TunnelProtocol: AnyObject {
func saveToPreferences(_ completion: @escaping (Error?) -> Void)
func removeFromPreferences(completion: @escaping (Error?) -> Void)
+ func updatePreferences(_ completion: @escaping (Error?) -> Void)
func setConfiguration(_ configuration: TunnelConfiguration)
func start(options: [String: NSObject]?) throws
@@ -148,6 +149,16 @@ final class Tunnel: TunnelProtocol, Equatable {
configuration.apply(to: tunnelProvider)
}
+ func updatePreferences(_ completion: @escaping (Error?) -> Void) {
+ tunnelProvider.loadFromPreferences { [weak self] error in
+ if let error {
+ completion(error)
+ } else {
+ self?.tunnelProvider.saveToPreferences(completionHandler: completion)
+ }
+ }
+ }
+
func saveToPreferences(_ completion: @escaping (Error?) -> Void) {
tunnelProvider.saveToPreferences { error in
if let error {
diff --git a/ios/MullvadVPN/TunnelManager/TunnelManager.swift b/ios/MullvadVPN/TunnelManager/TunnelManager.swift
index 4703fe3cda..b8acbb3870 100644
--- a/ios/MullvadVPN/TunnelManager/TunnelManager.swift
+++ b/ios/MullvadVPN/TunnelManager/TunnelManager.swift
@@ -217,6 +217,42 @@ final class TunnelManager: StorePaymentObserver {
operationQueue.addOperation(loadTunnelOperation)
}
+ func updateTunnel(completionHandler: ((Error?) -> Void)? = nil) {
+ let operation = UpdateTunnelConfigurationOperation(
+ interactor: TunnelInteractorProxy(self),
+ dispatchQueue: internalQueue,
+ completionHandler: { [weak self] result in
+ guard let self else { return }
+
+ DispatchQueue.main.async {
+ if let error = result.error {
+ self.logger.error(
+ error: error,
+ message: "Failed to Update the tunnel."
+ )
+
+ let tunnelError = StartTunnelError(underlyingError: error)
+
+ self.observerList.notify { observer in
+ observer.tunnelManager(self, didFailWithError: tunnelError)
+ }
+ }
+
+ completionHandler?(result.error)
+ }
+ }
+ )
+
+ operation.addObserver(BackgroundObserver(
+ backgroundTaskProvider: backgroundTaskProvider,
+ name: "Update tunnel Configuration",
+ cancelUponExpiration: true
+ ))
+ operation.addCondition(MutuallyExclusive(category: OperationCategory.manageTunnel.category))
+
+ operationQueue.addOperation(operation)
+ }
+
func startTunnel(completionHandler: ((Error?) -> Void)? = nil) {
let operation = StartTunnelOperation(
dispatchQueue: internalQueue,
diff --git a/ios/MullvadVPN/TunnelManager/UpdateTunnelConfigurationOperation.swift b/ios/MullvadVPN/TunnelManager/UpdateTunnelConfigurationOperation.swift
new file mode 100644
index 0000000000..9d43291ebd
--- /dev/null
+++ b/ios/MullvadVPN/TunnelManager/UpdateTunnelConfigurationOperation.swift
@@ -0,0 +1,122 @@
+//
+// UpdateTunnelConfigurationOperation.swift
+// MullvadVPN
+//
+// Created by Marco Nikic on 2024-12-09.
+// Copyright © 2024 Mullvad VPN AB. All rights reserved.
+//
+
+import Foundation
+import MullvadLogging
+import NetworkExtension
+import Operations
+import PacketTunnelCore
+
+class UpdateTunnelConfigurationOperation: ResultOperation<Void> {
+ typealias EncodeErrorHandler = (Error) -> Void
+
+ private let logger = Logger(label: "UpdateTunnelOperation")
+ private let interactor: TunnelInteractor
+
+ init(interactor: TunnelInteractor, dispatchQueue: DispatchQueue, completionHandler: @escaping CompletionHandler) {
+ self.interactor = interactor
+
+ super.init(dispatchQueue: dispatchQueue, completionQueue: dispatchQueue, completionHandler: completionHandler)
+ }
+
+ override func main() {
+ guard case .loggedIn = interactor.deviceState else {
+ finish(result: .failure(InvalidDeviceStateError()))
+ return
+ }
+
+ switch interactor.tunnelStatus.state {
+ case .disconnected, .disconnecting:
+ finish(result: .success(()))
+
+ case .connected, .error, .waitingForConnectivity, .connecting, .reconnecting, .negotiatingEphemeralPeer,
+ .pendingReconnect:
+ makeTunnelProviderAndUpdateTunnel { error in
+ self.finish(result: error.map { .failure($0) } ?? .success(()))
+ }
+ }
+ }
+
+ private func makeTunnelProviderAndUpdateTunnel(completionHandler: @escaping (Error?) -> Void) {
+ updateTunnelProvider { result in
+ self.dispatchQueue.async {
+ do {
+ try self.updateTunnel(tunnel: result.get())
+ } catch {
+ completionHandler(error)
+ }
+ }
+ }
+ }
+
+ private func updateTunnel(tunnel: any TunnelProtocol) throws {
+ let selectedRelays = try? interactor.selectRelays()
+ var tunnelOptions = PacketTunnelOptions()
+
+ do {
+ if let selectedRelays {
+ try tunnelOptions.setSelectedRelays(selectedRelays)
+ }
+ } catch {
+ logger.error(
+ error: error,
+ message: "Failed to encode the selector result."
+ )
+ }
+
+ interactor.setTunnel(tunnel, shouldRefreshTunnelState: true)
+
+ interactor.updateTunnelStatus { tunnelStatus in
+ tunnelStatus = TunnelStatus()
+ tunnelStatus.state = .connecting(
+ selectedRelays,
+ isPostQuantum: interactor.settings.tunnelQuantumResistance.isEnabled,
+ isDaita: interactor.settings.daita.daitaState.isEnabled
+ )
+ }
+
+ _ = tunnel.reconnectTunnel(to: .current) { [weak self] result in
+ self?.finish(result: result)
+ }
+ }
+
+ private func updateTunnelProvider(completionHandler: @escaping (Result<any TunnelProtocol, Error>) -> Void) {
+ let persistentTunnels = interactor.getPersistentTunnels()
+ let tunnel = persistentTunnels.first!
+ let configuration = Self.makeTunnelConfiguration()
+
+// tunnel.removeFromPreferences(completion: { _ in })
+ tunnel.setConfiguration(configuration)
+ tunnel.updatePreferences { error in
+ completionHandler(error.map { .failure($0) } ?? .success(tunnel))
+ }
+ }
+
+ private class func makeTunnelConfiguration() -> TunnelConfiguration {
+ let protocolConfig = NETunnelProviderProtocol()
+ protocolConfig.providerBundleIdentifier = ApplicationTarget.packetTunnel.bundleIdentifier
+ protocolConfig.serverAddress = ""
+
+ let includeAllNetworks = UserDefaults.standard.bool(forKey: "includeAllNetworks")
+ let excludeLocalNetworks = UserDefaults.standard.bool(forKey: "excludeLocalNetworks")
+
+ protocolConfig.includeAllNetworks = includeAllNetworks
+ protocolConfig.excludeLocalNetworks = excludeLocalNetworks
+
+ let alwaysOnRule = NEOnDemandRuleConnect()
+ alwaysOnRule.interfaceTypeMatch = .any
+
+ return TunnelConfiguration(
+ isEnabled: true,
+ localizedDescription: "WireGuard",
+ protocolConfiguration: protocolConfig,
+ onDemandRules: [alwaysOnRule],
+ isOnDemandEnabled: true
+ )
+ }
+}
diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift
index b95376590f..288f327978 100644
--- a/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift
+++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelControlView.swift
@@ -17,6 +17,7 @@ enum TunnelControlAction {
case disconnect
case cancel
case reconnect
+ case updateTunnel
case selectLocation
}
@@ -32,6 +33,41 @@ final class TunnelControlView: UIView {
private let cityLabel = makeBoldTextLabel(ofSize: 34)
private let countryLabel = makeBoldTextLabel(ofSize: 34)
+ private let includeAllNetworksStackView: UIStackView = {
+ let view = UIStackView()
+ view.translatesAutoresizingMaskIntoConstraints = false
+ view.isAccessibilityElement = false
+ view.accessibilityTraits = .summaryElement
+ view.axis = .horizontal
+ view.spacing = 8
+ return view
+ }()
+
+ private let excludeLocalNetworksStackView: UIStackView = {
+ let view = UIStackView()
+ view.translatesAutoresizingMaskIntoConstraints = false
+ view.isAccessibilityElement = false
+ view.accessibilityTraits = .summaryElement
+ view.axis = .horizontal
+ view.spacing = 8
+ return view
+ }()
+
+ private let includeAllNetworksLabel = makeBoldTextLabel(ofSize: 15)
+ private let excludeLocalNetworksLabel = makeBoldTextLabel(ofSize: 15)
+
+ private let includeAllNetworksToggle: UISwitch = {
+ let switchButton = UISwitch()
+ switchButton.isOn = UserDefaults.standard.bool(forKey: "includeAllNetworks")
+ return switchButton
+ }()
+
+ private let excludeLocalNetworksToggle: UISwitch = {
+ let switchButton = UISwitch()
+ switchButton.isOn = UserDefaults.standard.bool(forKey: "excludeLocalNetworks")
+ return switchButton
+ }()
+
private let activityIndicator: SpinnerActivityIndicatorView = {
let activityIndicator = SpinnerActivityIndicatorView(style: .large)
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
@@ -41,6 +77,16 @@ final class TunnelControlView: UIView {
return activityIndicator
}()
+ private let debugContainerView: UIStackView = {
+ let view = UIStackView()
+ view.translatesAutoresizingMaskIntoConstraints = false
+ view.isAccessibilityElement = false
+ view.accessibilityTraits = .summaryElement
+ view.axis = .vertical
+ view.spacing = 8
+ return view
+ }()
+
private let locationContainerView: UIStackView = {
let view = UIStackView()
view.translatesAutoresizingMaskIntoConstraints = false
@@ -137,6 +183,13 @@ final class TunnelControlView: UIView {
let tunnelState = model.tunnelStatus.state
secureLabel.text = model.secureLabelText
secureLabel.textColor = tunnelState.textColorForSecureLabel
+
+ includeAllNetworksLabel.text = "Include All Networks"
+ includeAllNetworksLabel.textColor = .white
+
+ excludeLocalNetworksLabel.text = "Exclude Local Networks"
+ excludeLocalNetworksLabel.textColor = .white
+
selectLocationButtonBlurView.isEnabled = model.enableButtons
connectButtonBlurView.isEnabled = model.enableButtons
cityLabel.attributedText = attributedStringForLocation(string: model.city)
@@ -274,11 +327,23 @@ final class TunnelControlView: UIView {
// MARK: - Private
private func addSubviews() {
+ for subview in [includeAllNetworksLabel, includeAllNetworksToggle] {
+ includeAllNetworksStackView.addArrangedSubview(subview)
+ }
+
+ for subview in [excludeLocalNetworksLabel, excludeLocalNetworksToggle] {
+ excludeLocalNetworksStackView.addArrangedSubview(subview)
+ }
+
+ for subview in [includeAllNetworksStackView, excludeLocalNetworksStackView] {
+ debugContainerView.addArrangedSubview(subview)
+ }
+
for subview in [secureLabel, countryLabel, cityLabel, connectionPanel] {
locationContainerView.addArrangedSubview(subview)
}
- for subview in [activityIndicator, buttonsStackView, locationContainerView] {
+ for subview in [activityIndicator, buttonsStackView, locationContainerView, debugContainerView] {
containerView.addSubview(subview)
}
@@ -290,15 +355,22 @@ final class TunnelControlView: UIView {
containerView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor),
containerView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
- locationContainerView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor),
- locationContainerView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
- locationContainerView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
+ debugContainerView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor),
+ debugContainerView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
+ debugContainerView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
- activityIndicator.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
locationContainerView.topAnchor.constraint(
- equalTo: activityIndicator.bottomAnchor,
+ greaterThanOrEqualTo: debugContainerView.bottomAnchor,
constant: 22
),
+ locationContainerView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
+ locationContainerView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
+
+ activityIndicator.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
+// locationContainerView.topAnchor.constraint(
+// equalTo: activityIndicator.bottomAnchor,
+// constant: 22
+// ),
buttonsStackView.topAnchor.constraint(
equalTo: locationContainerView.bottomAnchor,
@@ -336,6 +408,9 @@ final class TunnelControlView: UIView {
action: #selector(handleSelectLocation),
for: .touchUpInside
)
+
+ includeAllNetworksToggle.addTarget(self, action: #selector(toggleIncludeAllNetwork), for: .valueChanged)
+ excludeLocalNetworksToggle.addTarget(self, action: #selector(toggleExcludeLocalNetworks), for: .valueChanged)
}
private func setArrangedButtons(_ newButtons: [UIView]) {
@@ -405,6 +480,16 @@ final class TunnelControlView: UIView {
@objc private func handleSelectLocation() {
actionHandler?(.selectLocation)
}
+
+ @objc private func toggleIncludeAllNetwork() {
+ UserDefaults.standard.set(includeAllNetworksToggle.isOn, forKey: "includeAllNetworks")
+ actionHandler?(.updateTunnel)
+ }
+
+ @objc private func toggleExcludeLocalNetworks() {
+ UserDefaults.standard.set(excludeLocalNetworksToggle.isOn, forKey: "excludeLocalNetworks")
+ actionHandler?(.updateTunnel)
+ }
}
private extension TunnelState {
diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift
index 7cf879f3bf..42b5dc5397 100644
--- a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift
+++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewController.swift
@@ -84,6 +84,9 @@ class TunnelViewController: UIViewController, RootContainment {
case .disconnect:
self?.interactor.stopTunnel()
+ case .updateTunnel:
+ self?.interactor.updateTunnel()
+
case .reconnect:
self?.interactor.reconnectTunnel(selectNewRelay: true)
diff --git a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewControllerInteractor.swift b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewControllerInteractor.swift
index 47b75fd7d5..479b5b3257 100644
--- a/ios/MullvadVPN/View controllers/Tunnel/TunnelViewControllerInteractor.swift
+++ b/ios/MullvadVPN/View controllers/Tunnel/TunnelViewControllerInteractor.swift
@@ -64,6 +64,10 @@ final class TunnelViewControllerInteractor {
self.tunnelObserver = tunnelObserver
}
+ func updateTunnel() {
+ tunnelManager.updateTunnel()
+ }
+
func startTunnel() {
tunnelManager.startTunnel()
}