From 5d85699ce47008bfa5822325acbaa52c24af91f4 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Tue, 19 Apr 2022 08:33:22 +0200 Subject: [PATCH] Delete profile from Organizer Swipe to delete. Address a couple things on iPad though: 1. Also check provider availability before showing view fatalError hit on iPad when navigating from a ready provider profile to a non-ready one. Similar to when navigating between different VPN protocols. 2. Suppress assertion on deleted profile Deleting current profile via swipe seems to re-render a new NavigationLink with the deleted profile, which results in loading a deleted profile and hitting the assertion. Not sure if this is a programming error or a glitch in ForEach. --- .../iOS/Views/OrganizerView+Profiles.swift | 10 +++++ .../App/iOS/Views/ProfileView+Provider.swift | 12 +++-- Passepartout/App/iOS/Views/ProfileView.swift | 44 ------------------- .../Managers/ProfileManager.swift | 2 +- 4 files changed, 20 insertions(+), 48 deletions(-) diff --git a/Passepartout/App/iOS/Views/OrganizerView+Profiles.swift b/Passepartout/App/iOS/Views/OrganizerView+Profiles.swift index 30a82f68..f52416f1 100644 --- a/Passepartout/App/iOS/Views/OrganizerView+Profiles.swift +++ b/Passepartout/App/iOS/Views/OrganizerView+Profiles.swift @@ -78,6 +78,7 @@ extension OrganizerView { List { Section { ForEach(headers.sorted(), content: navigationLink(forHeader:)) + .onDelete(perform: removeProfiles) .onAppear(perform: selectActiveProfile) } } @@ -157,6 +158,15 @@ extension OrganizerView.ProfilesList { } } + private func removeProfiles(_ indexSet: IndexSet) { + let headers = profileManager.headers.sorted() + var toDelete: [UUID] = [] + indexSet.forEach { + toDelete.append(headers[$0].id) + } + profileManager.removeProfiles(withIds: toDelete) + } + private func dismissSelectionIfDeleted(headers: [Profile.Header]) { if let selectedProfileId = selectedProfileId, !profileManager.isExistingProfile(withId: selectedProfileId) { diff --git a/Passepartout/App/iOS/Views/ProfileView+Provider.swift b/Passepartout/App/iOS/Views/ProfileView+Provider.swift index c6d42638..80caa8ba 100644 --- a/Passepartout/App/iOS/Views/ProfileView+Provider.swift +++ b/Passepartout/App/iOS/Views/ProfileView+Provider.swift @@ -44,7 +44,7 @@ extension ProfileView { var body: some View { debugChanges() return Group { - if !isEmpty { + if canDisplay { mainView } else { EmptyView() @@ -52,8 +52,14 @@ extension ProfileView { } } - private var isEmpty: Bool { - currentProfile.value.isPlaceholder || !currentProfile.value.isProvider + 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 { diff --git a/Passepartout/App/iOS/Views/ProfileView.swift b/Passepartout/App/iOS/Views/ProfileView.swift index 7d921090..1b7e415e 100644 --- a/Passepartout/App/iOS/Views/ProfileView.swift +++ b/Passepartout/App/iOS/Views/ProfileView.swift @@ -53,8 +53,6 @@ struct ProfileView: View { @State private var modalType: ModalType? @State private var isLoaded = false - - @State private var isAskingRemoveProfile = false init(header: Profile.Header?) { let profileManager: ProfileManager = .shared @@ -98,7 +96,6 @@ struct ProfileView: View { ) ExtraSection(currentProfile: profileManager.currentProfile) DiagnosticsSection(currentProfile: profileManager.currentProfile) - removeProfileSection UninstallVPNSection() } @@ -152,47 +149,6 @@ struct ProfileView: View { } } - private var removeProfileSection: some View { - Section { - Button { - isAskingRemoveProfile = true - } label: { - Label(L10n.Organizer.Alerts.RemoveProfile.title, systemImage: themeDeleteImage) - }.foregroundColor(themeErrorColor) - .actionSheet(isPresented: $isAskingRemoveProfile) { - ActionSheet( - title: Text(L10n.Organizer.Alerts.RemoveProfile.message(header.name)), - message: nil, - buttons: [ - .destructive(Text(L10n.Organizer.Alerts.RemoveProfile.title), action: confirmRemoveProfile), - .cancel(Text(L10n.Global.Strings.cancel)) - ] - ) - } - } - } - - private func confirmRemoveProfile() { - withAnimation { - removeProfile() - } - } - - private func removeProfile() { - guard profileManager.isExistingProfile(withId: header.id) else { - assertionFailure("Deleting non-existent profile \(header.name)") - return - } - IntentDispatcher.forgetProfile(withHeader: header) - profileManager.removeProfiles(withIds: [header.id]) - - // XXX: iOS 14, NavigationLink removal via header removal in OrganizerView+Profiles doesn't pop - if #available(iOS 15, *) { - } else { - presentationMode.wrappedValue.dismiss() - } - } - private func loadProfileIfNeeded() { guard !isLoaded else { return diff --git a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager.swift b/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager.swift index 372e16bd..e9a5f687 100644 --- a/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager.swift +++ b/PassepartoutCore/Sources/PassepartoutProfiles/Managers/ProfileManager.swift @@ -162,7 +162,7 @@ extension ProfileManager { } guard let profile = strategy.profile(withId: id) else { - assertionFailure("Profile in headers yet not found in persistent store") +// assertionFailure("Profile in headers yet not found in persistent store") return nil } guard availabilityFilter?(profile.header) ?? true else {