diff --git a/CHANGELOG.md b/CHANGELOG.md index 87c1dbd6..9cdc7eaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Host compression framing and algorithm are now editable. +### Fixed + +- NordVPN double servers not connecting out of the box. [#78](https://github.com/passepartoutvpn/passepartout-ios/issues/78) + ## 1.6.0 (2019-05-01) ### Added diff --git a/Passepartout-iOS/Scenes/ServiceViewController.swift b/Passepartout-iOS/Scenes/ServiceViewController.swift index 188552d5..98837dec 100644 --- a/Passepartout-iOS/Scenes/ServiceViewController.swift +++ b/Passepartout-iOS/Scenes/ServiceViewController.swift @@ -162,8 +162,13 @@ class ServiceViewController: UIViewController, TableModelHost { vc?.modificationDelegate = self case .providerPresetSegueIdentifier: + let infra = uncheckedProviderProfile.infrastructure + let presets: [InfrastructurePreset] = uncheckedProviderProfile.pool?.supportedPresetIds(in: uncheckedProviderProfile.infrastructure).map { + return infra.preset(for: $0)! + } ?? [] + let vc = destination as? ProviderPresetViewController - vc?.presets = uncheckedProviderProfile.infrastructure.presets + vc?.presets = presets vc?.currentPresetId = uncheckedProviderProfile.presetId vc?.delegate = self @@ -631,6 +636,13 @@ extension ServiceViewController: UITableViewDataSource, UITableViewDelegate, Tog return ip } + private var providerPresetIndexPath: IndexPath { + guard let ip = model.indexPath(row: .providerPreset, section: .configuration) else { + fatalError("Could not locate presetIndexPath") + } + return ip + } + private func mappedTrustedNetworksRow(_ from: TrustedNetworksModel.RowType) -> RowType { switch from { case .trustsMobile: @@ -1122,13 +1134,13 @@ extension ServiceViewController: UITableViewDataSource, UITableViewDelegate, Tog tableView.reloadRows(at: [dataCountIndexPath], with: .none) } - func reloadSelectedRow(andRowAt indexPath: IndexPath? = nil) { + func reloadSelectedRow(andRowsAt indexPaths: [IndexPath]? = nil) { guard let selectedIP = tableView.indexPathForSelectedRow else { return } var outdatedIPs = [selectedIP] - if let otherIP = indexPath { - outdatedIPs.append(otherIP) + if let otherIPs = indexPaths { + outdatedIPs.append(contentsOf: otherIPs) } tableView.reloadRows(at: outdatedIPs, with: .none) tableView.selectRow(at: selectedIP, animated: false, scrollPosition: .none) @@ -1254,7 +1266,21 @@ extension ServiceViewController: ProviderPoolViewControllerDelegate { return } uncheckedProviderProfile.poolId = pool.id - reloadSelectedRow(andRowAt: endpointIndexPath) + + var extraReloadedRows = [endpointIndexPath] + + // fall back to a supported preset and reload preset row too + let supportedPresets = pool.supportedPresetIds(in: uncheckedProviderProfile.infrastructure) + if let presetId = uncheckedProviderProfile.preset?.id, !supportedPresets.contains(presetId), + let fallback = supportedPresets.first { + + if fallback != uncheckedProviderProfile.presetId { + extraReloadedRows.append(providerPresetIndexPath) + } + uncheckedProviderProfile.presetId = fallback + } + + reloadSelectedRow(andRowsAt: extraReloadedRows) vpn.reinstallIfEnabled() if #available(iOS 12, *) { @@ -1271,7 +1297,7 @@ extension ServiceViewController: ProviderPresetViewControllerDelegate { return } uncheckedProviderProfile.presetId = preset.id - reloadSelectedRow(andRowAt: endpointIndexPath) + reloadSelectedRow(andRowsAt: [endpointIndexPath]) vpn.reinstallIfEnabled() } } diff --git a/Passepartout/Sources/Services/Pool.swift b/Passepartout/Sources/Services/Pool.swift index f7b878f2..d23e21c3 100644 --- a/Passepartout/Sources/Services/Pool.swift +++ b/Passepartout/Sources/Services/Pool.swift @@ -69,6 +69,25 @@ public struct Pool: Codable, Hashable { public let numericAddresses: [UInt32]? + // XXX: inefficient but convenient field (not serialized) + public func category(in infrastructure: Infrastructure) -> PoolCategory? { + for category in infrastructure.categories { + for group in category.groups { + for pool in group.pools { + if pool.id == id { + return category + } + } + } + } + return nil + } + + public func supportedPresetIds(in infrastructure: Infrastructure) -> [String] { + let poolCategory = category(in: infrastructure) + return poolCategory?.presets ?? infrastructure.presets.map { $0.id } + } + public func hasAddress(_ address: String) -> Bool { guard let numericAddresses = numericAddresses else { return false @@ -88,6 +107,12 @@ public struct Pool: Codable, Hashable { return addrs } + // MARK: Equatable + + public static func == (lhs: Pool, rhs: Pool) -> Bool { + return lhs.id == rhs.id + } + // MARK: Hashable public func hash(into hasher: inout Hasher) {