diff --git a/WireGuard/WireGuard/Base.lproj/Localizable.strings b/WireGuard/WireGuard/Base.lproj/Localizable.strings index 30b633c..0ba64b2 100644 --- a/WireGuard/WireGuard/Base.lproj/Localizable.strings +++ b/WireGuard/WireGuard/Base.lproj/Localizable.strings @@ -84,9 +84,7 @@ "tunnelOnDemandCellular" = "Cellular"; "tunnelOnDemandEthernet" = "Ethernet"; "tunnelOnDemandWiFi" = "Wi-Fi"; -"tunnelOnDemandSSIDDescription" = "Selected SSIDs"; -"tunnelOnDemandSSIDescriptionMac" = "SSIDs"; -"tunnelOnDemandSSIDEdit" = "Select SSIDs"; +"tunnelOnDemandSSIDsKey" = "SSIDs"; "tunnelOnDemandAnySSID" = "Any SSID"; "tunnelOnDemandOnlySelectedSSIDs" = "Only selected SSIDs"; @@ -98,7 +96,7 @@ "tunnelOnDemandAddMessageAddNewSSID" = "Add manually"; "tunnelOnDemandAddMessageAddConnectedSSID (%@)" = "Connected: %@"; -"tunnelOnDemandKey" = "Activate on demand"; +"tunnelOnDemandKey" = "On demand"; "tunnelOnDemandOptionOff" = "Off"; "tunnelOnDemandOptionWiFiOnly" = "Wi-Fi only"; "tunnelOnDemandOptionWiFiOrCellular" = "Wi-Fi or cellular"; diff --git a/WireGuard/WireGuard/UI/ActivateOnDemandViewModel.swift b/WireGuard/WireGuard/UI/ActivateOnDemandViewModel.swift index b5ce633..a852818 100644 --- a/WireGuard/WireGuard/UI/ActivateOnDemandViewModel.swift +++ b/WireGuard/WireGuard/UI/ActivateOnDemandViewModel.swift @@ -5,13 +5,15 @@ import Foundation class ActivateOnDemandViewModel { enum OnDemandField { + case onDemand case nonWiFiInterface case wiFiInterface - case ssidDescription - case ssidEdit + case ssid var localizedUIString: String { switch self { + case .onDemand: + return tr("tunnelOnDemandKey") case .nonWiFiInterface: #if os(iOS) return tr("tunnelOnDemandCellular") @@ -21,8 +23,7 @@ class ActivateOnDemandViewModel { #error("Unimplemented") #endif case .wiFiInterface: return tr("tunnelOnDemandWiFi") - case .ssidDescription: return tr("tunnelOnDemandSSIDDescription") - case .ssidEdit: return tr("tunnelOnDemandSSIDEdit") + case .ssid: return tr("tunnelOnDemandSSIDsKey") } } } @@ -48,7 +49,15 @@ class ActivateOnDemandViewModel { } extension ActivateOnDemandViewModel { - convenience init(from option: ActivateOnDemandOption) { + convenience init(setting: ActivateOnDemandSetting) { + if setting.isActivateOnDemandEnabled { + self.init(option: setting.activateOnDemandOption) + } else { + self.init(option: .none) + } + } + + convenience init(option: ActivateOnDemandOption) { self.init() switch option { case .none: @@ -103,6 +112,33 @@ extension ActivateOnDemandViewModel { } } +extension ActivateOnDemandViewModel { + var localizedInterfaceDescription: String { + switch (isWiFiInterfaceEnabled, isNonWiFiInterfaceEnabled) { + case (false, false): + return tr("tunnelOnDemandOptionOff") + case (true, false): + return tr("tunnelOnDemandOptionWiFiOnly") + case (false, true): + #if os(iOS) + return tr("tunnelOnDemandOptionCellularOnly") + #elseif os(macOS) + return tr("tunnelOnDemandOptionEthernetOnly") + #else + #error("Unimplemented") + #endif + case (true, true): + #if os(iOS) + return tr("tunnelOnDemandOptionWiFiOrCellular") + #elseif os(macOS) + return tr("tunnelOnDemandOptionWiFiOrEthernet") + #else + #error("Unimplemented") + #endif + } + } +} + private extension ActivateOnDemandViewModel { func ssidViewModel(from ssidOption: ActivateOnDemandSSIDOption) -> (OnDemandSSIDOption, [String]) { switch ssidOption { diff --git a/WireGuard/WireGuard/UI/iOS/ViewController/TunnelDetailTableViewController.swift b/WireGuard/WireGuard/UI/iOS/ViewController/TunnelDetailTableViewController.swift index 1f1a24f..19d66e7 100644 --- a/WireGuard/WireGuard/UI/iOS/ViewController/TunnelDetailTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/ViewController/TunnelDetailTableViewController.swift @@ -24,21 +24,28 @@ class TunnelDetailTableViewController: UITableViewController { .rxBytes, .txBytes, .lastHandshakeTime ] + static let onDemandFields: [ActivateOnDemandViewModel.OnDemandField] = [ + .onDemand, .ssid + ] + let tunnelsManager: TunnelsManager let tunnel: TunnelContainer var tunnelViewModel: TunnelViewModel + var onDemandViewModel: ActivateOnDemandViewModel private var sections = [Section]() private var interfaceFieldIsVisible = [Bool]() private var peerFieldIsVisible = [[Bool]]() private var statusObservationToken: AnyObject? + private var onDemandObservationToken: AnyObject? private var reloadRuntimeConfigurationTimer: Timer? init(tunnelsManager: TunnelsManager, tunnel: TunnelContainer) { self.tunnelsManager = tunnelsManager self.tunnel = tunnel tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnel.tunnelConfiguration) + onDemandViewModel = ActivateOnDemandViewModel(setting: tunnel.activateOnDemandSetting) super.init(style: .grouped) loadSections() loadVisibleFields() @@ -51,6 +58,11 @@ class TunnelDetailTableViewController: UITableViewController { self.stopUpdatingRuntimeConfiguration() } } + onDemandObservationToken = tunnel.observe(\.isActivateOnDemandEnabled) { [weak self] tunnel, _ in + // Handle On-Demand getting turned on/off outside of the app + self?.onDemandViewModel = ActivateOnDemandViewModel(setting: tunnel.activateOnDemandSetting) + self?.updateActivateOnDemandFields() + } } required init?(coder aDecoder: NSCoder) { @@ -242,11 +254,27 @@ class TunnelDetailTableViewController: UITableViewController { self.applyTunnelConfiguration(tunnelConfiguration: tunnelConfiguration) } } + + private func updateActivateOnDemandFields() { + guard let onDemandSection = sections.firstIndex(where: { if case .onDemand = $0 { return true } else { return false } }) else { return } + let numberOfTableViewOnDemandRows = tableView.numberOfRows(inSection: onDemandSection) + let ssidRowIndexPath = IndexPath(row: 1, section: onDemandSection) + switch (numberOfTableViewOnDemandRows, onDemandViewModel.isWiFiInterfaceEnabled) { + case (1, true): + tableView.insertRows(at: [ssidRowIndexPath], with: .automatic) + case (2, false): + tableView.deleteRows(at: [ssidRowIndexPath], with: .automatic) + default: + break + } + tableView.reloadSections(IndexSet(integer: onDemandSection), with: .automatic) + } } extension TunnelDetailTableViewController: TunnelEditTableViewControllerDelegate { func tunnelSaved(tunnel: TunnelContainer) { tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnel.tunnelConfiguration) + onDemandViewModel = ActivateOnDemandViewModel(setting: tunnel.activateOnDemandSetting) loadSections() loadVisibleFields() title = tunnel.name @@ -272,7 +300,7 @@ extension TunnelDetailTableViewController { case .peer(let peerIndex, _): return peerFieldIsVisible[peerIndex].filter { $0 }.count case .onDemand: - return 1 + return onDemandViewModel.isWiFiInterfaceEnabled ? 2 : 1 case .delete: return 1 } @@ -380,10 +408,12 @@ extension TunnelDetailTableViewController { private func onDemandCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell { let cell: KeyValueCell = tableView.dequeueReusableCell(for: indexPath) - cell.key = tr("tunnelOnDemandKey") - cell.value = TunnelViewModel.activateOnDemandDetailText(for: tunnel.activateOnDemandSetting) - cell.observationToken = tunnel.observe(\.isActivateOnDemandEnabled) { [weak cell] tunnel, _ in - cell?.value = TunnelViewModel.activateOnDemandDetailText(for: tunnel.activateOnDemandSetting) + let field = TunnelDetailTableViewController.onDemandFields[indexPath.row] + cell.key = field.localizedUIString + if field == .onDemand { + cell.value = onDemandViewModel.localizedInterfaceDescription + } else if field == .ssid { + cell.value = onDemandViewModel.ssidOption.localizedUIString } return cell } diff --git a/WireGuard/WireGuard/UI/iOS/ViewController/TunnelEditTableViewController.swift b/WireGuard/WireGuard/UI/iOS/ViewController/TunnelEditTableViewController.swift index ef7fc60..6f0444e 100644 --- a/WireGuard/WireGuard/UI/iOS/ViewController/TunnelEditTableViewController.swift +++ b/WireGuard/WireGuard/UI/iOS/ViewController/TunnelEditTableViewController.swift @@ -46,7 +46,7 @@ class TunnelEditTableViewController: UITableViewController { let onDemandFields: [ActivateOnDemandViewModel.OnDemandField] = [ .nonWiFiInterface, .wiFiInterface, - .ssidEdit + .ssid ] let tunnelsManager: TunnelsManager @@ -60,8 +60,7 @@ class TunnelEditTableViewController: UITableViewController { self.tunnelsManager = tunnelsManager self.tunnel = tunnel tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnel.tunnelConfiguration) - let onDemandOption = tunnel.activateOnDemandSetting.isActivateOnDemandEnabled ? tunnel.activateOnDemandSetting.activateOnDemandOption : .none - onDemandViewModel = ActivateOnDemandViewModel(from: onDemandOption) + onDemandViewModel = ActivateOnDemandViewModel(setting: tunnel.activateOnDemandSetting) super.init(style: .grouped) loadSections() }