diff --git a/Passepartout.xcodeproj/project.pbxproj b/Passepartout.xcodeproj/project.pbxproj index de63aa3d..83329dd0 100644 --- a/Passepartout.xcodeproj/project.pbxproj +++ b/Passepartout.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 0E34AC7827F840890042F2AB /* OrganizerView+Scene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34AC7727F840890042F2AB /* OrganizerView+Scene.swift */; }; 0E34AC7C27F845510042F2AB /* OrganizerView+Profiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34AC7B27F845510042F2AB /* OrganizerView+Profiles.swift */; }; 0E34AC8227F892C40042F2AB /* OnDemandView+SSID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E34AC8127F892C40042F2AB /* OnDemandView+SSID.swift */; }; + 0E35C09A280E95BB0071FA35 /* ProviderProfileAvailability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E35C099280E95BB0071FA35 /* ProviderProfileAvailability.swift */; }; 0E3B7FCD27E47B3700C66F13 /* AddHostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3B7FCC27E47B3700C66F13 /* AddHostView.swift */; }; 0E3B7FD627E5173A00C66F13 /* ProfileView+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */; }; 0E3B7FDA27E51A0200C66F13 /* ProfileView+Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3B7FD927E51A0200C66F13 /* ProfileView+Provider.swift */; }; @@ -207,6 +208,7 @@ 0E34AC7727F840890042F2AB /* OrganizerView+Scene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrganizerView+Scene.swift"; sourceTree = ""; }; 0E34AC7B27F845510042F2AB /* OrganizerView+Profiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrganizerView+Profiles.swift"; sourceTree = ""; }; 0E34AC8127F892C40042F2AB /* OnDemandView+SSID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OnDemandView+SSID.swift"; sourceTree = ""; }; + 0E35C099280E95BB0071FA35 /* ProviderProfileAvailability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderProfileAvailability.swift; sourceTree = ""; }; 0E3B7FCC27E47B3700C66F13 /* AddHostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddHostView.swift; sourceTree = ""; }; 0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+VPN.swift"; sourceTree = ""; }; 0E3B7FD927E51A0200C66F13 /* ProfileView+Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Provider.swift"; sourceTree = ""; }; @@ -475,6 +477,7 @@ children = ( 0EBC075C27EC529000208AD9 /* DebugLog+Constants.swift */, 0EB17EB927D2560300D473B5 /* PassepartoutProviders+Extensions.swift */, + 0E35C099280E95BB0071FA35 /* ProviderProfileAvailability.swift */, 0E2DE71B27DCCFE80067B9E1 /* TunnelKit+Identifiable.swift */, 0EE8B7E227FF340F00B68621 /* VPNProtocolType+FileExtensions.swift */, ); @@ -943,6 +946,7 @@ 0E5324A627D297BB002565C3 /* InApp.swift in Sources */, 0E3B7FCD27E47B3700C66F13 /* AddHostView.swift in Sources */, 0EF2212D27E66EB5001D0BD7 /* AddProviderView.swift in Sources */, + 0E35C09A280E95BB0071FA35 /* ProviderProfileAvailability.swift in Sources */, 0E5349C827C176D100C71BB3 /* EndpointView+WireGuard.swift in Sources */, 0EBC076027EC587900208AD9 /* SwiftGen+Strings.swift in Sources */, 0E5683B927C2825D00EAF1CD /* DiagnosticsView.swift in Sources */, diff --git a/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme b/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme index 5824feb5..8649b99f 100644 --- a/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme +++ b/Passepartout.xcodeproj/xcshareddata/xcschemes/Passepartout.xcscheme @@ -126,7 +126,7 @@ . +// + +import Foundation +import PassepartoutCore + +protocol ProviderProfileAvailability { + var profile: Profile { get } + + var providerManager: ProviderManager { get } +} + +extension ProviderProfileAvailability { + + @MainActor + var isProviderProfileAvailable: Bool { + guard !profile.isPlaceholder else { + return false + } + guard let providerName = profile.header.providerName else { + return false + } + return providerManager.isAvailable(providerName, vpnProtocol: profile.currentVPNProtocol) + } +} diff --git a/Passepartout/App/iOS/Views/ProfileView+Provider.swift b/Passepartout/App/iOS/Views/ProfileView+Provider.swift index 80caa8ba..fa21a05c 100644 --- a/Passepartout/App/iOS/Views/ProfileView+Provider.swift +++ b/Passepartout/App/iOS/Views/ProfileView+Provider.swift @@ -27,11 +27,15 @@ import SwiftUI import PassepartoutCore extension ProfileView { - struct ProviderSection: View { - @ObservedObject private var providerManager: ProviderManager + struct ProviderSection: View, ProviderProfileAvailability { + @ObservedObject var providerManager: ProviderManager @ObservedObject private var currentProfile: ObservableProfile + var profile: Profile { + currentProfile.value + } + @State private var isProviderLocationPresented = false @State private var isRefreshingInfrastructure = false @@ -44,7 +48,7 @@ extension ProfileView { var body: some View { debugChanges() return Group { - if canDisplay { + if isProviderProfileAvailable { mainView } else { EmptyView() @@ -52,16 +56,6 @@ extension ProfileView { } } - private var canDisplay: Bool { - guard !currentProfile.value.isPlaceholder else { - return false - } - guard let providerName = currentProfile.value.header.providerName else { - return false - } - return providerManager.isAvailable(providerName, vpnProtocol: currentProfile.value.currentVPNProtocol) - } - private var mainView: some View { Section( header: Text(currentProvider.fullName), diff --git a/Passepartout/App/iOS/Views/ProviderLocationView.swift b/Passepartout/App/iOS/Views/ProviderLocationView.swift index e3b20feb..26d9b98b 100644 --- a/Passepartout/App/iOS/Views/ProviderLocationView.swift +++ b/Passepartout/App/iOS/Views/ProviderLocationView.swift @@ -26,15 +26,19 @@ import SwiftUI import PassepartoutCore -struct ProviderLocationView: View { +struct ProviderLocationView: View, ProviderProfileAvailability { + @ObservedObject var providerManager: ProviderManager + @ObservedObject private var appManager: AppManager - @ObservedObject private var providerManager: ProviderManager - @ObservedObject private var currentProfile: ObservableProfile - private let isEditable: Bool + var profile: Profile { + currentProfile.value + } + private let isEditable: Bool + private var providerName: ProviderName { guard let name = currentProfile.value.header.providerName else { assertionFailure("Not a provider") @@ -92,7 +96,7 @@ struct ProviderLocationView: View { var body: some View { debugChanges() return Group { - if !isEmpty { + if isProviderProfileAvailable { mainView } else { EmptyView() @@ -101,10 +105,6 @@ struct ProviderLocationView: View { .toolbar(content: toolbar) } - private var isEmpty: Bool { - currentProfile.value.isPlaceholder || !currentProfile.value.isProvider - } - private var mainView: some View { ScrollViewReader { scrollProxy in List {