diff --git a/Passepartout.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Passepartout.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e058c40f..be4a2c01 100644 --- a/Passepartout.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Passepartout.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -41,7 +41,7 @@ "kind" : "remoteSourceControl", "location" : "git@github.com:passepartoutvpn/passepartoutkit-source", "state" : { - "revision" : "39cd828d3ee7cb502c4c0e36e3dc42e45bfae10b" + "revision" : "c0a615bc7a85d68a9b00d3703d0dae6efab9bdd2" } }, { diff --git a/Passepartout/Library/Package.swift b/Passepartout/Library/Package.swift index 1cb6c7da..e27bb2a4 100644 --- a/Passepartout/Library/Package.swift +++ b/Passepartout/Library/Package.swift @@ -44,7 +44,7 @@ let package = Package( ], dependencies: [ // .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", from: "0.11.0"), - .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "39cd828d3ee7cb502c4c0e36e3dc42e45bfae10b"), + .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "c0a615bc7a85d68a9b00d3703d0dae6efab9bdd2"), // .package(path: "../../../passepartoutkit-source"), .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", from: "0.9.1"), // .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"), diff --git a/Passepartout/Library/Sources/AppUIMain/Extensions/ProviderEntityViewProviding+Extensions.swift b/Passepartout/Library/Sources/AppUIMain/Extensions/ProviderEntityViewProviding+Extensions.swift index d14499d9..4f9f9fa5 100644 --- a/Passepartout/Library/Sources/AppUIMain/Extensions/ProviderEntityViewProviding+Extensions.swift +++ b/Passepartout/Library/Sources/AppUIMain/Extensions/ProviderEntityViewProviding+Extensions.swift @@ -27,9 +27,9 @@ import CommonUtils import PassepartoutKit import SwiftUI -extension ProviderEntityViewProviding where Self: ProviderCompatibleModule, EntityType.Configuration: ProviderConfigurationIdentifiable & Codable { +extension ProviderEntityViewProviding where Self: ProviderTransformable, EntityType.Configuration: ProviderConfigurationIdentifiable & Codable { func vpnProviderEntityView( - with provider: ModuleMetadata.Provider, + with provider: SerializedProvider, errorHandler: ErrorHandler, onSelect: @escaping (any ProviderEntity & Encodable) async throws -> Void ) -> some View { diff --git a/Passepartout/Library/Sources/AppUIMain/Protocols/ProviderEntityViewProviding.swift b/Passepartout/Library/Sources/AppUIMain/Protocols/ProviderEntityViewProviding.swift index bc45486c..d63892e3 100644 --- a/Passepartout/Library/Sources/AppUIMain/Protocols/ProviderEntityViewProviding.swift +++ b/Passepartout/Library/Sources/AppUIMain/Protocols/ProviderEntityViewProviding.swift @@ -32,7 +32,7 @@ protocol ProviderEntityViewProviding { @MainActor func providerEntityView( - with provider: ModuleMetadata.Provider, + with provider: SerializedProvider, errorHandler: ErrorHandler, onSelect: @escaping (any ProviderEntity & Encodable) async throws -> Void ) -> EntityContent diff --git a/Passepartout/Library/Sources/AppUIMain/Views/App/AppCoordinator.swift b/Passepartout/Library/Sources/AppUIMain/Views/App/AppCoordinator.swift index ad82264d..799cd6ec 100644 --- a/Passepartout/Library/Sources/AppUIMain/Views/App/AppCoordinator.swift +++ b/Passepartout/Library/Sources/AppUIMain/Views/App/AppCoordinator.swift @@ -89,7 +89,7 @@ extension AppCoordinator { enum ModalRoute: Identifiable { case editProfile - case editProviderEntity(Profile, Module, ModuleMetadata.Provider) + case editProviderEntity(Profile, Module, SerializedProvider) case migrateProfiles diff --git a/Passepartout/Library/Sources/AppUIMain/Views/App/InstalledProfileView.swift b/Passepartout/Library/Sources/AppUIMain/Views/App/InstalledProfileView.swift index 298605d0..e2894acf 100644 --- a/Passepartout/Library/Sources/AppUIMain/Views/App/InstalledProfileView.swift +++ b/Passepartout/Library/Sources/AppUIMain/Views/App/InstalledProfileView.swift @@ -145,7 +145,7 @@ private extension InstalledProfileView { } } - func providerSelectorLabel(with provider: ModuleMetadata.Provider) -> some View { + func providerSelectorLabel(with provider: SerializedProvider) -> some View { ProviderCountryFlag(provider: provider) } } @@ -215,7 +215,7 @@ private struct ToggleButton: View { } private struct ProviderCountryFlag: View { - let provider: ModuleMetadata.Provider + let provider: SerializedProvider var body: some View { ThemeCountryFlag( diff --git a/Passepartout/Library/Sources/AppUIMain/Views/App/ProviderEntitySelector.swift b/Passepartout/Library/Sources/AppUIMain/Views/App/ProviderEntitySelector.swift index 54de04ff..3bb73c47 100644 --- a/Passepartout/Library/Sources/AppUIMain/Views/App/ProviderEntitySelector.swift +++ b/Passepartout/Library/Sources/AppUIMain/Views/App/ProviderEntitySelector.swift @@ -40,7 +40,7 @@ struct ProviderEntitySelector: View { let module: Module - let provider: ModuleMetadata.Provider + let provider: SerializedProvider let errorHandler: ErrorHandler @@ -61,10 +61,18 @@ private extension ProviderEntitySelector { func onSelect(_ entity: any ProviderEntity & Encodable) async throws { pp_log(.app, .info, "Select new provider entity: \(entity)") - var builder = profile.builder() do { - try builder.setProviderEntity(entity, forModuleWithId: module.id) + guard var moduleBuilder = module.asProviderModuleBuilder else { + assertionFailure("Module is not a ProviderModuleBuilder?") + return + } + try moduleBuilder.setProviderEntity(entity) + let newModule = try moduleBuilder.tryBuild() + + var builder = profile.builder() + builder.saveModule(newModule) let newProfile = try builder.tryBuild() + try await profileManager.save(newProfile) // will reconnect via AppContext observation diff --git a/Passepartout/Library/Sources/AppUIMain/Views/Modules/Extensions/OpenVPNModule+Extensions.swift b/Passepartout/Library/Sources/AppUIMain/Views/Modules/Extensions/OpenVPNModule+Extensions.swift index 7b00e34d..1d01fa91 100644 --- a/Passepartout/Library/Sources/AppUIMain/Views/Modules/Extensions/OpenVPNModule+Extensions.swift +++ b/Passepartout/Library/Sources/AppUIMain/Views/Modules/Extensions/OpenVPNModule+Extensions.swift @@ -35,7 +35,7 @@ extension OpenVPNModule.Builder: ModuleViewProviding { extension OpenVPNModule: ProviderEntityViewProviding { func providerEntityView( - with provider: ModuleMetadata.Provider, + with provider: SerializedProvider, errorHandler: ErrorHandler, onSelect: @escaping (any ProviderEntity & Encodable) async throws -> Void ) -> some View { diff --git a/Passepartout/Library/Sources/LegacyV2/Domain/MapperV2.swift b/Passepartout/Library/Sources/LegacyV2/Domain/MapperV2.swift index 3237089e..34bd65be 100644 --- a/Passepartout/Library/Sources/LegacyV2/Domain/MapperV2.swift +++ b/Passepartout/Library/Sources/LegacyV2/Domain/MapperV2.swift @@ -36,9 +36,7 @@ struct MapperV2 { if let provider = v2.provider { if let module = try toProviderModule(provider) { - let providerId = ProviderID(rawValue: provider.name) modules.append(module) - builder.setProviderId(providerId, forModuleWithId: module.id) } } else if let ovpn = v2.host?.ovpnSettings { modules.append(try toOpenVPNModule(ovpn)) @@ -113,6 +111,7 @@ extension MapperV2 { let settings = entry.value var builder = OpenVPNModule.Builder() + builder.provider = SerializedProvider(id: ProviderID(rawValue: v2.name)) builder.credentials = settings.account.map(toOpenVPNCredentials) return try builder.tryBuild() } diff --git a/Passepartout/Library/Sources/UILibrary/Business/ProfileEditor.swift b/Passepartout/Library/Sources/UILibrary/Business/ProfileEditor.swift index e6d9baa7..4e0d8a56 100644 --- a/Passepartout/Library/Sources/UILibrary/Business/ProfileEditor.swift +++ b/Passepartout/Library/Sources/UILibrary/Business/ProfileEditor.swift @@ -123,6 +123,10 @@ extension ProfileEditor { } ?? removedModules[moduleId] } + public func providerModule(withId moduleId: UUID) -> (any ProviderModuleBuilder)? { + module(withId: moduleId) as? any ProviderModuleBuilder + } + public func isActiveModule(withId moduleId: UUID) -> Bool { editableProfile.isActiveModule(withId: moduleId) } diff --git a/Passepartout/Library/Sources/UILibrary/Domain/EditableProfile.swift b/Passepartout/Library/Sources/UILibrary/Domain/EditableProfile.swift index 596b60a9..3e260153 100644 --- a/Passepartout/Library/Sources/UILibrary/Domain/EditableProfile.swift +++ b/Passepartout/Library/Sources/UILibrary/Domain/EditableProfile.swift @@ -97,15 +97,25 @@ extension Profile { public var modulesBuilders: [any ModuleBuilder] { modules.compactMap { - guard let buildableModule = $0 as? any BuildableType else { - return nil - } - let builder = buildableModule.builder() as any BuilderType - return builder as? any ModuleBuilder + $0.asModuleBuilder } } } +extension Module { + public var asModuleBuilder: (any ModuleBuilder)? { + guard let buildableModule = self as? any BuildableType else { + return nil + } + let builder = buildableModule.builder() as any BuilderType + return builder as? any ModuleBuilder + } + + public var asProviderModuleBuilder: (any ProviderModuleBuilder)? { + asModuleBuilder as? any ProviderModuleBuilder + } +} + private extension EditableProfile { var activeConnectionModule: (any ModuleBuilder)? { modules.first { diff --git a/Passepartout/Library/Sources/UILibrary/Extensions/ProfileEditor+UI.swift b/Passepartout/Library/Sources/UILibrary/Extensions/ProfileEditor+UI.swift index e74490e0..4625eac2 100644 --- a/Passepartout/Library/Sources/UILibrary/Extensions/ProfileEditor+UI.swift +++ b/Passepartout/Library/Sources/UILibrary/Extensions/ProfileEditor+UI.swift @@ -37,17 +37,25 @@ extension ProfileEditor { public func binding(forProviderOf moduleId: UUID) -> Binding { Binding { [weak self] in - self?.profile.providerId(forModuleWithId: moduleId) + self?.providerModule(withId: moduleId)?.providerId } set: { [weak self] in - self?.profile.setProviderId($0, forModuleWithId: moduleId) + guard var builder = self?.providerModule(withId: moduleId) else { + return + } + builder.providerId = $0 + self?.saveModule(builder, activating: false) } } public func binding(forProviderEntityOf moduleId: UUID) -> Binding where E: ProviderEntity & Codable { Binding { [weak self] in - try? self?.profile.providerEntity(E.self, forModuleWithId: moduleId) + try? self?.providerModule(withId: moduleId)?.providerEntity(E.self) } set: { [weak self] in - try? self?.profile.setProviderEntity($0, forModuleWithId: moduleId) + guard var builder = self?.providerModule(withId: moduleId) else { + return + } + try? builder.setProviderEntity($0) + self?.saveModule(builder, activating: false) } }