Attempt an iOS layout with DisclosureGroup

Also fix missing initial filters based on selection.

Fixes #746
This commit is contained in:
Davide 2024-10-23 17:58:04 +02:00
parent 2455c5397e
commit 48dc31a1f1
No known key found for this signature in database
GPG Key ID: A48836171C759F5E
4 changed files with 76 additions and 10 deletions

View File

@ -130,6 +130,7 @@ private extension OpenVPNView {
VPNProviderServerView( VPNProviderServerView(
providerId: $0, providerId: $0,
configurationType: OpenVPN.Configuration.self, configurationType: OpenVPN.Configuration.self,
selectedEntity: providerEntity.wrappedValue,
onSelect: onSelectServer onSelect: onSelectServer
) )
} }

View File

@ -39,7 +39,7 @@ struct VPNProviderServerView<Configuration>: View where Configuration: ProviderC
let configurationType: Configuration.Type let configurationType: Configuration.Type
var selectedEntity: VPNEntity<Configuration>? let selectedEntity: VPNEntity<Configuration>?
let onSelect: (_ server: VPNServer, _ preset: VPNPreset<Configuration>) -> Void let onSelect: (_ server: VPNServer, _ preset: VPNPreset<Configuration>) -> Void
@ -119,9 +119,10 @@ extension VPNProviderServerView {
VPNProviderServerView( VPNProviderServerView(
apis: [API.bundled], apis: [API.bundled],
providerId: .protonvpn, providerId: .protonvpn,
configurationType: OpenVPN.Configuration.self configurationType: OpenVPN.Configuration.self,
) { _, _ in selectedEntity: nil,
} onSelect: { _, _ in }
)
} }
.withMockEnvironment() .withMockEnvironment()
} }

View File

@ -55,20 +55,54 @@ extension VPNProviderServerView {
private extension VPNProviderServerView.Subview { private extension VPNProviderServerView.Subview {
var listView: some View { var listView: some View {
List { List {
// FIXME: #746, providers UI, iOS server rows + country flags
if manager.isFiltering { if manager.isFiltering {
ProgressView() ProgressView()
} else { } else {
ForEach(manager.filteredServers, id: \.id) { server in ForEach(countryCodes, id: \.self, content: countryView)
Button("\(server.hostname ?? server.id) \(server.provider.countryCode)") {
onSelect(server)
}
}
} }
} }
.themeAnimation(on: manager.isFiltering, category: .providers) .themeAnimation(on: manager.isFiltering, category: .providers)
} }
var countryCodes: [String] {
manager
.allCountryCodes
.sorted {
$0.localizedAsRegionCode! < $1.localizedAsRegionCode!
}
}
func countryServers(for code: String) -> [VPNServer]? {
manager
.filteredServers
.filter {
$0.provider.countryCode == code
}
.nilIfEmpty
}
func countryView(for code: String) -> some View {
countryServers(for: code)
.map { servers in
DisclosureGroup {
ForEach(servers, id: \.serverId, content: serverView)
} label: {
HStack {
ThemeCountryFlag(code: code)
Text(code.localizedAsRegionCode!)
}
}
}
}
func serverView(for server: VPNServer) -> some View {
Button {
onSelect(server)
} label: {
Text(server.hostname ?? server.id)
}
}
var filtersItem: some ToolbarContent { var filtersItem: some ToolbarContent {
ToolbarItem { ToolbarItem {
Button { Button {
@ -93,4 +127,19 @@ private extension VPNProviderServerView.Subview {
} }
} }
// MARK: - Preview
#Preview {
NavigationStack {
VPNProviderServerView(
apis: [API.bundled],
providerId: .tunnelbear,
configurationType: OpenVPN.Configuration.self,
selectedEntity: nil,
onSelect: { _, _ in }
)
}
.withMockEnvironment()
}
#endif #endif

View File

@ -82,4 +82,19 @@ private extension VPNProviderServerView.Subview {
} }
} }
// MARK: - Preview
#Preview {
NavigationStack {
VPNProviderServerView(
apis: [API.bundled],
providerId: .tunnelbear,
configurationType: OpenVPN.Configuration.self,
selectedEntity: nil,
onSelect: { _, _ in }
)
}
.withMockEnvironment()
}
#endif #endif