Skip to content

Commit bc53c2b

Browse files
APPLE: variuos fixes (#3646)
* Add region search * APPLE: update launch animation * APPLE: update country expanding logic * APPLE: bump build * APPLE: integrate core changes (#3649) * APPLE: add QUIC reconnect alert * macOS: fix daemon not restarting
1 parent af81409 commit bc53c2b

File tree

19 files changed

+263
-71
lines changed

19 files changed

+263
-71
lines changed

nym-vpn-apple/Home/Sources/Gateways/CountryDropDown/GatewayCountryDropDown.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,11 @@ public struct GatewayCountryDropDown: View {
4848

4949
let unwrappedScrollToModel = scrollToModel.wrappedValue
5050
let selectedServer = servers.first { $0.id == unwrappedScrollToModel.serverId }
51-
let shouldExpand = unwrappedScrollToModel.countryCode == country.code
52-
|| selectedServer?.location?.twoLetterIsoCountryCode == country.code
51+
let shouldExpand = unwrappedScrollToModel.shouldExpand(
52+
countryCode: country.code,
53+
region: nil,
54+
server: selectedServer
55+
)
5356
_isExpanded = State(initialValue: shouldExpand)
5457
let shouldSelect = unwrappedScrollToModel.countryCode == country.code && unwrappedScrollToModel.isCountry
5558
_isCountrySelected = State(initialValue: shouldSelect)

nym-vpn-apple/Home/Sources/Gateways/CountryDropDown/GatewayScrollToModel.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ConnectionTypes
2+
import CountriesManagerTypes
23

34
public enum GatewayScrollToModel: Equatable {
45
case country(code: String)
@@ -98,4 +99,22 @@ public enum GatewayScrollToModel: Equatable {
9899
false
99100
}
100101
}
102+
103+
func shouldExpand(countryCode: String, region: String?, server: GatewayNode?) -> Bool {
104+
switch self {
105+
case .country:
106+
return false
107+
case let .region(regionCountryCode, _):
108+
if region != nil {
109+
return false
110+
} else {
111+
return countryCode == regionCountryCode
112+
}
113+
case let .server(id):
114+
return server?.id == id && server?.location?.twoLetterIsoCountryCode == countryCode
115+
|| server?.id == id && server?.location?.region == region
116+
case .empty:
117+
return false
118+
}
119+
}
101120
}

nym-vpn-apple/Home/Sources/Gateways/CountryDropDown/GatewaysRegionCell.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ public struct GatewaysRegionCell: View {
6565

6666
let unwrappedScrollToModel = scrollToModel.wrappedValue
6767
let selectedServer = servers.first { $0.id == unwrappedScrollToModel.serverId }
68-
let shouldExpand = unwrappedScrollToModel.region == region || selectedServer?.location?.region == region
68+
let shouldExpand = unwrappedScrollToModel.shouldExpand(
69+
countryCode: country.code,
70+
region: region,
71+
server: selectedServer
72+
)
6973
_isExpanded = State(initialValue: shouldExpand)
7074
let shouldSelect = unwrappedScrollToModel.region == region && unwrappedScrollToModel.isRegion
7175
_isRegionSelected = State(initialValue: shouldSelect)

nym-vpn-apple/Home/Sources/Gateways/GatewaysView.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public struct GatewaysView: View {
2929
countriesGatewaysList()
3030
noSearchResultsView()
3131
foundCountriesList()
32+
foundUSRegionsList()
3233
foundGatewaysList()
3334
}
3435
.scrollDismissesKeyboard(.immediately)
@@ -200,4 +201,24 @@ private extension GatewaysView {
200201
)
201202
}
202203
}
204+
205+
@ViewBuilder
206+
func foundUSRegionsList() -> some View {
207+
if let usCountry = viewModel.gatewayManager.localizedCountry(with: "US") {
208+
ForEach(viewModel.foundUSRegions, id: \.self) { region in
209+
GatewaysRegionCell(
210+
hopType: viewModel.type,
211+
country: usCountry,
212+
region: region,
213+
servers: viewModel.gatewayManager.vpn.filter { $0.location?.region == region},
214+
infoButtonTapCompletion: { _ in },
215+
path: $viewModel.path,
216+
entryGateway: $viewModel.connectionManager.entryGateway,
217+
exitRouter: $viewModel.connectionManager.exitRouter,
218+
scrollToModel: .constant(.empty)
219+
)
220+
}
221+
222+
}
223+
}
203224
}

nym-vpn-apple/Home/Sources/Gateways/GatewaysViewModel.swift

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import GatewayManager
66
import UIComponents
77

