Skip to content

Commit aa0e997

Browse files
author
Jon Petersson
committed
List only DAITA entry locations if multihop and DAITA are enabled
1 parent 207cc54 commit aa0e997

13 files changed

+148
-63
lines changed

ios/MullvadVPN.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,8 @@
489489
7A516C3C2B712F0B00BBD33D /* IPOverrideWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A516C3B2B712F0B00BBD33D /* IPOverrideWrapperTests.swift */; };
490490
7A52F96A2C1735AE00B133B9 /* RelaySelectorStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FE25EF2AA77664003D1918 /* RelaySelectorStub.swift */; };
491491
7A52F96C2C17450C00B133B9 /* RelaySelectorWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A52F96B2C17450C00B133B9 /* RelaySelectorWrapperTests.swift */; };
492+
7A5468AC2C6A55B100590086 /* LocationRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5468AB2C6A55B100590086 /* LocationRelays.swift */; };
493+
7A5468AD2C6B5E4B00590086 /* LocationRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5468AB2C6A55B100590086 /* LocationRelays.swift */; };
492494
7A5869952B32E9C700640D27 /* LinkButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5869942B32E9C700640D27 /* LinkButton.swift */; };
493495
7A5869972B32EA4500640D27 /* AppButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5869962B32EA4500640D27 /* AppButton.swift */; };
494496
7A58699B2B482FE200640D27 /* UITableViewCell+Disable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A58699A2B482FE200640D27 /* UITableViewCell+Disable.swift */; };
@@ -1806,6 +1808,7 @@
18061808
7A516C392B7111A700BBD33D /* IPOverrideWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideWrapper.swift; sourceTree = "<group>"; };
18071809
7A516C3B2B712F0B00BBD33D /* IPOverrideWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPOverrideWrapperTests.swift; sourceTree = "<group>"; };
18081810
7A52F96B2C17450C00B133B9 /* RelaySelectorWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySelectorWrapperTests.swift; sourceTree = "<group>"; };
1811+
7A5468AB2C6A55B100590086 /* LocationRelays.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRelays.swift; sourceTree = "<group>"; };
18091812
7A5869942B32E9C700640D27 /* LinkButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkButton.swift; sourceTree = "<group>"; };
18101813
7A5869962B32EA4500640D27 /* AppButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppButton.swift; sourceTree = "<group>"; };
18111814
7A58699A2B482FE200640D27 /* UITableViewCell+Disable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+Disable.swift"; sourceTree = "<group>"; };
@@ -2756,6 +2759,7 @@
27562759
F050AE5D2B739A73003F4EDB /* LocationDataSourceProtocol.swift */,
27572760
7A6652B62BB44B120042D848 /* LocationDiffableDataSourceProtocol.swift */,
27582761
7A6389F72B864CDF008E77E1 /* LocationNode.swift */,
2762+
7A5468AB2C6A55B100590086 /* LocationRelays.swift */,
27592763
F050AE512B70DFC0003F4EDB /* LocationSection.swift */,
27602764
F0BE65362B9F136A005CC385 /* LocationSectionHeaderView.swift */,
27612765
5888AD86227B17950051EB06 /* LocationViewController.swift */,
@@ -5251,6 +5255,7 @@
52515255
A9A5FA422ACB05D90083449F /* DeviceStateAccessorProtocol.swift in Sources */,
52525256
7A5869C32B5820CE00640D27 /* IPOverrideRepositoryTests.swift in Sources */,
52535257
A9A5FA392ACB05910083449F /* UIColor+Palette.swift in Sources */,
5258+
7A5468AD2C6B5E4B00590086 /* LocationRelays.swift in Sources */,
52545259
A9A5FA3A2ACB05910083449F /* UIEdgeInsets+Extensions.swift in Sources */,
52555260
A9A5FA3B2ACB05910083449F /* UIMetrics.swift in Sources */,
52565261
58B07C182AEFDD6C00A09625 /* StoreTransactionLog.swift in Sources */,
@@ -5542,6 +5547,7 @@
55425547
7A9CCCC42A96302800DD6A34 /* TunnelCoordinator.swift in Sources */,
55435548
5827B0A42B0F38FD00CCBBA1 /* EditAccessMethodInteractorProtocol.swift in Sources */,
55445549
586C0D852B03D31E00E7CDD7 /* SocksSectionHandler.swift in Sources */,
5550+
7A5468AC2C6A55B100590086 /* LocationRelays.swift in Sources */,
55455551
58BFA5CC22A7CE1F00A6173D /* ApplicationConfiguration.swift in Sources */,
55465552
5891BF5125E66B1E006D6FB0 /* UIBarButtonItem+KeyboardNavigation.swift in Sources */,
55475553
58E511E628DDDEAC00B0BCDE /* CodingErrors+CustomErrorDescription.swift in Sources */,

