Skip to content

Commit

Permalink
Add UI for DAITA in VPN settings
Browse files Browse the repository at this point in the history
  • Loading branch information
mojganii committed Aug 28, 2024
1 parent e1af89b commit a0f226c
Show file tree
Hide file tree
Showing 14 changed files with 314 additions and 120 deletions.
4 changes: 4 additions & 0 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,7 @@
F08B6B7D2C528C6300D0A121 /* PostQuantumKeyExchangingPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F05919762C453FAF00C301F3 /* PostQuantumKeyExchangingPipeline.swift */; };
F08B6B7E2C528C6300D0A121 /* MultiHopPostQuantumKeyExchanging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F059197C2C454C9200C301F3 /* MultiHopPostQuantumKeyExchanging.swift */; };
F08B6B822C52931600D0A121 /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = F08B6B812C52931600D0A121 /* WireGuardKitTypes */; };
F09084682C6E88ED001CD36E /* DaitaPromptAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09084672C6E88ED001CD36E /* DaitaPromptAlert.swift */; };
F09A297B2A9F8A9B00EA3B6F /* LogoutDialogueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09A29782A9F8A9B00EA3B6F /* LogoutDialogueView.swift */; };
F09A297C2A9F8A9B00EA3B6F /* VoucherTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09A29792A9F8A9B00EA3B6F /* VoucherTextField.swift */; };
F09A297D2A9F8A9B00EA3B6F /* RedeemVoucherContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09A297A2A9F8A9B00EA3B6F /* RedeemVoucherContentView.swift */; };
Expand Down Expand Up @@ -2106,6 +2107,7 @@
F07BF2572A26112D00042943 /* InputTextFormatterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputTextFormatterTests.swift; sourceTree = "<group>"; };
F07BF2612A26279100042943 /* RedeemVoucherOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedeemVoucherOperation.swift; sourceTree = "<group>"; };
F07CFF1F29F2720E008C0343 /* RegisteredDeviceInAppNotificationProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisteredDeviceInAppNotificationProvider.swift; sourceTree = "<group>"; };
F09084672C6E88ED001CD36E /* DaitaPromptAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaitaPromptAlert.swift; sourceTree = "<group>"; };
F09A29782A9F8A9B00EA3B6F /* LogoutDialogueView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogoutDialogueView.swift; sourceTree = "<group>"; };
F09A29792A9F8A9B00EA3B6F /* VoucherTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoucherTextField.swift; sourceTree = "<group>"; };
F09A297A2A9F8A9B00EA3B6F /* RedeemVoucherContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedeemVoucherContentView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3932,6 +3934,7 @@
85021CAD2BDBC4290098B400 /* AppLogsPage.swift */,
8587A05C2B84D43100152938 /* ChangeLogAlert.swift */,
A9BFB0002BD00B7F00F2BCA1 /* CustomListPage.swift */,
F09084672C6E88ED001CD36E /* DaitaPromptAlert.swift */,
85A42B872BB44D31007BABF7 /* DeviceManagementPage.swift */,
852A26452BA9C9CB006EB9C8 /* DNSSettingsPage.swift */,
8585CBE22BC684180015B6A4 /* EditAccessMethodPage.swift */,
Expand Down Expand Up @@ -6067,6 +6070,7 @@
85EC620C2B838D10005AFFB5 /* MullvadAPIWrapper.swift in Sources */,
A9DF789D2B7D1E8B0094E4AD /* LoggedInWithTimeUITestCase.swift in Sources */,
85D2B0B12B6BD32400DF9DA7 /* BaseUITestCase.swift in Sources */,
F09084682C6E88ED001CD36E /* DaitaPromptAlert.swift in Sources */,
8529693C2B4F0257007EAD4C /* Alert.swift in Sources */,
8542F7532BCFBD050035C042 /* SelectLocationFilterPage.swift in Sources */,
850201DD2B503D8C00EF8C96 /* SelectLocationPage.swift in Sources */,
Expand Down
9 changes: 6 additions & 3 deletions ios/MullvadVPN/Classes/AccessbilityIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ public enum AccessibilityIdentifier: String {
case cityLocationCell
case relayLocationCell
case customListLocationCell
case multihopConfirmAlertBackButton
case multihopConfirmAlertEnableButton
case daitaConfirmAlertBackButton
case daitaConfirmAlertEnableButton

// Labels
case accountPageDeviceNameLabel
Expand Down Expand Up @@ -190,14 +190,17 @@ public enum AccessibilityIdentifier: String {
case dnsServer
case dnsServerInfo

// DAITA
case daitaSwitch
case daitaPromptAlert

// Quantum resistance
case quantumResistanceAutomatic
case quantumResistanceOff
case quantumResistanceOn

// Multihop
case multihopSwitch
case multihopPromptAlert

// Error
case unknown
Expand Down
3 changes: 3 additions & 0 deletions ios/MullvadVPN/View controllers/Login/LoginContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class LoginContentView: UIView {
let statusActivityView: StatusActivityView = {
let statusActivityView = StatusActivityView(state: .hidden)
statusActivityView.translatesAutoresizingMaskIntoConstraints = false
statusActivityView.clipsToBounds = true
return statusActivityView
}()

Expand Down Expand Up @@ -151,6 +152,8 @@ class LoginContentView: UIView {
createAccountButton.pinEdges(.all().excluding(.top), to: footerContainer.layoutMarginsGuide)

statusActivityView.centerXAnchor.constraint(equalTo: contentContainer.centerXAnchor)
statusActivityView.widthAnchor.constraint(equalToConstant: 60.0)
statusActivityView.heightAnchor.constraint(equalTo: statusActivityView.widthAnchor, multiplier: 1.0)

formContainer.topAnchor.constraint(equalTo: statusActivityView.bottomAnchor, constant: 30)
formContainer.centerYAnchor.constraint(equalTo: contentContainer.centerYAnchor, constant: -20)
Expand Down
11 changes: 0 additions & 11 deletions ios/MullvadVPN/View controllers/Login/LoginViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -256,17 +256,6 @@ class LoginViewController: UIViewController, RootContainment {

private func updateStatusIcon() {
contentView.statusActivityView.state = loginState.statusActivityState

switch loginState {
case .authenticating:
contentView.statusActivityView.accessibilityIdentifier = .loginStatusIconAuthenticating
case .failure:
contentView.statusActivityView.accessibilityIdentifier = .loginStatusIconFailure
case .success:
contentView.statusActivityView.accessibilityIdentifier = .loginStatusIconSuccess
default:
break
}
}

private func beginLogin(_ action: LoginAction) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ protocol VPNSettingsCellEventHandler {
func selectCustomPortEntry(_ port: UInt16) -> Bool
func selectObfuscationState(_ state: WireGuardObfuscationState)
func switchMultihop(_ state: MultihopState)
func switchDaitaState(_ settings: DAITASettings)
}

final class VPNSettingsCellFactory: CellFactoryProtocol {
Expand Down Expand Up @@ -170,7 +171,6 @@ final class VPNSettingsCellFactory: CellFactoryProtocol {
)
cell.accessibilityIdentifier = "\(item.accessibilityIdentifier.rawValue)\(portString)"
cell.applySubCellStyling()

case .quantumResistanceAutomatic:
guard let cell = cell as? SelectableSettingsCell else { return }

Expand Down Expand Up @@ -206,13 +206,34 @@ final class VPNSettingsCellFactory: CellFactoryProtocol {
cell.accessibilityIdentifier = item.accessibilityIdentifier
cell.applySubCellStyling()

case .multihop:
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.state.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(state: state))
}

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

cell.titleLabel.text = NSLocalizedString(
"MULTIHOP_LABEL",
tableName: "VPNSettings",
value: "Enable multihop",
value: "Multihop",
comment: ""
)
cell.accessibilityIdentifier = item.accessibilityIdentifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
case wireGuardObfuscationPort
case quantumResistance
case multihop
case daita
var reusableViewClass: AnyClass {
switch self {
case .dnsSettings:
Expand All @@ -42,12 +43,14 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
return SelectableSettingsCell.self
case .multihop:
return SettingsSwitchCell.self
case .daita:
return SettingsSwitchCell.self
}
}
}

private enum HeaderFooterReuseIdentifiers: String, CaseIterable {
case wireGuardPortHeader
case settingsHeaderView

var reusableViewClass: AnyClass {
return SettingsHeaderView.self
Expand All @@ -61,7 +64,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
case wireGuardObfuscation
case wireGuardObfuscationPort
case quantumResistance
case multiHop
case privacyAndSecurity
}

enum Item: Hashable {
Expand All @@ -76,7 +79,8 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
case quantumResistanceAutomatic
case quantumResistanceOn
case quantumResistanceOff
case multihop
case multihopSwitch
case daitaSwitch

static var wireGuardPorts: [Item] {
let defaultPorts = VPNSettingsViewModel.defaultWireGuardPorts.map {
Expand Down Expand Up @@ -121,7 +125,9 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
return .quantumResistanceOn
case .quantumResistanceOff:
return .quantumResistanceOff
case .multihop:
case .daitaSwitch:
return .daitaSwitch
case .multihopSwitch:
return .multihopSwitch
}
}
Expand All @@ -142,8 +148,10 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
return .wireGuardObfuscationPort
case .quantumResistanceAutomatic, .quantumResistanceOn, .quantumResistanceOff:
return .quantumResistance
case .multihop:
case .multihopSwitch:
return .multihop
case .daitaSwitch:
return .daita
}
}
}
Expand Down Expand Up @@ -319,8 +327,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<

guard let view = tableView
.dequeueReusableHeaderFooterView(
withIdentifier: HeaderFooterReuseIdentifiers.wireGuardPortHeader
.rawValue
withIdentifier: HeaderFooterReuseIdentifiers.settingsHeaderView.rawValue
) as? SettingsHeaderView else { return nil }

switch sectionIdentifier {
Expand Down Expand Up @@ -353,8 +360,8 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
let sectionIdentifier = snapshot().sectionIdentifiers[section]

switch sectionIdentifier {
case .dnsSettings, .ipOverrides, .multiHop:
return 0
case .dnsSettings, .ipOverrides, .privacyAndSecurity:
return .leastNonzeroMagnitude
default:
return tableView.estimatedRowHeight
}
Expand All @@ -375,7 +382,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
let sectionIdentifier = snapshot().sectionIdentifiers[indexPath.section]

return switch sectionIdentifier {
case .multiHop: false
case .privacyAndSecurity: false
default: true
}
}
Expand All @@ -392,7 +399,7 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<

tableView?.register(
SettingsHeaderView.self,
forHeaderFooterViewReuseIdentifier: HeaderFooterReuseIdentifiers.wireGuardPortHeader.rawValue
forHeaderFooterViewReuseIdentifier: HeaderFooterReuseIdentifiers.settingsHeaderView.rawValue
)
}

Expand All @@ -412,7 +419,11 @@ final class VPNSettingsDataSource: UITableViewDiffableDataSource<
snapshot.appendItems([.dnsSettings], toSection: .dnsSettings)
snapshot.appendItems([.ipOverrides], toSection: .ipOverrides)

snapshot.appendItems([.multihop], toSection: .multiHop)
#if DEBUG
snapshot.appendItems([.daitaSwitch, .multihopSwitch], toSection: .privacyAndSecurity)
#else
snapshot.appendItems([.multihopSwitch], toSection: .privacyAndSecurity)
#endif

applySnapshot(snapshot, animated: animated, completion: completion)
}
Expand Down Expand Up @@ -620,6 +631,22 @@ extension VPNSettingsDataSource: VPNSettingsCellEventHandler {
viewModel.setMultihop(state)
delegate?.didChangeViewModel(viewModel)
}

func switchDaitaState(_ settings: DAITASettings) {
if settings.state.isEnabled {
delegate?.showPrompt(for: .daita) { [weak self] in
guard let self else { return }
viewModel.setDAITASettings(settings)
delegate?.didChangeViewModel(viewModel)
} onDiscard: { [weak self] in
guard let self else { return }
tableView?.reloadData()
}
} else {
viewModel.setDAITASettings(settings)
delegate?.didChangeViewModel(viewModel)
}
}
}

// swiftlint:disable:this file_length
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ protocol VPNSettingsDataSourceDelegate: AnyObject {
func showDNSSettings()
func showIPOverrides()
func didSelectWireGuardPort(_ port: UInt16?)
func showPrompt(for: VPNSettingsPromptAlertItem, onSave: @escaping () -> Void, onDiscard: @escaping () -> Void)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ enum VPNSettingsInfoButtonItem {
case wireGuardObfuscationPort
case quantumResistance
case multihop
case daita
}

enum VPNSettingsPromptAlertItem {
case daita
}
Loading

0 comments on commit a0f226c

Please sign in to comment.