2024-10-10 22:24:06 +00:00
//
// V P N P r o v i d e r S e r v e r V i e w . s w i f t
// P a s s e p a r t o u t
//
// C r e a t e d b y D a v i d e D e R o s a o n 1 0 / 7 / 2 4 .
// C o p y r i g h t ( c ) 2 0 2 4 D a v i d e D e R o s a . A l l r i g h t s r e s e r v e d .
//
// h t t p s : / / g i t h u b . c o m / p a s s e p a r t o u t v p n
//
// T h i s f i l e i s p a r t o f P a s s e p a r t o u t .
//
// P a s s e p a r t o u t i s f r e e s o f t w a r e : y o u c a n r e d i s t r i b u t e i t a n d / o r m o d i f y
// i t u n d e r t h e t e r m s o f t h e G N U G e n e r a l P u b l i c L i c e n s e a s p u b l i s h e d b y
// t h e F r e e S o f t w a r e F o u n d a t i o n , e i t h e r v e r s i o n 3 o f t h e L i c e n s e , o r
// ( a t y o u r o p t i o n ) a n y l a t e r v e r s i o n .
//
// P a s s e p a r t o u t i s d i s t r i b u t e d i n t h e h o p e t h a t i t w i l l b e u s e f u l ,
// b u t W I T H O U T A N Y W A R R A N T Y ; w i t h o u t e v e n t h e i m p l i e d w a r r a n t y o f
// M E R C H A N T A B I L I T Y o r F I T N E S S F O R A P A R T I C U L A R P U R P O S E . S e e t h e
// G N U G e n e r a l P u b l i c L i c e n s e f o r m o r e d e t a i l s .
//
// Y o u s h o u l d h a v e r e c e i v e d a c o p y o f t h e G N U G e n e r a l P u b l i c L i c e n s e
// a l o n g w i t h P a s s e p a r t o u t . I f n o t , s e e < h t t p : / / w w w . g n u . o r g / l i c e n s e s / > .
//
import AppLibrary
import PassepartoutKit
import SwiftUI
2024-10-18 16:12:28 +00:00
import UtilsLibrary
2024-10-10 22:24:06 +00:00
2024-10-15 19:34:02 +00:00
struct VPNProviderServerView < Configuration > : View where Configuration : ProviderConfigurationIdentifiable & Codable {
2024-10-10 22:24:06 +00:00
2024-10-18 16:12:28 +00:00
@ EnvironmentObject
private var providerManager : ProviderManager
2024-10-23 13:42:54 +00:00
var apis : [ APIMapper ] = API . shared
2024-10-18 16:12:28 +00:00
let providerId : ProviderID
let configurationType : Configuration . Type
2024-10-23 15:58:04 +00:00
let selectedEntity : VPNEntity < Configuration > ?
2024-10-10 22:24:06 +00:00
2024-10-23 20:57:30 +00:00
let filtersWithSelection : Bool
2024-10-25 09:38:27 +00:00
let selectTitle : String
2024-10-10 22:24:06 +00:00
let onSelect : ( _ server : VPNServer , _ preset : VPNPreset < Configuration > ) -> Void
2024-10-18 16:12:28 +00:00
@ StateObject
private var manager = VPNProviderManager < Configuration > ( sorting : [
. localizedCountry ,
. area ,
. hostname
] )
@ State
private var filters = VPNFilters ( )
@ StateObject
private var errorHandler : ErrorHandler = . default ( )
2024-10-10 22:24:06 +00:00
var body : some View {
2024-10-18 16:12:28 +00:00
debugChanges ( )
return Subview (
manager : manager ,
2024-10-23 16:40:09 +00:00
selectedServer : selectedEntity ? . server ,
2024-10-18 16:12:28 +00:00
filters : $ filters ,
2024-10-25 09:38:27 +00:00
selectTitle : selectTitle ,
2024-10-18 16:12:28 +00:00
onSelect : selectServer
)
. withErrorHandler ( errorHandler )
. navigationTitle ( Strings . Global . servers )
2024-10-25 09:38:27 +00:00
. themeNavigationDetail ( )
2024-10-18 16:12:28 +00:00
. onLoad {
Task {
do {
manager . repository = try await providerManager . vpnRepository (
from : apis ,
2024-10-25 08:54:28 +00:00
for : providerId
2024-10-18 16:12:28 +00:00
)
2024-10-23 20:57:30 +00:00
if let selectedEntity , filtersWithSelection {
2024-10-18 16:12:28 +00:00
filters = VPNFilters ( with : selectedEntity . server . provider )
} else {
filters = VPNFilters ( )
}
manager . applyFilters ( filters )
} catch {
pp_log ( . app , . error , " Unable to load VPN repository: \( error ) " )
errorHandler . handle ( error , title : Strings . Global . servers )
}
}
}
2024-10-10 22:24:06 +00:00
}
}
// MARK: - A c t i o n s
extension VPNProviderServerView {
func compatiblePreset ( with server : VPNServer ) -> VPNPreset < Configuration > ? {
2024-10-13 09:36:34 +00:00
manager
2024-10-18 16:12:28 +00:00
. presets
2024-10-10 22:24:06 +00:00
. first {
if let supportedIds = server . provider . supportedPresetIds {
return supportedIds . contains ( $0 . presetId )
}
return true
}
}
2024-10-18 16:12:28 +00:00
func selectServer ( _ server : VPNServer ) {
guard let preset = compatiblePreset ( with : server ) else {
pp_log ( . app , . error , " Unable to find a compatible preset. Supported IDs: \( server . provider . supportedPresetIds ? ? [ ] ) " )
assertionFailure ( " No compatible presets for server \( server . serverId ) (manager= \( manager . providerId ) , configuration= \( Configuration . providerConfigurationIdentifier ) , supported= \( server . provider . supportedPresetIds ? ? [ ] ) ) " )
return
}
onSelect ( server , preset )
}
2024-10-10 22:24:06 +00:00
}
// MARK: - P r e v i e w
# Preview {
NavigationStack {
2024-10-23 15:17:20 +00:00
VPNProviderServerView (
2024-10-18 16:12:28 +00:00
apis : [ API . bundled ] ,
providerId : . protonvpn ,
2024-10-23 15:58:04 +00:00
configurationType : OpenVPN . Configuration . self ,
selectedEntity : nil ,
2024-10-23 20:57:30 +00:00
filtersWithSelection : false ,
2024-10-25 09:38:27 +00:00
selectTitle : " Select " ,
2024-10-23 15:58:04 +00:00
onSelect : { _ , _ in }
)
2024-10-10 22:24:06 +00:00
}
. withMockEnvironment ( )
}