ios/MullvadVPN/Coordinators/LocationCoordinator.swift

+33-8
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
1616
private let tunnelManager: TunnelManager
1717
private let relayCacheTracker: RelayCacheTracker
1818
private let customListRepository: CustomListRepositoryProtocol
19-
private var cachedRelays: CachedRelays?
19+
private var cachedRelays: LocationRelays?
2020

2121
let navigationController: UINavigationController
2222

@@ -54,10 +54,16 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
5454
}
5555

5656
func start() {
57+
let startContext: LocationViewControllerWrapper.MultihopContext =
58+
if case .noRelaysSatisfyingDaitaConstraints = tunnelManager.tunnelStatus.observedState
59+
.blockedState?.reason { .entry } else { .exit }
60+
5761
let locationViewControllerWrapper = LocationViewControllerWrapper(
5862
customListRepository: customListRepository,
5963
constraints: tunnelManager.settings.relayConstraints,
60-
multihopEnabled: tunnelManager.settings.tunnelMultihopState.isEnabled
64+
multihopEnabled: tunnelManager.settings.tunnelMultihopState.isEnabled,
65+
daitaEnabled: tunnelManager.settings.daita.state.isEnabled,
66+
startContext: startContext
6167
)
6268
locationViewControllerWrapper.delegate = self
6369

@@ -69,8 +75,13 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
6975
relayCacheTracker.addObserver(self)
7076

7177
if let cachedRelays = try? relayCacheTracker.getCachedRelays() {
72-
self.cachedRelays = cachedRelays
73-
locationViewControllerWrapper.setCachedRelays(cachedRelays, filter: relayFilter)
78+
let locationRelays = LocationRelays(
79+
relays: cachedRelays.relays.wireguard.relays,
80+
locations: cachedRelays.relays.locations
81+
)
82+
self.cachedRelays = locationRelays
83+
84+
locationViewControllerWrapper.setCachedRelays(locationRelays, filter: relayFilter)
7485
}
7586

7687
navigationController.pushViewController(locationViewControllerWrapper, animated: false)
@@ -87,8 +98,14 @@ class LocationCoordinator: Coordinator, Presentable, Presenting {
8798
)
8899

89100
relayFilterCoordinator.didFinish = { [weak self] coordinator, filter in
90-
if let cachedRelays = self?.cachedRelays, let filter {
91-
self?.locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: filter)
101+
guard let self else { return }
102+
103+
if var cachedRelays, let filter {
104+
cachedRelays.relays = cachedRelays.relays.filter { relay in
105+
RelaySelector.relayMatchesFilter(relay, filter: filter)
106+
}
107+
108+
locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: filter)
92109
}
93110

94111
coordinator.dismiss(animated: true)
@@ -148,9 +165,13 @@ extension LocationCoordinator: RelayCacheTrackerObserver {
148165
_ tracker: RelayCacheTracker,
149166
didUpdateCachedRelays cachedRelays: CachedRelays
150167
) {
151-
self.cachedRelays = cachedRelays
168+
let locationRelays = LocationRelays(
169+
relays: cachedRelays.relays.wireguard.relays,
170+
locations: cachedRelays.relays.locations
171+
)
172+
self.cachedRelays = locationRelays
152173

153-
locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: relayFilter)
174+
locationViewControllerWrapper?.setCachedRelays(locationRelays, filter: relayFilter)
154175
}
155176
}
156177

@@ -178,6 +199,10 @@ extension LocationCoordinator: LocationViewControllerWrapperDelegate {
178199
relayConstraints.filter = .only(filter)
179200

180201
tunnelManager.updateSettings([.relayConstraints(relayConstraints)])
202+
203+
if let cachedRelays {
204+
locationViewControllerWrapper?.setCachedRelays(cachedRelays, filter: filter)
205+
}
181206
}
182207

