// // ProviderContentModifier.swift // Passepartout // // Created by Davide De Rosa on 10/14/24. // Copyright (c) 2024 Davide De Rosa. All rights reserved. // // https://github.com/passepartoutvpn // // This file is part of Passepartout. // // Passepartout is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Passepartout is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Passepartout. If not, see . // import PassepartoutKit import SwiftUI struct ProviderContentModifier: ViewModifier where Entity: ProviderEntity, Entity.Configuration: ProviderConfigurationIdentifiable & Codable, ProviderRows: View { @EnvironmentObject private var providerManager: ProviderManager @EnvironmentObject private var iapManager: IAPManager let apis: [APIMapper] @Binding var providerId: ProviderID? let entityType: Entity.Type @Binding var paywallReason: PaywallReason? @ViewBuilder let providerRows: ProviderRows let onSelectProvider: (ProviderManager, ProviderID?, _ isInitial: Bool) -> Void func body(content: Content) -> some View { providerView .onLoad(perform: loadCurrentProvider) .onChange(of: providerId) { newId in Task { if let newId { await refreshInfrastructure(for: newId) } onSelectProvider(providerManager, newId, false) } } .disabled(providerManager.isLoading) content } static func == (lhs: Self, rhs: Self) -> Bool { lhs.providerId == rhs.providerId } } private extension ProviderContentModifier { #if os(iOS) @ViewBuilder var providerView: some View { Group { providerPicker purchaseButton } .themeSection() Group { if providerId != nil { providerRows refreshButton { HStack { Text(Strings.Providers.refreshInfrastructure) if providerManager.isLoading { Spacer() ProgressView() } } } } } .themeSection(footer: lastUpdatedString) } #else @ViewBuilder var providerView: some View { Section { providerPicker purchaseButton } Section { if providerId != nil { providerRows HStack { lastUpdatedString.map { Text($0) .foregroundStyle(.secondary) } Spacer() refreshButton { Text(Strings.Providers.refreshInfrastructure) } } } } } #endif var providerPicker: some View { ProviderPicker( providers: supportedProviders, providerId: $providerId, isRequired: true, isLoading: providerManager.isLoading ) } @ViewBuilder var purchaseButton: some View { switch iapManager.paywallReason(forFeature: .providers) { case .purchase(let appFeature): Button(Strings.Providers.Picker.purchase) { paywallReason = .purchase(appFeature) } default: EmptyView() } } func refreshButton