88
@MainActor public class GatewaysViewModel: ObservableObject {
9-
private let gatewayManager: GatewayManager
10-
9+
let gatewayManager: GatewayManager
1110
let type: HopType
1211
let minimumSearchSymbols = 2
1312

@@ -17,6 +16,7 @@ import UIComponents
1716
@Published var gateways = [GatewayNode]()
1817
@Published var countries = [NymCountry]()
1918
@Published var foundCountries = [NymCountry]()
19+
@Published var foundUSRegions = [String]()
2020
@Published var foundGateways = [GatewayNode]()
2121
@Published var scrollToModel: GatewayScrollToModel
2222
@Published var searchText: String = "" {
@@ -106,12 +106,23 @@ import UIComponents
106106
return
107107
}
108108
foundCountries = countries.filter {
109-
$0.name.lowercased().contains(searchText.lowercased())
110-
|| $0.code.lowercased().contains(searchText.lowercased())
109+
$0.name.lowercased().localizedCaseInsensitiveContains(searchText.lowercased())
110+
|| $0.code.lowercased().localizedCaseInsensitiveContains(searchText.lowercased())
111111
}
112+
113+
var seen = Set<String>()
114+
foundUSRegions = gateways
115+
.lazy
116+
.filter { $0.location?.twoLetterIsoCountryCode.caseInsensitiveCompare("US") == .orderedSame }
117+
.compactMap { $0.location?.region.trimmingCharacters(in: .whitespacesAndNewlines) }
118+
.filter {
119+
!$0.isEmpty && $0.range(of: self.searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil
120+
}
121+
.filter { seen.insert($0).inserted }
122+
112123
foundGateways = gateways.filter {
113-
$0.moniker?.lowercased().contains(searchText.lowercased()) ?? false
114-
|| $0.id.lowercased().contains(searchText.lowercased())
124+
$0.moniker?.lowercased().localizedCaseInsensitiveContains(searchText.lowercased()) ?? false
125+
|| $0.id.lowercased().localizedCaseInsensitiveContains(searchText.lowercased())
115126
}
116127
}
117128
}

