mirror of
https://github.com/passepartoutvpn/passepartout-apple.git
synced 2025-01-22 08:32:11 +00:00
Edit OpenVPN remotes (#1052)
In a further subview. Remotes are not editable in providers.
This commit is contained in:
parent
a91f71345c
commit
5caf6da23f
@ -36,6 +36,8 @@ extension OpenVPNView {
|
||||
|
||||
let credentialsRoute: (any Hashable)?
|
||||
|
||||
let remotesRoute: (any Hashable)?
|
||||
|
||||
@ObservedObject
|
||||
var excludedEndpoints: ObservableList<ExtendedEndpoint>
|
||||
|
||||
@ -72,12 +74,17 @@ extension OpenVPNView {
|
||||
private extension OpenVPNView.ConfigurationView {
|
||||
var remotesSection: some View {
|
||||
configuration.remotes.map { remotes in
|
||||
ForEach(remotes, id: \.rawValue) { remote in
|
||||
SelectableRemoteButton(
|
||||
remote: remote,
|
||||
all: Set(remotes),
|
||||
excludedEndpoints: excludedEndpoints
|
||||
)
|
||||
Group {
|
||||
ForEach(remotes, id: \.rawValue) { remote in
|
||||
SelectableRemoteButton(
|
||||
remote: remote,
|
||||
all: Set(remotes),
|
||||
excludedEndpoints: excludedEndpoints
|
||||
)
|
||||
}
|
||||
if let remotesRoute {
|
||||
NavigationLink(Strings.Global.Actions.edit, value: remotesRoute)
|
||||
}
|
||||
}
|
||||
.themeSection(header: Strings.Modules.Openvpn.remotes)
|
||||
}
|
||||
@ -103,14 +110,7 @@ private struct SelectableRemoteButton: View {
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text(remote.address.rawValue)
|
||||
.font(.headline)
|
||||
|
||||
Text("\(remote.proto.socketType.rawValue):\(remote.proto.port.description)")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
EndpointCardView(endpoint: remote)
|
||||
Spacer()
|
||||
ThemeImage(.marked)
|
||||
.opaque(!excludedEndpoints.contains(remote))
|
||||
@ -363,6 +363,7 @@ private extension OpenVPNView.ConfigurationView {
|
||||
isServerPushed: false,
|
||||
configuration: .forPreviews,
|
||||
credentialsRoute: nil,
|
||||
remotesRoute: nil,
|
||||
excludedEndpoints: excludedEndpoints
|
||||
)
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
//
|
||||
// OpenVPNView+Remotes.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 1/5/25.
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension OpenVPNView {
|
||||
struct RemotesView: View {
|
||||
|
||||
@EnvironmentObject
|
||||
private var theme: Theme
|
||||
|
||||
@Binding
|
||||
var remotes: [String]
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
theme.listSection(
|
||||
Strings.Modules.Openvpn.remotes,
|
||||
addTitle: Strings.Global.Actions.add,
|
||||
originalItems: $remotes,
|
||||
itemLabel: {
|
||||
if $0 {
|
||||
Text($1.wrappedValue)
|
||||
} else {
|
||||
ThemeTextField("", text: $1, placeholder: Strings.Unlocalized.OpenVPN.Placeholders.remote)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
.labelsHidden()
|
||||
.themeForm()
|
||||
}
|
||||
}
|
||||
}
|
@ -94,6 +94,7 @@ private extension OpenVPNView {
|
||||
isServerPushed: isServerPushed,
|
||||
configuration: configuration,
|
||||
credentialsRoute: Subroute.credentials,
|
||||
remotesRoute: Subroute.editRemotes,
|
||||
excludedEndpoints: excludedEndpoints
|
||||
)
|
||||
} else {
|
||||
@ -147,6 +148,8 @@ private extension OpenVPNView {
|
||||
case providerConfiguration(OpenVPN.Configuration)
|
||||
|
||||
case credentials
|
||||
|
||||
case editRemotes
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@ -169,6 +172,7 @@ private extension OpenVPNView {
|
||||
isServerPushed: false,
|
||||
configuration: configuration.builder(),
|
||||
credentialsRoute: nil,
|
||||
remotesRoute: nil,
|
||||
excludedEndpoints: excludedEndpoints
|
||||
)
|
||||
}
|
||||
@ -186,6 +190,9 @@ private extension OpenVPNView {
|
||||
.navigationTitle(Strings.Modules.Openvpn.credentials)
|
||||
.themeForm()
|
||||
.themeAnimation(on: draft.wrappedValue.isInteractive, category: .modules)
|
||||
|
||||
case .editRemotes:
|
||||
RemotesView(remotes: editableRemotesBinding)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -197,6 +204,16 @@ private extension OpenVPNView {
|
||||
editor.excludedEndpoints(for: module.id, preferences: modulePreferences)
|
||||
}
|
||||
|
||||
var editableRemotesBinding: Binding<[String]> {
|
||||
Binding {
|
||||
draft.wrappedValue.configurationBuilder?.remotes?.map(\.rawValue) ?? []
|
||||
} set: {
|
||||
draft.wrappedValue.configurationBuilder?.remotes = $0.compactMap {
|
||||
ExtendedEndpoint(rawValue: $0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func onSelectServer(server: VPNServer, preset: VPNPreset<OpenVPN.Configuration>) {
|
||||
draft.wrappedValue.providerEntity = VPNEntity(server: server, preset: preset)
|
||||
resetExcludedEndpointsWithCurrentProviderEntity()
|
||||
|
@ -29,6 +29,10 @@ import PassepartoutKit
|
||||
extension Strings {
|
||||
public enum Unlocalized {
|
||||
public enum OpenVPN {
|
||||
public enum Placeholders {
|
||||
public static let remote = "1.1.1.1:UDP:2222"
|
||||
}
|
||||
|
||||
public enum XOR: String {
|
||||
case xormask
|
||||
|
||||
|
@ -184,6 +184,8 @@ public enum Strings {
|
||||
}
|
||||
public enum Global {
|
||||
public enum Actions {
|
||||
/// Add
|
||||
public static let add = Strings.tr("Localizable", "global.actions.add", fallback: "Add")
|
||||
/// Cancel
|
||||
public static let cancel = Strings.tr("Localizable", "global.actions.cancel", fallback: "Cancel")
|
||||
/// Connect
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Alle Anbieter";
|
||||
"features.routing" = "Benutzerdefiniertes Routing";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Hinzufügen";
|
||||
"global.actions.cancel" = "Abbrechen";
|
||||
"global.actions.connect" = "Verbinden";
|
||||
"global.actions.delete" = "Löschen";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Όλοι οι πάροχοι";
|
||||
"features.routing" = "Προσαρμοσμένη Δρομολόγηση";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Προσθήκη";
|
||||
"global.actions.cancel" = "Ακύρωση";
|
||||
"global.actions.connect" = "Σύνδεση";
|
||||
"global.actions.delete" = "Διαγραφή";
|
||||
|
@ -230,6 +230,7 @@
|
||||
|
||||
// MARK: Global (Actions)
|
||||
|
||||
"global.actions.add" = "Add";
|
||||
"global.actions.cancel" = "Cancel";
|
||||
"global.actions.connect" = "Connect";
|
||||
"global.actions.delete" = "Delete";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Todos los proveedores";
|
||||
"features.routing" = "Enrutamiento Personalizado";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Agregar";
|
||||
"global.actions.cancel" = "Cancelar";
|
||||
"global.actions.connect" = "Conectar";
|
||||
"global.actions.delete" = "Eliminar";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Tous les fournisseurs";
|
||||
"features.routing" = "Routage Personnalisé";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Ajouter";
|
||||
"global.actions.cancel" = "Annuler";
|
||||
"global.actions.connect" = "Connecter";
|
||||
"global.actions.delete" = "Supprimer";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Tutti i provider";
|
||||
"features.routing" = "Routing Personalizzato";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Aggiungi";
|
||||
"global.actions.cancel" = "Annulla";
|
||||
"global.actions.connect" = "Connetti";
|
||||
"global.actions.delete" = "Elimina";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Alle providers";
|
||||
"features.routing" = "Aangepaste routering";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Toevoegen";
|
||||
"global.actions.cancel" = "Annuleren";
|
||||
"global.actions.connect" = "Verbinden";
|
||||
"global.actions.delete" = "Verwijderen";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Wszyscy dostawcy";
|
||||
"features.routing" = "Niestandardowe trasowanie";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Dodaj";
|
||||
"global.actions.cancel" = "Anuluj";
|
||||
"global.actions.connect" = "Połącz";
|
||||
"global.actions.delete" = "Usuń";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Todos os provedores";
|
||||
"features.routing" = "Roteamento Personalizado";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Adicionar";
|
||||
"global.actions.cancel" = "Cancelar";
|
||||
"global.actions.connect" = "Conectar";
|
||||
"global.actions.delete" = "Excluir";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Все поставщики";
|
||||
"features.routing" = "Пользовательская маршрутизация";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Добавить";
|
||||
"global.actions.cancel" = "Отмена";
|
||||
"global.actions.connect" = "Подключить";
|
||||
"global.actions.delete" = "Удалить";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Alla leverantörer";
|
||||
"features.routing" = "Anpassad Ruttning";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Lägg till";
|
||||
"global.actions.cancel" = "Avbryt";
|
||||
"global.actions.connect" = "Anslut";
|
||||
"global.actions.delete" = "Ta bort";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "Усі постачальники";
|
||||
"features.routing" = "Індивідуальна маршрутизація";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "Додати";
|
||||
"global.actions.cancel" = "Скасувати";
|
||||
"global.actions.connect" = "Підключитися";
|
||||
"global.actions.delete" = "Видалити";
|
||||
|
@ -54,6 +54,7 @@
|
||||
"features.providers" = "所有提供商";
|
||||
"features.routing" = "自定义路由";
|
||||
"features.sharing" = "%@";
|
||||
"global.actions.add" = "添加";
|
||||
"global.actions.cancel" = "取消";
|
||||
"global.actions.connect" = "连接";
|
||||
"global.actions.delete" = "删除";
|
||||
|
46
Library/Sources/UILibrary/Views/UI/EndpointCardView.swift
Normal file
46
Library/Sources/UILibrary/Views/UI/EndpointCardView.swift
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// EndpointCardView.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 1/5/25.
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import PassepartoutKit
|
||||
import SwiftUI
|
||||
|
||||
public struct EndpointCardView: View {
|
||||
private let endpoint: ExtendedEndpoint
|
||||
|
||||
public init(endpoint: ExtendedEndpoint) {
|
||||
self.endpoint = endpoint
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text(endpoint.address.rawValue)
|
||||
.font(.headline)
|
||||
|
||||
Text("\(endpoint.proto.socketType.rawValue):\(endpoint.proto.port.description)")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user