183208
func navigateToFilter() {

ios/MullvadVPN/View controllers/RelayFilter/RelayFilterChipView.swift

+10-6
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,23 @@ class RelayFilterChipView: UIView {
1818
return label
1919
}()
2020

21+
let closeButton: IncreasedHitButton = {
22+
let button = IncreasedHitButton()
23+
button.setImage(
24+
UIImage(resource: .iconCloseSml).withTintColor(.white.withAlphaComponent(0.6)),
25+
for: .normal
26+
)
27+
button.accessibilityIdentifier = .relayFilterChipCloseButton
28+
return button
29+
}()
30+
2131
var didTapButton: (() -> Void)?
2232

2333
init() {
2434
super.init(frame: .zero)
2535

2636
self.accessibilityIdentifier = .relayFilterChipView
2737

28-
let closeButton = IncreasedHitButton()
29-
closeButton.setImage(
30-
UIImage(named: "IconCloseSml")?.withTintColor(.white.withAlphaComponent(0.6)),
31-
for: .normal
32-
)
33-
closeButton.accessibilityIdentifier = .relayFilterChipCloseButton
3438
closeButton.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)
3539

3640
let container = UIStackView(arrangedSubviews: [titleLabel, closeButton])

ios/MullvadVPN/View controllers/RelayFilter/RelayFilterView.swift

+21-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class RelayFilterView: UIView {
3434

3535
private let ownershipView = RelayFilterChipView()
3636
private let providersView = RelayFilterChipView()
37+
private let daitaView = RelayFilterChipView()
3738
private var filter: RelayFilter?
3839

3940
var didUpdateFilter: ((RelayFilter) -> Void)?
@@ -71,14 +72,24 @@ class RelayFilterView: UIView {
7172
}
7273
}
7374

75+
func setDaita(_ enabled: Bool) {
76+
daitaView.isHidden = !enabled
77+
}
78+
7479
private func setUpViews() {
80+
daitaView.setTitle(localizedDaitaText())
81+
daitaView.isHidden = true
82+
daitaView.closeButton.isHidden = true
83+
84+
ownershipView.isHidden = true
7585
ownershipView.didTapButton = { [weak self] in
7686
guard var filter = self?.filter else { return }
7787

7888
filter.ownership = .any
7989
self?.didUpdateFilter?(filter)
8090
}
8191

92+
providersView.isHidden = true
8293
providersView.didTapButton = { [weak self] in
8394
guard var filter = self?.filter else { return }
8495

@@ -87,7 +98,7 @@ class RelayFilterView: UIView {
8798
}
8899

89100
// Add a dummy view at the end to push content to the left.
90-
let filterContainer = UIStackView(arrangedSubviews: [ownershipView, providersView, UIView()])
101+
let filterContainer = UIStackView(arrangedSubviews: [daitaView, ownershipView, providersView, UIView()])
91102
filterContainer.spacing = UIMetrics.FilterView.interChipViewSpacing
92103

93104
let contentContainer = UIStackView(arrangedSubviews: [titleLabel, filterContainer])
@@ -99,6 +110,15 @@ class RelayFilterView: UIView {
99110
}
100111
}
101112

113+
private func localizedDaitaText() -> String {
114+
return NSLocalizedString(
115+
"RELAY_FILTER_APPLIED_DAITA",
116+
tableName: "RelayFilter",
117+
value: "Setting: DAITA",
118+
comment: ""
119+
)
120+
}
121+
102122
private func localizedOwnershipText(for string: String) -> String {
103123
return NSLocalizedString(
104124
"RELAY_FILTER_APPLIED_OWNERSHIP",

ios/MullvadVPN/View controllers/SelectLocation/AllLocationDataSource.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ class AllLocationDataSource: LocationDataSourceProtocol {
2020
/// Constructs a collection of node trees from relays fetched from the API.
2121
/// ``RelayLocation.city`` is of special import since we use it to get country
2222
/// and city names.
23-
func reload(_ response: REST.ServerRelaysResponse, relays: [REST.ServerRelay]) {
23+
func reload(_ relays: LocationRelays) {
2424
let rootNode = RootLocationNode()
2525

26-
for relay in relays {
26+
for relay in relays.relays {
2727
guard case
2828
let .city(countryCode, cityCode) = RelayLocation(dashSeparatedString: relay.location),
29-
let serverLocation = response.locations[relay.location]
29+
let serverLocation = relays.locations[relay.location]
3030
else { continue }
3131

3232
let relayLocation = RelayLocation.hostname(countryCode, cityCode, relay.hostname)

ios/MullvadVPN/View controllers/SelectLocation/LocationCellViewModel.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,17 @@ extension [LocationCellViewModel] {
6262
}
6363

6464
extension LocationCellViewModel {
65-
/* Exclusion of other locations in the same node tree as the currently excluded location
65+
/* Exclusion of other locations in the same node tree (as the currently excluded location)
6666
happens when there are no more hosts in that tree that can be selected.
6767
We check this by doing the following, in order:
6868

69-
1. Count host names in the tree. More than one means that there are other locations than
69+
1. Count hostnames in the tree. More than one means that there are other locations than
7070
the excluded one for the relay selector to choose from. No exlusion.
7171

72-
2. Count host names in the excluded node. More than one means that there are multiple
73-
locations for the relay selector to choose from. No exlusion.
72+
2. Count hostnames in the excluded node. More than one means that there are multiple
73+
locations for the relay selector to choose from. No exclusion.
7474

75-
3. Check existance of a location in the tree that match the currently excluded location.
75+
3. Check existance of a location in the tree that matches the currently excluded location.
7676
No match means no exclusion.
7777
*/
7878
func shouldExcludeLocation(_ excludedLocation: LocationCellViewModel?) -> Bool {
@@ -86,8 +86,8 @@ extension LocationCellViewModel {
8686
if case .hostname = location { true } else { false }
8787
}.count
8888

89-
// If the there are more than one selectable relay in the current node we don't need
90-
// show this in the location tree and can return early.
89+
// If the there's more than one selectable relay in the current node we don't need
90+
// to show this in the location tree and can return early.
9191
guard hostCount == 1 else { return false }
9292

9393
let proxyExcludedNode = RootLocationNode(children: [excludedLocation.node])
@@ -96,8 +96,8 @@ extension LocationCellViewModel {
9696
if case .hostname = location { true } else { false }
9797
}.count
9898

99-
// If the there are more than one selectable relay in the excluded node we don't need
100-
// show this in the location tree and can return early.
99+
// If the there's more than one selectable relay in the excluded node we don't need
100+
// to show this in the location tree and can return early.
101101
guard excludedHostCount == 1 else { return false }
102102

103103
var containsExcludedLocation = false

ios/MullvadVPN/View controllers/SelectLocation/LocationDataSource.swift

+2-12
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,14 @@ final class LocationDataSource:
5454
defaultRowAnimation = .fade
5555
}
5656

57-
func setRelays(_ response: REST.ServerRelaysResponse, selectedRelays: RelaySelection, filter: RelayFilter) {
57+
func setRelays(_ cachedRelays: LocationRelays, selectedRelays: RelaySelection) {
5858
let allLocationsDataSource =
5959
dataSources.first(where: { $0 is AllLocationDataSource }) as? AllLocationDataSource
6060

6161
let customListsDataSource =
6262
dataSources.first(where: { $0 is CustomListsDataSource }) as? CustomListsDataSource
6363

64-
let relays = response.wireguard.relays.filter { relay in
65-
RelaySelector.relayMatchesFilter(relay, filter: filter)
66-
}
67-
68-
allLocationsDataSource?.reload(response, relays: relays)
64+
allLocationsDataSource?.reload(cachedRelays)
6965
customListsDataSource?.reload(allLocationNodes: allLocationsDataSource?.nodes ?? [])
7066

7167
setSelectedRelays(selectedRelays)
@@ -237,12 +233,6 @@ final class LocationDataSource:
237233
)
238234
}
239235

240-
private func nodeMatchesExcludedLocation(_ node: LocationNode) -> Bool {
241-
// Compare nodes on name rather than whole node in order to match all items in both .customLists
242-
// and .allLocations.
243-
node.name == excludedLocation?.node.name
244-
}
245-
246236
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
247237
let cell = super.tableView(tableView, cellForRowAt: indexPath)
248238
guard let cell = cell as? LocationCell, let item = itemIdentifier(for: indexPath) else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// LocationRelays.swift
3+
// MullvadVPN
4+
//
5+
// Created by Jon Petersson on 2024-08-12.
6+
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
7+
//
8+
9+
import MullvadREST
10+
11+
struct LocationRelays {
12+
var relays: [REST.ServerRelay]
13+
var locations: [String: REST.ServerLocation]
14+
}

0 commit comments

Comments
 (0)