nym-vpn-apple/NymVPN.xcodeproj/project.pbxproj

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,7 @@
809809
};
810810
D94127BD2C00AB2E009EDB7A /* Run Swiftlint */ = {
811811
isa = PBXShellScriptBuildPhase;
812+
alwaysOutOfDate = 1;
812813
buildActionMask = 2147483647;
813814
files = (
814815
);
@@ -912,7 +913,7 @@
912913
CODE_SIGN_ENTITLEMENTS = NymMixnetTunnel/NymMixnetTunnel.entitlements;
913914
CODE_SIGN_IDENTITY = "Apple Development";
914915
CODE_SIGN_STYLE = Automatic;
915-
CURRENT_PROJECT_VERSION = 418;
916+
CURRENT_PROJECT_VERSION = 419;
916917
DEVELOPMENT_TEAM = VW5DZLFHM5;
917918
ENABLE_APP_SANDBOX = YES;
918919
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
@@ -950,7 +951,7 @@
950951
CODE_SIGN_ENTITLEMENTS = NymMixnetTunnel/NymMixnetTunnel.entitlements;
951952
CODE_SIGN_IDENTITY = "Apple Development";
952953
CODE_SIGN_STYLE = Automatic;
953-
CURRENT_PROJECT_VERSION = 418;
954+
CURRENT_PROJECT_VERSION = 419;
954955
DEVELOPMENT_TEAM = VW5DZLFHM5;
955956
ENABLE_APP_SANDBOX = YES;
956957
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
@@ -1114,7 +1115,7 @@
11141115
CODE_SIGN_ENTITLEMENTS = NymVPN/NymVPN.entitlements;
11151116
CODE_SIGN_IDENTITY = "Apple Development";
11161117
CODE_SIGN_STYLE = Automatic;
1117-
CURRENT_PROJECT_VERSION = 418;
1118+
CURRENT_PROJECT_VERSION = 419;
11181119
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
11191120
DEVELOPMENT_TEAM = VW5DZLFHM5;
11201121
ENABLE_APP_SANDBOX = YES;
@@ -1155,7 +1156,7 @@
11551156
CODE_SIGN_ENTITLEMENTS = NymVPN/NymVPN.entitlements;
11561157
CODE_SIGN_IDENTITY = "Apple Development";
11571158
CODE_SIGN_STYLE = Automatic;
1158-
CURRENT_PROJECT_VERSION = 418;
1159+
CURRENT_PROJECT_VERSION = 419;
11591160
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
11601161
DEVELOPMENT_TEAM = VW5DZLFHM5;
11611162
ENABLE_APP_SANDBOX = YES;
@@ -1196,7 +1197,7 @@
11961197
CODE_SIGN_IDENTITY = "Apple Development";
11971198
CODE_SIGN_STYLE = Manual;
11981199
COMBINE_HIDPI_IMAGES = YES;
1199-
CURRENT_PROJECT_VERSION = 120;
1200+
CURRENT_PROJECT_VERSION = 121;
12001201
DEAD_CODE_STRIPPING = YES;
12011202
DEVELOPMENT_ASSET_PATHS = "\"NymVPNDaemon/Preview Content\"";
12021203
DEVELOPMENT_TEAM = VW5DZLFHM5;
@@ -1233,7 +1234,7 @@
12331234
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application";
12341235
CODE_SIGN_STYLE = Manual;
12351236
COMBINE_HIDPI_IMAGES = YES;
1236-
CURRENT_PROJECT_VERSION = 120;
1237+
CURRENT_PROJECT_VERSION = 121;
12371238
DEAD_CODE_STRIPPING = YES;
12381239
DEVELOPMENT_ASSET_PATHS = "\"NymVPNDaemon/Preview Content\"";
12391240
DEVELOPMENT_TEAM = "";

nym-vpn-apple/NymVPN/Resources/Localizable.xcstrings

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3528,6 +3528,28 @@
35283528
}
35293529
}
35303530
},
3531+
"censorship.quic.disable.alert.subtitle" : {
3532+
"extractionState" : "manual",
3533+
"localizations" : {
3534+
"en" : {
3535+
"stringUnit" : {
3536+
"state" : "translated",
3537+
"value" : "For changes to take effect, you need to reconnect."
3538+
}
3539+
}
3540+
}
3541+
},
3542+
"censorship.quic.disable.alert.title" : {
3543+
"extractionState" : "manual",
3544+
"localizations" : {
3545+
"en" : {
3546+
"stringUnit" : {
3547+
"state" : "translated",
3548+
"value" : "Are you sure you want to continue?"
3549+
}
3550+
}
3551+
}
3552+
},
35313553
"censorship.quic.link" : {
35323554
"extractionState" : "manual",
35333555
"localizations" : {
@@ -6570,13 +6592,13 @@
65706592
"de" : {
65716593
"stringUnit" : {
65726594
"state" : "new",
6573-
"value" : "Instead, you’re creating an account secured \u2028by a 24-word passphrase."
6595+
"value" : "Instead, you’re creating an account secured 
by a 24-word passphrase."
65746596
}
65756597
},
65766598
"en" : {
65776599
"stringUnit" : {
65786600
"state" : "translated",
6579-
"value" : "Instead, you’re creating an account secured \u2028by a 24-word passphrase."
6601+
"value" : "Instead, you’re creating an account secured 
by a 24-word passphrase."
65806602
}
65816603
},
65826604
"es" : {
@@ -6612,7 +6634,7 @@
66126634
"ja" : {
66136635
"stringUnit" : {
66146636
"state" : "new",
6615-
"value" : "Instead, you’re creating an account secured \u2028by a 24-word passphrase."
6637+
"value" : "Instead, you’re creating an account secured 
by a 24-word passphrase."
66166638
}
66176639
},
66186640
"pt" : {
@@ -18583,19 +18605,19 @@
1858318605
"ar" : {
1858418606
"stringUnit" : {
1858518607
"state" : "new",
18586-
"value" : "NymVPN runs a background service (daemon) \u2028to keep your connection secure. It handles encryption and routing, protecting your activity even when the app is closed.\n\nFollow the steps below to install the daemon."
18608+
"value" : "NymVPN runs a background service (daemon) 
to keep your connection secure. It handles encryption and routing, protecting your activity even when the app is closed.\n\nFollow the steps below to install the daemon."
1858718609
}
1858818610
},
1858918611
"de" : {
1859018612
"stringUnit" : {
1859118613
"state" : "new",
18592-
"value" : "NymVPN runs a background service (daemon) \u2028to keep your connection secure. It handles encryption and routing, protecting your activity even when the app is closed.\n\nFollow the steps below to install the daemon."
18614+
"value" : "NymVPN runs a background service (daemon) 
to keep your connection secure. It handles encryption and routing, protecting your activity even when the app is closed.\n\nFollow the steps below to install the daemon."
1859318615
}
1859418616
},
1859518617
"en" : {
1859618618
"stringUnit" : {
1859718619
"state" : "translated",
18598-
"value" : "NymVPN runs a background service (daemon) \u2028to keep your connection secure. It handles encryption and routing, protecting your activity even when the app is closed.\n\nFollow the steps below to install the daemon."
18620+
"value" : "NymVPN runs a background service (daemon) 
to keep your connection secure. It handles encryption and routing, protecting your activity even when the app is closed.\n\nFollow the steps below to install the daemon."
1859918621
}
1860018622
},
1860118623
"es" : {
@@ -18637,7 +18659,7 @@
1863718659
"pt" : {
1863818660
"stringUnit" : {
1863918661
"state" : "new",
18640-
"value" : "NymVPN runs a background service (daemon) \u2028to keep your connection secure. It handles encryption and routing, protecting your activity even when the app is closed.\n\nFollow the steps below to install the daemon."
18662+
"value" : "NymVPN runs a background service (daemon) 
to keep your connection secure. It handles encryption and routing, protecting your activity even when the app is closed.\n\nFollow the steps below to install the daemon."
1864118663
}
1864218664
},
1864318665
"pt-BR" : {
@@ -29503,7 +29525,7 @@
2950329525
"en" : {
2950429526
"stringUnit" : {
2950529527
"state" : "translated",
29506-
"value" : "Retrieving your anonymous\u2028account credentials (zk-nyms)..."
29528+
"value" : "Retrieving your anonymous
account credentials (zk-nyms)..."
2950729529
}
2950829530
},
2950929531
"es" : {
@@ -29515,7 +29537,7 @@
2951529537
"fa" : {
2951629538
"stringUnit" : {
2951729539
"state" : "new",
29518-
"value" : "Retrieving your anonymous\u2028account credentials (zk-nyms)..."
29540+
"value" : "Retrieving your anonymous
account credentials (zk-nyms)..."
2951929541
}
2952029542
},
2952129543
"fr" : {
@@ -29575,7 +29597,7 @@
2957529597
"vi" : {
2957629598
"stringUnit" : {
2957729599
"state" : "new",
29578-
"value" : "Retrieving your anonymous\u2028account credentials (zk-nyms)..."
29600+
"value" : "Retrieving your anonymous
account credentials (zk-nyms)..."
2957929601
}
2958029602
},
2958129603
"zh-Hans" : {
@@ -29604,7 +29626,7 @@
2960429626
"en" : {
2960529627
"stringUnit" : {
2960629628
"state" : "translated",
29607-
"value" : "Saving your zk-nyms\u2028on the device..."
29629+
"value" : "Saving your zk-nyms
on the device..."
2960829630
}
2960929631
},
2961029632
"es" : {
@@ -29616,7 +29638,7 @@
2961629638
"fa" : {
2961729639
"stringUnit" : {
2961829640
"state" : "new",
29619-
"value" : "Saving your zk-nyms\u2028on the device..."
29641+
"value" : "Saving your zk-nyms
on the device..."
2962029642
}
2962129643
},
2962229644
"fr" : {
@@ -29676,7 +29698,7 @@
2967629698
"vi" : {
2967729699
"stringUnit" : {
2967829700
"state" : "new",
29679-
"value" : "Saving your zk-nyms\u2028on the device..."
29701+
"value" : "Saving your zk-nyms
on the device..."
2968029702
}
2968129703
},
2968229704
"zh-Hans" : {
@@ -31404,6 +31426,17 @@
3140431426
}
3140531427
}
3140631428
},
31429+
"reconnect" : {
31430+
"extractionState" : "manual",
31431+
"localizations" : {
31432+
"en" : {
31433+
"stringUnit" : {
31434+
"state" : "translated",
31435+
"value" : "Reconnect"
31436+
}
31437+
}
31438+
}
31439+
},
3140731440
"retry" : {
3140831441
"extractionState" : "manual",
3140931442
"localizations" : {

nym-vpn-apple/Services/Sources/Services/ConnectionManager/ConnectionManager+iOS.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ extension ConnectionManager {
132132

133133
/// Sends connect command to lib if entry/exit gateways changed while connected,
134134
/// to initiate reconnect
135-
@MainActor func reconnectIfNeeded() async {
135+
func reconnectIfNeeded() async {
136136
do {
137137
let newConfig = try generateConfig()
138138
guard currentTunnelStatus == .connected || currentTunnelStatus == .connecting,

nym-vpn-apple/Services/Sources/Services/ConnectionManager/ConnectionManager.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ private extension ConnectionManager {
171171
#elseif os(macOS)
172172
setupGRPCManagerObservers()
173173
#endif
174+
setupAppSettingsObservers()
174175
setupConnectionChangeObserver()
175176
setupConnectionErrorObserver()
176177
configureConnectedTimeTimer()
@@ -211,8 +212,19 @@ private extension ConnectionManager {
211212
// MARK: - Countries -
212213

213214
private extension ConnectionManager {
215+
func setupAppSettingsObservers() {
216+
appSettings.$isQuicEnabledPublisher
217+
.removeDuplicates()
218+
.sink { [weak self] value in
219+
self?.connectionConfig?.enableBridges = value
220+
self?.updateConnectionConfig()
221+
}
222+
.store(in: &cancellables)
223+
}
224+
214225
func setupConnectionChangeObserver() {
215-
$connectionType.sink { [weak self] _ in
226+
$connectionType
227+
.sink { [weak self] _ in
216228
self?.updateCountries()
217229
}
218230
.store(in: &cancellables)

0 commit comments

Comments
 (0)