-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
VPN Geoswitching - initial draft (#1978)
Task/Issue URL: https://app.asana.com/0/0/1206183910299715/f Description: This adds an initial implementation of location switching for the VPN. Known issues: Some of the layout / spacing is not quite right The tap area of the items on the VPN Location selection screen is too small The styling of the list sections on the VPN Location screen is not finished. There seems to be a bug where the initial selection is not respected when connecting after selecting There is a momentary delay before the list items load. Needs unit tests (I promise I will add them, they are very similar to the iOS ones so it won’t take long. I just ran out of time before the holidays).
- Loading branch information
Showing
10 changed files
with
690 additions
and
1 deletion.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
...ection/AppTargets/BothAppTargets/VPNLocation/NetworkProtectionVPNCountryLabelsModel.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// | ||
// NetworkProtectionVPNCountryLabelsModel.swift | ||
// | ||
// Copyright © 2023 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
#if NETWORK_PROTECTION | ||
|
||
import Foundation | ||
import NetworkProtection | ||
|
||
struct NetworkProtectionVPNCountryLabelsModel { | ||
let emoji: String | ||
let title: String | ||
|
||
init(country: String) { | ||
self.title = Locale.current.localizedString(forRegionCode: country) ?? country.capitalized | ||
self.emoji = Self.flag(country: country) | ||
} | ||
|
||
private static func flag(country: String) -> String { | ||
let flagBase = UnicodeScalar("🇦").value - UnicodeScalar("A").value | ||
|
||
let flag = country | ||
.uppercased() | ||
.unicodeScalars | ||
.compactMap({ UnicodeScalar(flagBase + $0.value)?.description }) | ||
.joined() | ||
return flag | ||
} | ||
} | ||
|
||
#endif |
67 changes: 67 additions & 0 deletions
67
...o/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationPreferenceItem.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// | ||
// NetworkProtectionVPNLocationPreferenceItem.swift | ||
// | ||
// Copyright © 2023 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
#if NETWORK_PROTECTION | ||
|
||
import Foundation | ||
import SwiftUI | ||
|
||
struct VPNLocationPreferenceItem: View { | ||
let model: VPNLocationPreferenceItemModel | ||
@State private var isShowingLocationSheet: Bool = false | ||
|
||
var body: some View { | ||
VStack(alignment: .leading) { | ||
HStack(spacing: 10) { | ||
switch model.icon { | ||
case .defaultIcon: | ||
Image(systemName: "location.fill") | ||
.resizable() | ||
.frame(width: 18, height: 18) | ||
case .emoji(let string): | ||
Text(string).font(.system(size: 20)) | ||
} | ||
|
||
VStack(alignment: .leading) { | ||
Text(model.title) | ||
.font(.system(size: 13)) | ||
.foregroundColor(.primary) | ||
if let subtitle = model.subtitle { | ||
Text(subtitle) | ||
.font(.system(size: 11)) | ||
.foregroundColor(.secondary) | ||
} | ||
} | ||
Spacer() | ||
Button(UserText.vpnLocationChangeButtonTitle) { | ||
isShowingLocationSheet = true | ||
} | ||
.sheet(isPresented: $isShowingLocationSheet) { | ||
VPNLocationView(isPresented: $isShowingLocationSheet) | ||
} | ||
} | ||
} | ||
.frame(idealWidth: .infinity, maxWidth: .infinity, alignment: .topLeading) | ||
.padding(10) | ||
.background(Color("BlackWhite1")) | ||
.roundedBorder() | ||
} | ||
|
||
} | ||
|
||
#endif |
49 changes: 49 additions & 0 deletions
49
...workProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationPreferenceItemModel.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// | ||
// NetworkProtectionLocationSettingsItemModel.swift | ||
// | ||
// Copyright © 2023 DuckDuckGo. All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
|
||
#if NETWORK_PROTECTION | ||
|
||
import Foundation | ||
import NetworkProtection | ||
|
||
struct VPNLocationPreferenceItemModel { | ||
enum LocationIcon { | ||
case defaultIcon | ||
case emoji(String) | ||
} | ||
|
||
let title: String | ||
let subtitle: String? | ||
let icon: LocationIcon | ||
|
||
init(selectedLocation: VPNSettings.SelectedLocation) { | ||
switch selectedLocation { | ||
case .nearest: | ||
title = UserText.vpnLocationNearestAvailable | ||
subtitle = UserText.vpnLocationNearestAvailableSubtitle | ||
icon = .defaultIcon | ||
case .location(let location): | ||
let countryLabelsModel = NetworkProtectionVPNCountryLabelsModel(country: location.country) | ||
title = countryLabelsModel.title | ||
subtitle = selectedLocation.location?.city | ||
icon = .emoji(countryLabelsModel.emoji) | ||
} | ||
} | ||
} | ||
|
||
#endif |
Oops, something went wrong.