Group profile actions into menus
- Organizer - Duplicate - Profile - Rename - Siri - Uninstall (+ confirmation) - Delete (+ confirmation)
This commit is contained in:
parent
1c047b9ce2
commit
cd854f8ebf
|
@ -34,7 +34,7 @@
|
|||
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 */; };
|
||||
0E3CD47F280DA14B007075C0 /* OrganizerView+AddMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3CD47E280DA14B007075C0 /* OrganizerView+AddMenu.swift */; };
|
||||
0E3CD483280DAE92007075C0 /* ProfileView+Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3CD482280DAE92007075C0 /* ProfileView+Toolbar.swift */; };
|
||||
0E3CD483280DAE92007075C0 /* ProfileView+MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3CD482280DAE92007075C0 /* ProfileView+MainMenu.swift */; };
|
||||
0E44689627B051C300A14CE4 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E44689527B051C300A14CE4 /* ProfileView.swift */; };
|
||||
0E44689C27B11B5300A14CE4 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E44689B27B11B5300A14CE4 /* AboutView.swift */; };
|
||||
0E49F6BB27D7638300385834 /* EndpointAdvancedView+OpenVPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E49F6BA27D7638300385834 /* EndpointAdvancedView+OpenVPN.swift */; };
|
||||
|
@ -64,7 +64,6 @@
|
|||
0E71ACFB27C12E5300F85C4B /* VersionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E71ACFA27C12E5300F85C4B /* VersionView.swift */; };
|
||||
0E71ACFD27C1321A00F85C4B /* ActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E71ACFC27C1321A00F85C4B /* ActivityView.swift */; };
|
||||
0E7577D72816A3B200081CBE /* DestructiveButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7577D62816A3B200081CBE /* DestructiveButton.swift */; };
|
||||
0E7577DD2816C3AD00081CBE /* ProfileView+Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7577DC2816C3AD00081CBE /* ProfileView+Buttons.swift */; };
|
||||
0E7577DF2817E22C00081CBE /* VPNToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7577DE2817E22C00081CBE /* VPNToggle.swift */; };
|
||||
0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */; };
|
||||
0E92D7C627F103300033CB7B /* ProfileView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */; };
|
||||
|
@ -220,7 +219,7 @@
|
|||
0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+VPN.swift"; sourceTree = "<group>"; };
|
||||
0E3B7FD927E51A0200C66F13 /* ProfileView+Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Provider.swift"; sourceTree = "<group>"; };
|
||||
0E3CD47E280DA14B007075C0 /* OrganizerView+AddMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OrganizerView+AddMenu.swift"; sourceTree = "<group>"; };
|
||||
0E3CD482280DAE92007075C0 /* ProfileView+Toolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Toolbar.swift"; sourceTree = "<group>"; };
|
||||
0E3CD482280DAE92007075C0 /* ProfileView+MainMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+MainMenu.swift"; sourceTree = "<group>"; };
|
||||
0E44689527B051C300A14CE4 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
|
||||
0E44689B27B11B5300A14CE4 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
|
||||
0E49F6BA27D7638300385834 /* EndpointAdvancedView+OpenVPN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EndpointAdvancedView+OpenVPN.swift"; sourceTree = "<group>"; };
|
||||
|
@ -251,7 +250,6 @@
|
|||
0E71ACFA27C12E5300F85C4B /* VersionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionView.swift; sourceTree = "<group>"; };
|
||||
0E71ACFC27C1321A00F85C4B /* ActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityView.swift; sourceTree = "<group>"; };
|
||||
0E7577D62816A3B200081CBE /* DestructiveButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestructiveButton.swift; sourceTree = "<group>"; };
|
||||
0E7577DC2816C3AD00081CBE /* ProfileView+Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Buttons.swift"; sourceTree = "<group>"; };
|
||||
0E7577DE2817E22C00081CBE /* VPNToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNToggle.swift; sourceTree = "<group>"; };
|
||||
0E90DFE527BACC1500EF5078 /* AddHostViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddHostViewModel.swift; sourceTree = "<group>"; };
|
||||
0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileView+Configuration.swift"; sourceTree = "<group>"; };
|
||||
|
@ -454,13 +452,12 @@
|
|||
0ED30DD127EA1F650057D8A3 /* PaywallView+Purchase.swift */,
|
||||
0ED89C2427DE45A3008B36D6 /* ProfileHeaderRow.swift */,
|
||||
0E44689527B051C300A14CE4 /* ProfileView.swift */,
|
||||
0E7577DC2816C3AD00081CBE /* ProfileView+Buttons.swift */,
|
||||
0E92D7C527F103300033CB7B /* ProfileView+Configuration.swift */,
|
||||
0E92D7F327F104B80033CB7B /* ProfileView+Diagnostics.swift */,
|
||||
0E92D7C827F1042A0033CB7B /* ProfileView+Extra.swift */,
|
||||
0E3CD482280DAE92007075C0 /* ProfileView+MainMenu.swift */,
|
||||
0E3B7FD927E51A0200C66F13 /* ProfileView+Provider.swift */,
|
||||
0EBC074B27EB673C00208AD9 /* ProfileView+Rename.swift */,
|
||||
0E3CD482280DAE92007075C0 /* ProfileView+Toolbar.swift */,
|
||||
0E3B7FD527E5173A00C66F13 /* ProfileView+VPN.swift */,
|
||||
0E71ACF027C1073800F85C4B /* ProviderLocationView.swift */,
|
||||
0E71ACEE27C106B400F85C4B /* ProviderPresetView.swift */,
|
||||
|
@ -902,7 +899,6 @@
|
|||
0E90DFE627BACC1500EF5078 /* AddHostViewModel.swift in Sources */,
|
||||
0E34AC8227F892C40042F2AB /* OnDemandView+SSID.swift in Sources */,
|
||||
0EF708322811CC8400A3A308 /* VPNStatusText.swift in Sources */,
|
||||
0E7577DD2816C3AD00081CBE /* ProfileView+Buttons.swift in Sources */,
|
||||
0E5324A627D297BB002565C3 /* InApp.swift in Sources */,
|
||||
0E3B7FCD27E47B3700C66F13 /* AddHostView+Name.swift in Sources */,
|
||||
0E7577D72816A3B200081CBE /* DestructiveButton.swift in Sources */,
|
||||
|
@ -967,7 +963,7 @@
|
|||
0E71ACF927C12E4800F85C4B /* CreditsView.swift in Sources */,
|
||||
0ED89C1527DE0A0C008B36D6 /* Shortcut.swift in Sources */,
|
||||
0E34A2B927CAA96A00C73B67 /* OpenVPN+L10n.swift in Sources */,
|
||||
0E3CD483280DAE92007075C0 /* ProfileView+Toolbar.swift in Sources */,
|
||||
0E3CD483280DAE92007075C0 /* ProfileView+MainMenu.swift in Sources */,
|
||||
0EB17EAE27D226CF00D473B5 /* LocalProduct.swift in Sources */,
|
||||
0E71ACEB27C1060D00F85C4B /* EndpointView.swift in Sources */,
|
||||
0E53249927D26B51002565C3 /* ProductManager.swift in Sources */,
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "APP_TYPE"
|
||||
value = "0"
|
||||
value = "2"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
|
|
|
@ -437,6 +437,8 @@ internal enum L10n {
|
|||
internal static let configuration = L10n.tr("Localizable", "global.strings.configuration")
|
||||
/// Default
|
||||
internal static let `default` = L10n.tr("Localizable", "global.strings.default")
|
||||
/// Delete
|
||||
internal static let delete = L10n.tr("Localizable", "global.strings.delete")
|
||||
/// Disabled
|
||||
internal static let disabled = L10n.tr("Localizable", "global.strings.disabled")
|
||||
/// Domain
|
||||
|
@ -493,6 +495,8 @@ internal enum L10n {
|
|||
internal static let servers = L10n.tr("Localizable", "global.strings.servers")
|
||||
/// Translations
|
||||
internal static let translations = L10n.tr("Localizable", "global.strings.translations")
|
||||
/// Uninstall
|
||||
internal static let uninstall = L10n.tr("Localizable", "global.strings.uninstall")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -694,8 +698,6 @@ internal enum L10n {
|
|||
internal static func message(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "organizer.alerts.remove_profile.message", String(describing: p1))
|
||||
}
|
||||
/// Remove profile
|
||||
internal static let title = L10n.tr("Localizable", "organizer.alerts.remove_profile.title")
|
||||
}
|
||||
}
|
||||
internal enum Empty {
|
||||
|
@ -815,10 +817,6 @@ internal enum L10n {
|
|||
/// Reconnect
|
||||
internal static let caption = L10n.tr("Localizable", "profile.items.reconnect.caption")
|
||||
}
|
||||
internal enum Uninstall {
|
||||
/// Remove VPN configuration
|
||||
internal static let caption = L10n.tr("Localizable", "profile.items.uninstall.caption")
|
||||
}
|
||||
internal enum UseProfile {
|
||||
/// Use this profile
|
||||
internal static let caption = L10n.tr("Localizable", "profile.items.use_profile.caption")
|
||||
|
|
|
@ -172,6 +172,10 @@ extension View {
|
|||
"xmark"
|
||||
}
|
||||
|
||||
var themeUninstallImage: String {
|
||||
"arrow.uturn.down"
|
||||
}
|
||||
|
||||
var themeDeleteImage: String {
|
||||
"trash.fill"
|
||||
}
|
||||
|
@ -281,10 +285,6 @@ extension View {
|
|||
foregroundColor(themeLightTextColor)
|
||||
}
|
||||
|
||||
func themeDestructiveButtonStyle() -> some View {
|
||||
foregroundColor(themeErrorColor)
|
||||
}
|
||||
|
||||
@available(iOS 15, *)
|
||||
func themePrimaryTintStyle() -> some View {
|
||||
tint(themePrimaryBackgroundColor)
|
||||
|
|
|
@ -109,11 +109,7 @@ extension OrganizerView {
|
|||
isActive: profileManager.isActiveProfile(header.id)
|
||||
)
|
||||
}.contextMenu {
|
||||
Button {
|
||||
duplicateProfile(withId: header.id)
|
||||
} label: {
|
||||
Label(L10n.Global.Strings.duplicate, systemImage: themeDuplicateImage)
|
||||
}
|
||||
ProfileView.DuplicateButton(header: header)
|
||||
}.themeTextButtonStyle()
|
||||
}
|
||||
|
||||
|
@ -194,10 +190,6 @@ extension OrganizerView.ProfilesList {
|
|||
profileManager.removeProfiles(withIds: toDelete)
|
||||
}
|
||||
|
||||
private func duplicateProfile(withId id: UUID) {
|
||||
profileManager.duplicateProfile(withId: id)
|
||||
}
|
||||
|
||||
private func performMigrationsIfNeeded() {
|
||||
Task {
|
||||
await appManager.doMigrations(profileManager)
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
//
|
||||
// ProfileView+Buttons.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 4/25/22.
|
||||
// Copyright (c) 2022 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import PassepartoutCore
|
||||
|
||||
extension ProfileView {
|
||||
struct RemoveProfileButton: View {
|
||||
@ObservedObject private var profileManager: ProfileManager
|
||||
|
||||
private let header: Profile.Header
|
||||
|
||||
@State private var isConfirming = false
|
||||
|
||||
private let title = L10n.Organizer.Alerts.RemoveProfile.title
|
||||
|
||||
init(header: Profile.Header) {
|
||||
profileManager = .shared
|
||||
self.header = header
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
DestructiveButton {
|
||||
isConfirming = true
|
||||
} label: {
|
||||
Label(title, systemImage: themeDeleteImage)
|
||||
}.actionSheet(isPresented: $isConfirming) {
|
||||
ActionSheet(
|
||||
title: Text(L10n.Organizer.Alerts.RemoveProfile.message(header.name)),
|
||||
message: nil,
|
||||
buttons: [
|
||||
.destructive(Text(title), action: removeProfile),
|
||||
.cancel(Text(L10n.Global.Strings.cancel))
|
||||
]
|
||||
)
|
||||
}.themeDestructiveButtonStyle()
|
||||
}
|
||||
|
||||
private func removeProfile() {
|
||||
profileManager.removeProfiles(withIds: [header.id])
|
||||
}
|
||||
}
|
||||
|
||||
struct UninstallVPNButton: View {
|
||||
@ObservedObject private var vpnManager: VPNManager
|
||||
|
||||
@State private var isConfirming = false
|
||||
|
||||
init() {
|
||||
vpnManager = .shared
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
DestructiveButton {
|
||||
isConfirming = true
|
||||
} label: {
|
||||
Label(L10n.Profile.Items.Uninstall.caption, systemImage: themeDeleteImage)
|
||||
}.actionSheet(isPresented: $isConfirming) {
|
||||
ActionSheet(
|
||||
title: Text(L10n.Profile.Alerts.UninstallVpn.message),
|
||||
message: nil,
|
||||
buttons: [
|
||||
.destructive(Text(L10n.Profile.Items.Uninstall.caption), action: uninstallVPN),
|
||||
.cancel(Text(L10n.Global.Strings.cancel))
|
||||
]
|
||||
)
|
||||
}.themeDestructiveButtonStyle()
|
||||
}
|
||||
|
||||
private func uninstallVPN() {
|
||||
Task {
|
||||
await vpnManager.uninstall()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
//
|
||||
// ProfileView+MainMenu.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 2/6/22.
|
||||
// Copyright (c) 2022 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import PassepartoutCore
|
||||
|
||||
extension ProfileView {
|
||||
struct MainMenu: View {
|
||||
enum ActionSheetType: Int, Identifiable {
|
||||
case uninstallVPN
|
||||
|
||||
case deleteProfile
|
||||
|
||||
var id: Int {
|
||||
rawValue
|
||||
}
|
||||
}
|
||||
|
||||
@ObservedObject private var profileManager: ProfileManager
|
||||
|
||||
@ObservedObject private var vpnManager: VPNManager
|
||||
|
||||
@ObservedObject private var currentProfile: ObservableProfile
|
||||
|
||||
private var header: Profile.Header {
|
||||
currentProfile.value.header
|
||||
}
|
||||
|
||||
@Binding private var modalType: ModalType?
|
||||
|
||||
@State private var actionSheetType: ActionSheetType?
|
||||
|
||||
private let uninstallVPNTitle = L10n.Global.Strings.uninstall
|
||||
|
||||
private let deleteProfileTitle = L10n.Global.Strings.delete
|
||||
|
||||
private let cancelTitle = L10n.Global.Strings.cancel
|
||||
|
||||
init(currentProfile: ObservableProfile, modalType: Binding<ModalType?>) {
|
||||
profileManager = .shared
|
||||
vpnManager = .shared
|
||||
self.currentProfile = currentProfile
|
||||
_modalType = modalType
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Menu {
|
||||
RenameButton(
|
||||
modalType: $modalType
|
||||
)
|
||||
// should contextually set duplicate as current profile
|
||||
// DuplicateButton(
|
||||
// header: currentProfile.value.header
|
||||
// )
|
||||
ShortcutsButton(
|
||||
modalType: $modalType
|
||||
)
|
||||
uninstallVPNButton
|
||||
Divider()
|
||||
deleteProfileButton
|
||||
} label: {
|
||||
themeSettingsMenuImage.asSystemImage
|
||||
}.actionSheet(item: $actionSheetType) {
|
||||
switch $0 {
|
||||
case .uninstallVPN:
|
||||
return ActionSheet(
|
||||
title: Text(L10n.Profile.Alerts.UninstallVpn.message),
|
||||
message: nil,
|
||||
buttons: [
|
||||
.destructive(Text(uninstallVPNTitle), action: uninstallVPN),
|
||||
.cancel(Text(cancelTitle))
|
||||
]
|
||||
)
|
||||
|
||||
case .deleteProfile:
|
||||
return ActionSheet(
|
||||
title: Text(L10n.Organizer.Alerts.RemoveProfile.message(header.name)),
|
||||
message: nil,
|
||||
buttons: [
|
||||
.destructive(Text(deleteProfileTitle), action: removeProfile),
|
||||
.cancel(Text(cancelTitle))
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var uninstallVPNButton: some View {
|
||||
Button {
|
||||
actionSheetType = .uninstallVPN
|
||||
} label: {
|
||||
Label(uninstallVPNTitle, systemImage: themeUninstallImage)
|
||||
}
|
||||
}
|
||||
|
||||
private var deleteProfileButton: some View {
|
||||
DestructiveButton {
|
||||
actionSheetType = .deleteProfile
|
||||
} label: {
|
||||
Label(deleteProfileTitle, systemImage: themeDeleteImage)
|
||||
}
|
||||
}
|
||||
|
||||
private func uninstallVPN() {
|
||||
Task {
|
||||
await vpnManager.uninstall()
|
||||
}
|
||||
}
|
||||
|
||||
private func removeProfile() {
|
||||
profileManager.removeProfiles(withIds: [header.id])
|
||||
}
|
||||
}
|
||||
|
||||
struct RenameButton: View {
|
||||
@Binding private var modalType: ModalType?
|
||||
|
||||
init(modalType: Binding<ModalType?>) {
|
||||
_modalType = modalType
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
modalType = .rename
|
||||
} label: {
|
||||
Label(L10n.Global.Strings.rename, systemImage: themeRenameProfileImage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ShortcutsButton: View {
|
||||
@ObservedObject private var productManager: ProductManager
|
||||
|
||||
@Binding private var modalType: ModalType?
|
||||
|
||||
init(modalType: Binding<ModalType?>) {
|
||||
productManager = .shared
|
||||
_modalType = modalType
|
||||
}
|
||||
|
||||
private var isEligibleForSiri: Bool {
|
||||
productManager.isEligible(forFeature: .siriShortcuts)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
presentShortcutsOrPaywall()
|
||||
} label: {
|
||||
Label(Unlocalized.Other.siri, systemImage: themeShortcutsImage)
|
||||
}
|
||||
}
|
||||
|
||||
private func presentShortcutsOrPaywall() {
|
||||
|
||||
// eligibility: enter Siri shortcuts or present paywall
|
||||
if isEligibleForSiri {
|
||||
modalType = .shortcuts
|
||||
} else {
|
||||
modalType = .paywallShortcuts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DuplicateButton: View {
|
||||
@ObservedObject private var profileManager: ProfileManager
|
||||
|
||||
let header: Profile.Header
|
||||
|
||||
init(header: Profile.Header) {
|
||||
profileManager = .shared
|
||||
self.header = header
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
duplicateProfile(withId: header.id)
|
||||
} label: {
|
||||
Label(L10n.Global.Strings.duplicate, systemImage: themeDuplicateImage)
|
||||
}
|
||||
}
|
||||
|
||||
private func duplicateProfile(withId id: UUID) {
|
||||
profileManager.duplicateProfile(withId: id)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
//
|
||||
// ProfileView+Toolbar.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 2/6/22.
|
||||
// Copyright (c) 2022 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import PassepartoutCore
|
||||
|
||||
extension ProfileView {
|
||||
struct ShortcutsItem: View {
|
||||
@ObservedObject private var productManager: ProductManager
|
||||
|
||||
@Binding private var modalType: ModalType?
|
||||
|
||||
init(modalType: Binding<ModalType?>) {
|
||||
productManager = .shared
|
||||
_modalType = modalType
|
||||
}
|
||||
|
||||
private var isEligibleForSiri: Bool {
|
||||
productManager.isEligible(forFeature: .siriShortcuts)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
presentShortcutsOrPaywall()
|
||||
} label: {
|
||||
themeShortcutsImage.asSystemImage
|
||||
}
|
||||
}
|
||||
|
||||
private func presentShortcutsOrPaywall() {
|
||||
|
||||
// eligibility: enter Siri shortcuts or present paywall
|
||||
if isEligibleForSiri {
|
||||
modalType = .shortcuts
|
||||
} else {
|
||||
modalType = .paywallShortcuts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RenameItem: View {
|
||||
@ObservedObject private var currentProfile: ObservableProfile
|
||||
|
||||
@Binding private var modalType: ModalType?
|
||||
|
||||
init(currentProfile: ObservableProfile, modalType: Binding<ModalType?>) {
|
||||
self.currentProfile = currentProfile
|
||||
_modalType = modalType
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
modalType = .rename
|
||||
} label: {
|
||||
themeRenameProfileImage.asSystemImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -70,16 +70,10 @@ struct ProfileView: View {
|
|||
WelcomeView()
|
||||
}
|
||||
}.toolbar {
|
||||
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
||||
ShortcutsItem(
|
||||
modalType: $modalType
|
||||
).disabled(!isExisting)
|
||||
|
||||
RenameItem(
|
||||
currentProfile: profileManager.currentProfile,
|
||||
modalType: $modalType
|
||||
).disabled(!isExisting)
|
||||
}
|
||||
MainMenu(
|
||||
currentProfile: profileManager.currentProfile,
|
||||
modalType: $modalType
|
||||
).disabled(!isExisting)
|
||||
}.sheet(item: $modalType, content: presentedModal)
|
||||
.navigationTitle(title)
|
||||
.themeSecondaryView()
|
||||
|
@ -103,10 +97,6 @@ struct ProfileView: View {
|
|||
)
|
||||
ExtraSection(currentProfile: profileManager.currentProfile)
|
||||
DiagnosticsSection(currentProfile: profileManager.currentProfile)
|
||||
Section {
|
||||
UninstallVPNButton()
|
||||
RemoveProfileButton(header: profileManager.currentProfile.value.header)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
"global.strings.rename" = "Rename";
|
||||
"global.strings.duplicate" = "Duplicate";
|
||||
"global.strings.add" = "Add";
|
||||
"global.strings.delete" = "Delete";
|
||||
"global.strings.uninstall" = "Uninstall";
|
||||
"global.strings.default" = "Default";
|
||||
"global.strings.name" = "Name";
|
||||
"global.strings.profiles" = "Profiles";
|
||||
|
@ -123,7 +125,6 @@
|
|||
"organizer.alerts.reddit.buttons.remind" = "Remind me later";
|
||||
"organizer.alerts.reddit.buttons.never" = "Don't ask again";
|
||||
|
||||
"organizer.alerts.remove_profile.title" = "Remove profile";
|
||||
"organizer.alerts.remove_profile.message" = "Are you sure you want to delete profile %@?";
|
||||
|
||||
/* MARK: AddProfileView */
|
||||
|
@ -164,7 +165,6 @@
|
|||
"profile.items.vpn_survives_sleep.caption" = "Keep alive on sleep";
|
||||
"profile.items.vpn_resolves_hostname.caption" = "Resolve provider hostname";
|
||||
"profile.items.reconnect.caption" = "Reconnect";
|
||||
"profile.items.uninstall.caption" = "Remove VPN configuration";
|
||||
|
||||
"profile.alerts.rename.title" = "Rename profile";
|
||||
"profile.alerts.reconnect_vpn.message" = "Do you want to reconnect to the VPN?";
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 225 KiB After Width: | Height: | Size: 222 KiB |
Loading…
Reference in New Issue