Externalize complex bindings (#329)
Some bindings are too convoluted, move them out of initializers.
This commit is contained in:
parent
0804c6b38e
commit
4173c7aa6c
|
@ -47,58 +47,14 @@ extension EndpointView {
|
||||||
|
|
||||||
@State private var selectedPort: UInt16 = 0
|
@State private var selectedPort: UInt16 = 0
|
||||||
|
|
||||||
// XXX: do not escape mutating 'self', use constant providerManager
|
|
||||||
init(currentProfile: ObservableProfile) {
|
init(currentProfile: ObservableProfile) {
|
||||||
let providerManager: ProviderManager = .shared
|
let providerManager: ProviderManager = .shared
|
||||||
|
|
||||||
self.providerManager = providerManager
|
self.providerManager = providerManager
|
||||||
self.currentProfile = currentProfile
|
self.currentProfile = currentProfile
|
||||||
|
|
||||||
_builder = .init {
|
_builder = currentProfile.builderBinding(providerManager: providerManager)
|
||||||
if currentProfile.value.isProvider {
|
_customEndpoint = currentProfile.customEndpointBinding
|
||||||
guard let server = currentProfile.value.providerServer(providerManager) else {
|
|
||||||
assertionFailure("Server not found")
|
|
||||||
return .init()
|
|
||||||
}
|
|
||||||
guard let preset = currentProfile.value.providerPreset(server) else {
|
|
||||||
assertionFailure("Preset not found")
|
|
||||||
return .init()
|
|
||||||
}
|
|
||||||
guard let cfg = preset.openVPNConfiguration else {
|
|
||||||
assertionFailure("Preset \(preset.id) (\(preset.name)) has no OpenVPN configuration")
|
|
||||||
return .init()
|
|
||||||
}
|
|
||||||
var builder = cfg.builder(withFallbacks: true)
|
|
||||||
try? builder.setRemotes(from: preset, with: server, excludingHostname: false)
|
|
||||||
return builder
|
|
||||||
} else if let cfg = currentProfile.value.hostOpenVPNSettings?.configuration {
|
|
||||||
let builder = cfg.builder(withFallbacks: true)
|
|
||||||
// pp_log.debug("Loading OpenVPN configuration: \(builder)")
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
// fall back gracefully
|
|
||||||
return .init()
|
|
||||||
} set: {
|
|
||||||
if currentProfile.value.isProvider {
|
|
||||||
// readonly
|
|
||||||
} else {
|
|
||||||
pp_log.debug("Saving OpenVPN configuration: \($0)")
|
|
||||||
currentProfile.value.hostOpenVPNSettings?.configuration = $0.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_customEndpoint = .init {
|
|
||||||
if currentProfile.value.isProvider {
|
|
||||||
return currentProfile.value.providerCustomEndpoint
|
|
||||||
} else {
|
|
||||||
return currentProfile.value.hostOpenVPNSettings?.customEndpoint
|
|
||||||
}
|
|
||||||
} set: {
|
|
||||||
if currentProfile.value.isProvider {
|
|
||||||
currentProfile.value.providerCustomEndpoint = $0
|
|
||||||
} else {
|
|
||||||
currentProfile.value.hostOpenVPNSettings?.customEndpoint = $0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -280,3 +236,58 @@ private extension EndpointView.OpenVPNView {
|
||||||
proxy.maybeScrollTo(customEndpoint?.id)
|
proxy.maybeScrollTo(customEndpoint?.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Bindings
|
||||||
|
|
||||||
|
private extension ObservableProfile {
|
||||||
|
func builderBinding(providerManager: ProviderManager) -> Binding<OpenVPN.ConfigurationBuilder> {
|
||||||
|
.init {
|
||||||
|
if self.value.isProvider {
|
||||||
|
guard let server = self.value.providerServer(providerManager) else {
|
||||||
|
assertionFailure("Server not found")
|
||||||
|
return .init()
|
||||||
|
}
|
||||||
|
guard let preset = self.value.providerPreset(server) else {
|
||||||
|
assertionFailure("Preset not found")
|
||||||
|
return .init()
|
||||||
|
}
|
||||||
|
guard let cfg = preset.openVPNConfiguration else {
|
||||||
|
assertionFailure("Preset \(preset.id) (\(preset.name)) has no OpenVPN configuration")
|
||||||
|
return .init()
|
||||||
|
}
|
||||||
|
var builder = cfg.builder(withFallbacks: true)
|
||||||
|
try? builder.setRemotes(from: preset, with: server, excludingHostname: false)
|
||||||
|
return builder
|
||||||
|
} else if let cfg = self.value.hostOpenVPNSettings?.configuration {
|
||||||
|
let builder = cfg.builder(withFallbacks: true)
|
||||||
|
// pp_log.debug("Loading OpenVPN configuration: \(builder)")
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
// fall back gracefully
|
||||||
|
return .init()
|
||||||
|
} set: {
|
||||||
|
if self.value.isProvider {
|
||||||
|
// readonly
|
||||||
|
} else {
|
||||||
|
pp_log.debug("Saving OpenVPN configuration: \($0)")
|
||||||
|
self.value.hostOpenVPNSettings?.configuration = $0.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var customEndpointBinding: Binding<Endpoint?> {
|
||||||
|
.init {
|
||||||
|
if self.value.isProvider {
|
||||||
|
return self.value.providerCustomEndpoint
|
||||||
|
} else {
|
||||||
|
return self.value.hostOpenVPNSettings?.customEndpoint
|
||||||
|
}
|
||||||
|
} set: {
|
||||||
|
if self.value.isProvider {
|
||||||
|
self.value.providerCustomEndpoint = $0
|
||||||
|
} else {
|
||||||
|
self.value.hostOpenVPNSettings?.customEndpoint = $0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ extension EndpointView {
|
||||||
|
|
||||||
// var customPeer: Binding<Endpoint?>? = nil
|
// var customPeer: Binding<Endpoint?>? = nil
|
||||||
|
|
||||||
// XXX: do not escape mutating 'self', use constant providerManager
|
|
||||||
init(currentProfile: ObservableProfile, isReadonly: Bool) {
|
init(currentProfile: ObservableProfile, isReadonly: Bool) {
|
||||||
let providerManager: ProviderManager = .shared
|
let providerManager: ProviderManager = .shared
|
||||||
|
|
||||||
|
@ -47,36 +46,7 @@ extension EndpointView {
|
||||||
self.currentProfile = currentProfile
|
self.currentProfile = currentProfile
|
||||||
self.isReadonly = isReadonly
|
self.isReadonly = isReadonly
|
||||||
|
|
||||||
_builder = .init {
|
_builder = currentProfile.builderBinding(providerManager: providerManager)
|
||||||
if currentProfile.value.isProvider {
|
|
||||||
guard let server = currentProfile.value.providerServer(providerManager) else {
|
|
||||||
assertionFailure("Server not found")
|
|
||||||
return .init()
|
|
||||||
}
|
|
||||||
guard let preset = currentProfile.value.providerPreset(server) else {
|
|
||||||
assertionFailure("Preset not found")
|
|
||||||
return .init()
|
|
||||||
}
|
|
||||||
guard let cfg = preset.wireGuardConfiguration else {
|
|
||||||
assertionFailure("Preset \(preset.id) (\(preset.name)) has no WireGuard configuration")
|
|
||||||
return .init()
|
|
||||||
}
|
|
||||||
return cfg.builder()
|
|
||||||
} else if let cfg = currentProfile.value.hostWireGuardSettings?.configuration {
|
|
||||||
let builder = cfg.builder()
|
|
||||||
// pp_log.debug("Loading WireGuard configuration: \(builder)")
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
// fall back gracefully
|
|
||||||
return .init()
|
|
||||||
} set: {
|
|
||||||
if currentProfile.value.isProvider {
|
|
||||||
// readonly
|
|
||||||
} else {
|
|
||||||
pp_log.debug("Saving WireGuard configuration: \($0)")
|
|
||||||
currentProfile.value.hostWireGuardSettings?.configuration = $0.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -146,3 +116,40 @@ private extension EndpointView.WireGuardView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Bindings
|
||||||
|
|
||||||
|
private extension ObservableProfile {
|
||||||
|
func builderBinding(providerManager: ProviderManager) -> Binding<WireGuard.ConfigurationBuilder> {
|
||||||
|
.init {
|
||||||
|
if self.value.isProvider {
|
||||||
|
guard let server = self.value.providerServer(providerManager) else {
|
||||||
|
assertionFailure("Server not found")
|
||||||
|
return .init()
|
||||||
|
}
|
||||||
|
guard let preset = self.value.providerPreset(server) else {
|
||||||
|
assertionFailure("Preset not found")
|
||||||
|
return .init()
|
||||||
|
}
|
||||||
|
guard let cfg = preset.wireGuardConfiguration else {
|
||||||
|
assertionFailure("Preset \(preset.id) (\(preset.name)) has no WireGuard configuration")
|
||||||
|
return .init()
|
||||||
|
}
|
||||||
|
return cfg.builder()
|
||||||
|
} else if let cfg = self.value.hostWireGuardSettings?.configuration {
|
||||||
|
let builder = cfg.builder()
|
||||||
|
// pp_log.debug("Loading WireGuard configuration: \(builder)")
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
// fall back gracefully
|
||||||
|
return .init()
|
||||||
|
} set: {
|
||||||
|
if self.value.isProvider {
|
||||||
|
// readonly
|
||||||
|
} else {
|
||||||
|
pp_log.debug("Saving WireGuard configuration: \($0)")
|
||||||
|
self.value.hostWireGuardSettings?.configuration = $0.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@ struct ProviderLocationView: View, ProviderProfileAvailability {
|
||||||
currentProfile.value
|
currentProfile.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: do not escape mutating 'self', use constant providerManager
|
|
||||||
init(currentProfile: ObservableProfile, isEditable: Bool, isPresented: Binding<Bool>) {
|
init(currentProfile: ObservableProfile, isEditable: Bool, isPresented: Binding<Bool>) {
|
||||||
let providerManager: ProviderManager = .shared
|
let providerManager: ProviderManager = .shared
|
||||||
|
|
||||||
|
@ -51,24 +50,8 @@ struct ProviderLocationView: View, ProviderProfileAvailability {
|
||||||
self.currentProfile = currentProfile
|
self.currentProfile = currentProfile
|
||||||
self.isEditable = isEditable
|
self.isEditable = isEditable
|
||||||
|
|
||||||
_selectedServer = .init {
|
_selectedServer = currentProfile.selectedServerBinding(providerManager: providerManager, isPresented: isPresented)
|
||||||
guard let serverId = currentProfile.value.providerServerId else {
|
_favoriteLocationIds = currentProfile.providerFavoriteLocationIdsBinding
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return providerManager.server(withId: serverId)
|
|
||||||
} set: {
|
|
||||||
// user never selects a nil server
|
|
||||||
guard let server = $0 else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentProfile.value.setProviderServer(server)
|
|
||||||
isPresented.wrappedValue = false
|
|
||||||
}
|
|
||||||
_favoriteLocationIds = .init {
|
|
||||||
currentProfile.value.providerFavoriteLocationIds
|
|
||||||
} set: {
|
|
||||||
currentProfile.value.providerFavoriteLocationIds = $0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -323,3 +306,31 @@ private extension ProviderLocationView.ServerListView {
|
||||||
proxy.maybeScrollTo(selectedServer?.id)
|
proxy.maybeScrollTo(selectedServer?.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Bindings
|
||||||
|
|
||||||
|
private extension ObservableProfile {
|
||||||
|
func selectedServerBinding(providerManager: ProviderManager, isPresented: Binding<Bool>) -> Binding<ProviderServer?> {
|
||||||
|
.init {
|
||||||
|
guard let serverId = self.value.providerServerId else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return providerManager.server(withId: serverId)
|
||||||
|
} set: {
|
||||||
|
// user never selects a nil server
|
||||||
|
guard let server = $0 else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.value.setProviderServer(server)
|
||||||
|
isPresented.wrappedValue = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var providerFavoriteLocationIdsBinding: Binding<Set<String>?> {
|
||||||
|
.init {
|
||||||
|
self.value.providerFavoriteLocationIds
|
||||||
|
} set: {
|
||||||
|
self.value.providerFavoriteLocationIds = $0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ struct ProviderPresetView: View {
|
||||||
|
|
||||||
@Binding private var selectedPreset: ProviderServer.Preset?
|
@Binding private var selectedPreset: ProviderServer.Preset?
|
||||||
|
|
||||||
// XXX: do not escape mutating 'self', use constant providerManager
|
|
||||||
init(currentProfile: ObservableProfile) {
|
init(currentProfile: ObservableProfile) {
|
||||||
let providerManager: ProviderManager = .shared
|
let providerManager: ProviderManager = .shared
|
||||||
|
|
||||||
|
@ -45,21 +44,7 @@ struct ProviderPresetView: View {
|
||||||
self.currentProfile = currentProfile
|
self.currentProfile = currentProfile
|
||||||
|
|
||||||
server = currentProfile.value.providerServer(providerManager)
|
server = currentProfile.value.providerServer(providerManager)
|
||||||
_selectedPreset = .init {
|
_selectedPreset = currentProfile.selectedPresetBinding(providerManager: providerManager)
|
||||||
guard let serverId = currentProfile.value.providerServerId else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
guard let server = providerManager.server(withId: serverId) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return currentProfile.value.providerPreset(server)
|
|
||||||
} set: {
|
|
||||||
// user never selects a nil preset
|
|
||||||
guard let preset = $0 else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentProfile.value.setProviderPreset(preset)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -106,3 +91,25 @@ private extension ProviderPresetView {
|
||||||
server?.presets?.sorted() ?? []
|
server?.presets?.sorted() ?? []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Bindings
|
||||||
|
|
||||||
|
private extension ObservableProfile {
|
||||||
|
func selectedPresetBinding(providerManager: ProviderManager) -> Binding<ProviderServer.Preset?> {
|
||||||
|
.init {
|
||||||
|
guard let serverId = self.value.providerServerId else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
guard let server = providerManager.server(withId: serverId) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return self.value.providerPreset(server)
|
||||||
|
} set: {
|
||||||
|
// user never selects a nil preset
|
||||||
|
guard let preset = $0 else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.value.setProviderPreset(preset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue