summaryrefslogtreecommitdiffhomepage
path: root/ios
diff options
context:
space:
mode:
authorBug Magnet <marco.nikic@mullvad.net>2023-08-09 09:35:41 +0200
committerBug Magnet <marco.nikic@mullvad.net>2023-08-09 09:35:41 +0200
commit5deb1b781c2bb3318b91385762ee0cc64e83724e (patch)
tree903ef8832296469552cf38a695a65b562794a916 /ios
parent5d00739e09600c4e525c3b5687ddb4f7ec3931fe (diff)
parent62a11beb35df0741d7f0a444bde7dd02afa2b9f9 (diff)
downloadmullvadvpn-5deb1b781c2bb3318b91385762ee0cc64e83724e.tar.xz
mullvadvpn-5deb1b781c2bb3318b91385762ee0cc64e83724e.zip
Merge branch 'add-ui-controls-for-udp2tcp-ios-222'
Diffstat (limited to 'ios')
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj1
-rw-r--r--ios/MullvadVPN/View controllers/Preferences/PreferencesCellFactory.swift47
-rw-r--r--ios/MullvadVPN/View controllers/Preferences/PreferencesDataSource.swift167
-rw-r--r--ios/MullvadVPN/View controllers/Preferences/PreferencesViewController.swift16
-rw-r--r--ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift15
5 files changed, 219 insertions, 27 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index 464240306d..d71fb082c5 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -1618,6 +1618,7 @@
5867770F290975E8006F721F /* SettingsInteractorFactory.swift */,
58ACF64A26553C3F00ACE4B7 /* SettingsSwitchCell.swift */,
58CCA01122424D11004F3011 /* SettingsViewController.swift */,
+ 7A42DEC82A05164100B209BE /* SettingsInputCell.swift */,
);
path = Settings;
sourceTree = "<group>";
diff --git a/ios/MullvadVPN/View controllers/Preferences/PreferencesCellFactory.swift b/ios/MullvadVPN/View controllers/Preferences/PreferencesCellFactory.swift
index 7223808867..6ccefff8ac 100644
--- a/ios/MullvadVPN/View controllers/Preferences/PreferencesCellFactory.swift
+++ b/ios/MullvadVPN/View controllers/Preferences/PreferencesCellFactory.swift
@@ -245,6 +245,53 @@ final class PreferencesCellFactory: CellFactoryProtocol {
isEditing: isEditing,
preferredFont: .systemFont(ofSize: 14)
)
+ case .wireGuardObfuscationAutomatic:
+ guard let cell = cell as? SelectableSettingsCell else { return }
+
+ cell.titleLabel.text = NSLocalizedString(
+ "WIRE_GUARD_OBFUSCATION_AUTOMATIC_LABEL",
+ tableName: "Preferences",
+ value: "Automatic",
+ comment: ""
+ )
+ cell.accessibilityHint = nil
+ cell.applySubCellStyling()
+ case .wireGuardObfuscationOn:
+ guard let cell = cell as? SelectableSettingsCell else { return }
+
+ cell.titleLabel.text = NSLocalizedString(
+ "WIRE_GUARD_OBFUSCATION_ON_LABEL",
+ tableName: "Preferences",
+ value: "On (UDP-over-TCP)",
+ comment: ""
+ )
+ cell.accessibilityHint = nil
+ cell.applySubCellStyling()
+ case .wireGuardObfuscationOff:
+ guard let cell = cell as? SelectableSettingsCell else { return }
+
+ cell.titleLabel.text = NSLocalizedString(
+ "WIRE_GUARD_OBFUSCATION_OFF_LABEL",
+ tableName: "Preferences",
+ value: "Off",
+ comment: ""
+ )
+ cell.accessibilityHint = nil
+ cell.applySubCellStyling()
+
+ case let .wireGuardObfuscationPort(port):
+ guard let cell = cell as? SelectableSettingsCell else { return }
+
+ let portValue = port == 0 ? "Automatic" : "\(port)"
+
+ cell.titleLabel.text = NSLocalizedString(
+ "WIRE_GUARD_OBFUSCATION_PORT_LABEL",
+ tableName: "Preferences",
+ value: portValue,
+ comment: ""
+ )
+ cell.accessibilityHint = nil
+ cell.applySubCellStyling()
}
}
diff --git a/ios/MullvadVPN/View controllers/Preferences/PreferencesDataSource.swift b/ios/MullvadVPN/View controllers/Preferences/PreferencesDataSource.swift
index 8927d2107c..6e1a131d5f 100644
--- a/ios/MullvadVPN/View controllers/Preferences/PreferencesDataSource.swift
+++ b/ios/MullvadVPN/View controllers/Preferences/PreferencesDataSource.swift
@@ -22,6 +22,8 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case addDNSServer
case wireGuardPort
case wireGuardCustomPort
+ case wireGuardObfuscation
+ case wireGuardObfuscationPort
var reusableViewClass: AnyClass {
switch self {
@@ -39,6 +41,10 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
return SelectableSettingsCell.self
case .wireGuardCustomPort:
return SettingsInputCell.self
+ case .wireGuardObfuscation:
+ return SelectableSettingsCell.self
+ case .wireGuardObfuscationPort:
+ return SelectableSettingsCell.self
}
}
}
@@ -62,12 +68,16 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case contentBlockers
case blockMalware
case wireGuardPorts
+ case wireGuardObfuscation
+ case wireGuardObfuscationPort
}
enum Section: String, Hashable, CaseIterable {
case contentBlockers
case customDNS
case wireGuardPorts
+ case wireGuardObfuscation
+ case wireGuardObfuscationPort
}
enum Item: Hashable {
@@ -82,6 +92,10 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case addDNSServer
case dnsServer(_ uniqueID: UUID)
case dnsServerInfo
+ case wireGuardObfuscationAutomatic
+ case wireGuardObfuscationOn
+ case wireGuardObfuscationOff
+ case wireGuardObfuscationPort(_ port: UInt16)
static var contentBlockers: [Item] {
[.blockAdvertising, .blockTracking, .blockMalware, .blockAdultContent, .blockGambling]
@@ -94,6 +108,14 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
return [.wireGuardPort(nil)] + defaultPorts + [.wireGuardCustomPort]
}
+ static var wireGuardObfuscation: [Item] {
+ [.wireGuardObfuscationAutomatic, .wireGuardObfuscationOn, wireGuardObfuscationOff]
+ }
+
+ static var wireGuardObfuscationPort: [Item] {
+ [.wireGuardObfuscationPort(0), wireGuardObfuscationPort(80), wireGuardObfuscationPort(5001)]
+ }
+
var accessibilityIdentifier: String {
switch self {
case .blockAdvertising:
@@ -122,6 +144,17 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
return "dnsServer(\(uuid.uuidString))"
case .dnsServerInfo:
return "dnsServerInfo"
+ case .wireGuardObfuscationAutomatic:
+ return "Automatic"
+ case .wireGuardObfuscationOn:
+ return "On (UDP-over-TCP)"
+ case .wireGuardObfuscationOff:
+ return "Off"
+ case let .wireGuardObfuscationPort(port):
+ if port == 0 {
+ return "Automatic"
+ }
+ return "\(port)"
}
}
@@ -145,6 +178,10 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
return .wireGuardPort
case .wireGuardCustomPort:
return .wireGuardCustomPort
+ case .wireGuardObfuscationAutomatic, .wireGuardObfuscationOn, .wireGuardObfuscationOff:
+ return .wireGuardObfuscation
+ case .wireGuardObfuscationPort:
+ return .wireGuardObfuscationPort
default:
return .settingSwitch
}
@@ -331,7 +368,8 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
switch itemIdentifier(for: indexPath) {
- case .wireGuardPort, .wireGuardCustomPort:
+ case .wireGuardPort, .wireGuardCustomPort, .wireGuardObfuscationAutomatic, .wireGuardObfuscationOn,
+ .wireGuardObfuscationOff, .wireGuardObfuscationPort:
return true
default:
return false
@@ -341,6 +379,8 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = itemIdentifier(for: indexPath)
+ deselectAllRowsInSectionExceptRowAt(indexPath)
+
switch item {
case let .wireGuardPort(port):
viewModel.setWireGuardPort(port)
@@ -355,31 +395,48 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
case .wireGuardCustomPort:
getCustomPortCell()?.textField.becomeFirstResponder()
+ case .wireGuardObfuscationAutomatic:
+ print("UDP over TCP Set to automatic")
+ case .wireGuardObfuscationOn:
+ print("turning on UDP over TCP")
+ case .wireGuardObfuscationOff:
+ print("Turning off UDP over TCP")
+ case let .wireGuardObfuscationPort(port):
+ print("Setting port to \(port)")
+
default:
break
}
}
+ func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
+ nil
+ }
+
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let sectionIdentifier = snapshot().sectionIdentifiers[section]
+ guard let view = tableView
+ .dequeueReusableHeaderFooterView(
+ withIdentifier: HeaderFooterReuseIdentifiers.contentBlockerHeader
+ .rawValue
+ ) as? SettingsHeaderView else { return nil }
+
switch sectionIdentifier {
case .contentBlockers:
- guard let view = tableView
- .dequeueReusableHeaderFooterView(
- withIdentifier: HeaderFooterReuseIdentifiers.contentBlockerHeader.rawValue
- ) as? SettingsHeaderView else { return nil }
configureContentBlockersHeader(view)
return view
case .wireGuardPorts:
- guard let view = tableView
- .dequeueReusableHeaderFooterView(
- withIdentifier: HeaderFooterReuseIdentifiers.contentBlockerHeader.rawValue
- ) as? SettingsHeaderView else { return nil }
configureWireguardPortsHeader(view)
return view
+ case .wireGuardObfuscation:
+ configureObfuscationHeader(view)
+ return view
+ case .wireGuardObfuscationPort:
+ configureObfuscationPortHeader(view)
+ return view
default:
return nil
}
@@ -389,14 +446,10 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
let sectionIdentifier = snapshot().sectionIdentifiers[section]
switch sectionIdentifier {
- case .contentBlockers:
- return nil
-
case .wireGuardPorts:
return tableView.dequeueReusableHeaderFooterView(
withIdentifier: HeaderFooterReuseIdentifiers.spacer.rawValue
)
-
default:
return nil
}
@@ -418,7 +471,7 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
let sectionIdentifier = snapshot().sectionIdentifiers[section]
switch sectionIdentifier {
- case .wireGuardPorts:
+ case .wireGuardObfuscationPort:
return UIMetrics.sectionSpacing
default:
@@ -492,6 +545,15 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
}
}
+ private func deselectAllRowsInSectionExceptRowAt(_ indexPath: IndexPath) {
+ guard let indexPaths = tableView?.indexPathsForSelectedRows else { return }
+ let rowsToDeselect = indexPaths.filter { $0.section == indexPath.section && $0.row != indexPath.row }
+
+ rowsToDeselect.forEach {
+ tableView?.deselectRow(at: $0, animated: false)
+ }
+ }
+
private func updateSnapshot(animated: Bool = false, completion: (() -> Void)? = nil) {
var newSnapshot = NSDiffableDataSourceSnapshot<Section, Item>()
let oldSnapshot = snapshot()
@@ -712,21 +774,24 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
apply(snapshot, animatingDifferences: true)
}
- private func configureContentBlockersHeader(_ reusableView: SettingsHeaderView) {
- reusableView.titleLabel.text = NSLocalizedString(
+ private func configureContentBlockersHeader(_ header: SettingsHeaderView) {
+ let title = NSLocalizedString(
"CONTENT_BLOCKERS_HEADER_LABEL",
tableName: "Preferences",
value: "DNS content blockers",
comment: ""
)
- reusableView.infoButtonHandler = { [weak self] in
+ header.titleLabel.text = title
+ header.accessibilityCustomActionName = title
+
+ header.infoButtonHandler = { [weak self] in
if let self {
self.delegate?.preferencesDataSource(self, showInfo: .contentBlockers)
}
}
- reusableView.didCollapseHandler = { [weak self] headerView in
+ header.didCollapseHandler = { [weak self] headerView in
guard let self else { return }
var snapshot = self.snapshot()
@@ -742,21 +807,23 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
}
}
- private func configureWireguardPortsHeader(_ reusableView: SettingsHeaderView) {
- reusableView.titleLabel.text = NSLocalizedString(
+ private func configureWireguardPortsHeader(_ header: SettingsHeaderView) {
+ let title = NSLocalizedString(
"WIRE_GUARD_PORTS_HEADER_LABEL",
tableName: "Preferences",
value: "WireGuard ports",
comment: ""
)
- reusableView.infoButtonHandler = { [weak self] in
+ header.titleLabel.text = title
+ header.accessibilityCustomActionName = title
+ header.infoButtonHandler = { [weak self] in
if let self {
self.delegate?.preferencesDataSource(self, showInfo: .wireGuardPorts)
}
}
- reusableView.didCollapseHandler = { [weak self] headerView in
+ header.didCollapseHandler = { [weak self] headerView in
guard let self else { return }
var snapshot = self.snapshot()
@@ -783,6 +850,62 @@ final class PreferencesDataSource: UITableViewDiffableDataSource<
}
}
+ private func configureObfuscationHeader(_ header: SettingsHeaderView) {
+ let title = NSLocalizedString(
+ "OBFUSCATION_HEADER_LABEL",
+ tableName: "Preferences",
+ value: "WireGuard Obfuscation",
+ comment: ""
+ )
+
+ header.titleLabel.text = title
+ header.accessibilityCustomActionName = title
+ header.didCollapseHandler = { [weak self] header in
+ guard let self else { return }
+
+ var snapshot = snapshot()
+ if header.isExpanded {
+ snapshot.deleteItems(Item.wireGuardObfuscation)
+ } else {
+ snapshot.appendItems(Item.wireGuardObfuscation, toSection: .wireGuardObfuscation)
+ }
+ header.isExpanded.toggle()
+ applySnapshot(snapshot, animated: true)
+ }
+
+ header.infoButtonHandler = { [weak self] in
+ self.map { $0.delegate?.preferencesDataSource($0, showInfo: .wireGuardObfuscation) }
+ }
+ }
+
+ private func configureObfuscationPortHeader(_ header: SettingsHeaderView) {
+ let title = NSLocalizedString(
+ "OBFUSCATION_PORT_HEADER_LABEL",
+ tableName: "Preferences",
+ value: "UDP-over-TCP Port",
+ comment: ""
+ )
+
+ header.titleLabel.text = title
+ header.accessibilityCustomActionName = title
+ header.didCollapseHandler = { [weak self] header in
+ guard let self else { return }
+
+ var snapshot = snapshot()
+ if header.isExpanded {
+ snapshot.deleteItems(Item.wireGuardObfuscationPort)
+ } else {
+ snapshot.appendItems(Item.wireGuardObfuscationPort, toSection: .wireGuardObfuscationPort)
+ }
+ header.isExpanded.toggle()
+ applySnapshot(snapshot, animated: true)
+ }
+
+ header.infoButtonHandler = { [weak self] in
+ self.map { $0.delegate?.preferencesDataSource($0, showInfo: .wireGuardObfuscationPort) }
+ }
+ }
+
private func selectRow(at indexPath: IndexPath?, animated: Bool = false) {
tableView?.selectRow(at: indexPath, animated: false, scrollPosition: .none)
}
diff --git a/ios/MullvadVPN/View controllers/Preferences/PreferencesViewController.swift b/ios/MullvadVPN/View controllers/Preferences/PreferencesViewController.swift
index c6c3bfc218..4410c47d1d 100644
--- a/ios/MullvadVPN/View controllers/Preferences/PreferencesViewController.swift
+++ b/ios/MullvadVPN/View controllers/Preferences/PreferencesViewController.swift
@@ -35,6 +35,7 @@ class PreferencesViewController: UITableViewController, PreferencesDataSourceDel
tableView.estimatedRowHeight = 60
tableView.estimatedSectionHeaderHeight = tableView.estimatedRowHeight
tableView.allowsSelectionDuringEditing = true
+ tableView.allowsMultipleSelection = true
dataSource = PreferencesDataSource(tableView: tableView)
dataSource?.delegate = self
@@ -161,6 +162,21 @@ class PreferencesViewController: UITableViewController, PreferencesDataSourceDel
portsString
)
+ case .wireGuardObfuscation:
+ message = NSLocalizedString(
+ "PREFERENCES_WIRE_GUARD_OBFUSCATION_GENERAL",
+ tableName: "WireGuardObfuscation",
+ value: "Obfuscation hides the WireGuard traffic inside another protocol. It can be used to help circumvent censorship and other types of filtering, where a plain WireGuard connect would be blocked.",
+ comment: ""
+ )
+
+ case .wireGuardObfuscationPort:
+ message = NSLocalizedString(
+ "PREFERENCES_WIRE_GUARD_OBFUSCATION_PORT_GENERAL",
+ tableName: "WireGuardObfuscation",
+ value: "Which TCP port the UDP-over-TCP obfuscation protocol should connect to on the VPN server.",
+ comment: ""
+ )
default:
assertionFailure("No matching InfoButtonItem")
}
diff --git a/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift b/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift
index 51bb8e2742..c934042d62 100644
--- a/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift
+++ b/ios/MullvadVPN/View controllers/Settings/SettingsHeaderView.swift
@@ -44,6 +44,12 @@ class SettingsHeaderView: UITableViewHeaderFooterView {
}
}
+ var accessibilityCustomActionName = "" {
+ didSet {
+ updateAccessibilityCustomActions()
+ }
+ }
+
var didCollapseHandler: CollapseHandler?
var infoButtonHandler: InfoButtonHandler?
@@ -92,7 +98,6 @@ class SettingsHeaderView: UITableViewHeaderFooterView {
}
updateCollapseImage()
- updateAccessibilityCustomActions()
}
required init?(coder: NSCoder) {
@@ -121,15 +126,15 @@ class SettingsHeaderView: UITableViewHeaderFooterView {
private func updateAccessibilityCustomActions() {
let actionName = isExpanded
? NSLocalizedString(
- "CONTENT_BLOCKERS_COLLAPSE_ACCESSIBILITY_ACTION",
+ "SETTINGS_HEADER_COLLAPSE_ACCESSIBILITY_ACTION",
tableName: "Settings",
- value: "Collapse content blockers",
+ value: "Collapse \(accessibilityCustomActionName)",
comment: ""
)
: NSLocalizedString(
- "CONTENT_BLOCKERS_EXPAND_ACCESSIBILITY_ACTION",
+ "SETTINGS_HEADER_EXPAND_ACCESSIBILITY_ACTION",
tableName: "Settings",
- value: "Expand content blockers",
+ value: "Expand \(accessibilityCustomActionName)",
comment: ""
)