diff options
| author | Bug Magnet <marco.nikic@mullvad.net> | 2023-08-09 09:35:41 +0200 |
|---|---|---|
| committer | Bug Magnet <marco.nikic@mullvad.net> | 2023-08-09 09:35:41 +0200 |
| commit | 5deb1b781c2bb3318b91385762ee0cc64e83724e (patch) | |
| tree | 903ef8832296469552cf38a695a65b562794a916 /ios | |
| parent | 5d00739e09600c4e525c3b5687ddb4f7ec3931fe (diff) | |
| parent | 62a11beb35df0741d7f0a444bde7dd02afa2b9f9 (diff) | |
| download | mullvadvpn-5deb1b781c2bb3318b91385762ee0cc64e83724e.tar.xz mullvadvpn-5deb1b781c2bb3318b91385762ee0cc64e83724e.zip | |
Merge branch 'add-ui-controls-for-udp2tcp-ios-222'
Diffstat (limited to 'ios')
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: "" ) |
