summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBug Magnet <marco.nikic@mullvad.net>2025-05-23 13:37:40 +0200
committerBug Magnet <marco.nikic@mullvad.net>2025-05-23 13:37:40 +0200
commitb10275936d3a987220082933c4057c3d72ca2647 (patch)
treef638b0016563c9b8e62ee82bd76127d1c6171003
parent976b143a220b1b65a2a4d7004cd40688c25da79b (diff)
parent6b4547b0993b13595bdd1e5857b04ccb4903df52 (diff)
downloadmullvadvpn-b10275936d3a987220082933c4057c3d72ca2647.tar.xz
mullvadvpn-b10275936d3a987220082933c4057c3d72ca2647.zip
Merge branch 'adopt-api-access-enabledisable-logic-like-android-does-ios-1063'
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift3
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift1
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodInteractor.swift26
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodSectionIdentifier.swift10
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift5
-rw-r--r--ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel.swift3
-rw-r--r--ios/MullvadVPNUITests/AccessMethodsTests.swift37
-rw-r--r--ios/MullvadVPNUITests/Pages/EditAccessMethodPage.swift5
8 files changed, 88 insertions, 2 deletions
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift
index 54794917a8..8a68a72164 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentConfiguration.swift
@@ -32,6 +32,9 @@ struct SwitchCellContentConfiguration: UIContentConfiguration, Equatable {
/// Content view layout margins.
var directionalLayoutMargins: NSDirectionalEdgeInsets = UIMetrics.SettingsCell.apiAccessInsetLayoutMargins
+ /// Whether the toggle is enabled or disabled
+ var isEnabled = true
+
func makeContentView() -> UIView & UIContentView {
return SwitchCellContentView(configuration: self)
}
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift
index db77e8b8d7..cbf50170aa 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Cells/SwitchCellContentView.swift
@@ -77,6 +77,7 @@ class SwitchCellContentView: UIView, UIContentView, UITextFieldDelegate {
switchContainer.control.isOn = actualConfiguration.isOn
switchContainer.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)
switchContainer.setAccessibilityIdentifier(actualConfiguration.accessibilityIdentifier)
+ switchContainer.isEnabled = actualConfiguration.isEnabled
}
private func addSubviews() {
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodInteractor.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodInteractor.swift
index ee33e376d4..7770c3b2e1 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodInteractor.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodInteractor.swift
@@ -15,14 +15,40 @@ struct EditAccessMethodInteractor: EditAccessMethodInteractorProtocol {
let repository: AccessMethodRepositoryProtocol
let proxyConfigurationTester: ProxyConfigurationTesterProtocol
+ init(
+ subject: CurrentValueSubject<AccessMethodViewModel, Never>,
+ repository: AccessMethodRepositoryProtocol,
+ proxyConfigurationTester: ProxyConfigurationTesterProtocol
+ ) {
+ self.subject = subject
+ self.repository = repository
+ self.proxyConfigurationTester = proxyConfigurationTester
+ checkIfSwitchCanBeToggled()
+ }
+
+ // The access method can only be disabled if at least one other method is enabled
+ private func checkIfSwitchCanBeToggled() {
+ let enabledMethodsCount = repository.fetchAll().count { $0.isEnabled }
+ if enabledMethodsCount < 2 {
+ subject.value.canBeToggled = !subject.value.isEnabled
+ } else {
+ subject.value.canBeToggled = true
+ }
+ }
+
func saveAccessMethod() {
guard let persistentMethod = try? subject.value.intoPersistentAccessMethod() else { return }
repository.save(persistentMethod)
+ checkIfSwitchCanBeToggled()
}
func deleteAccessMethod() {
repository.delete(id: subject.value.id)
+ // Enable direct access if all methods are disabled
+ if repository.fetchAll().count(where: { $0.isEnabled }) == 0 {
+ repository.save(repository.directAccess)
+ }
}
func startProxyConfigurationTest(_ completion: (@Sendable (Bool) -> Void)?) {
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodSectionIdentifier.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodSectionIdentifier.swift
index 79f9bbae80..be0a05b4d2 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodSectionIdentifier.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodSectionIdentifier.swift
@@ -26,8 +26,14 @@ enum EditAccessMethodSectionIdentifier: Hashable {
value: "Performs a connection test to a Mullvad API server via this access method.",
comment: ""
)
-
- case .enableMethod, .methodSettings, .cancelTest, .testingStatus, .deleteMethod:
+ case .enableMethod:
+ NSLocalizedString(
+ "METHOD_FOOTER",
+ tableName: "APIAccess",
+ value: "At least one method needs to be enabled.",
+ comment: ""
+ )
+ case .methodSettings, .cancelTest, .testingStatus, .deleteMethod:
nil
}
}
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift
index ca05439678..4d0440fb07 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Edit/EditAccessMethodViewController.swift
@@ -140,6 +140,9 @@ extension EditAccessMethodViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
guard let sectionIdentifier = dataSource?.snapshot().sectionIdentifiers[section] else { return nil }
+ if sectionIdentifier == .enableMethod && subject.value.canBeToggled {
+ return nil
+ }
guard let sectionFooterText = sectionIdentifier.sectionFooter else { return nil }
guard let headerView = tableView
@@ -250,6 +253,8 @@ extension EditAccessMethodViewController: UITableViewDelegate {
self?.onSave()
}
}
+
+ contentConfiguration.isEnabled = subject.value.canBeToggled
cell.contentConfiguration = contentConfiguration
}
diff --git a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel.swift b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel.swift
index e6b98f96d0..56a31ce75d 100644
--- a/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel.swift
+++ b/ios/MullvadVPN/Coordinators/Settings/APIAccess/Models/AccessMethodViewModel.swift
@@ -63,6 +63,9 @@ struct AccessMethodViewModel: Identifiable {
/// The flag indicating whether configuration is enabled.
var isEnabled = true
+ /// The flag indicating whether configuration is enabled.
+ var canBeToggled = true
+
/// The status of testing the entered proxy configuration.
var testingStatus: TestingStatus = .initial
diff --git a/ios/MullvadVPNUITests/AccessMethodsTests.swift b/ios/MullvadVPNUITests/AccessMethodsTests.swift
index 37ec9e832d..30f8cdf48c 100644
--- a/ios/MullvadVPNUITests/AccessMethodsTests.swift
+++ b/ios/MullvadVPNUITests/AccessMethodsTests.swift
@@ -56,4 +56,41 @@ class AccessMethodsTests: LoggedOutUITestCase {
.tapTestMethodButton()
.verifyTestStatus(.reachable)
}
+
+ func testCanNotDisableLast() throws {
+ HeaderBar(app)
+ .tapSettingsButton()
+
+ SettingsPage(app)
+ .tapAPIAccessCell()
+
+ APIAccessPage(app)
+ .getAccessMethodCell(
+ accessibilityId: AccessibilityIdentifier.accessMethodDirectCell
+ )
+ .tap()
+
+ EditAccessMethodPage(app)
+ .tapEnableMethodSwitch()
+ .tapBackButton()
+
+ APIAccessPage(app)
+ .getAccessMethodCell(
+ accessibilityId: AccessibilityIdentifier.accessMethodBridgesCell
+ )
+ .tap()
+
+ EditAccessMethodPage(app)
+ .tapEnableMethodSwitch()
+ .tapBackButton()
+
+ APIAccessPage(app)
+ .getAccessMethodCell(
+ accessibilityId: AccessibilityIdentifier.accessMethodEncryptedDNSCell
+ )
+ .tap()
+
+ EditAccessMethodPage(app)
+ .verifySwitchDisabled()
+ }
}
diff --git a/ios/MullvadVPNUITests/Pages/EditAccessMethodPage.swift b/ios/MullvadVPNUITests/Pages/EditAccessMethodPage.swift
index 0941f8edab..bebcf92d12 100644
--- a/ios/MullvadVPNUITests/Pages/EditAccessMethodPage.swift
+++ b/ios/MullvadVPNUITests/Pages/EditAccessMethodPage.swift
@@ -59,4 +59,9 @@ class EditAccessMethodPage: Page {
backButton.tap()
return self
}
+
+ @discardableResult func verifySwitchDisabled() -> Self {
+ XCTAssertFalse(app.switches[AccessibilityIdentifier.accessMethodEnableSwitch].isEnabled)
+ return self
+ }
}