RemminaMac 0.1.0: SSH/RDP-Client für macOS (SwiftUI, Remmina-Layout, Profile, SSH-Keys, Docs, Release-Skripte)

This commit is contained in:
x3
2026-09-21 22:43:57 +02:00
commit cd834dce98
21 changed files with 1252 additions and 0 deletions
@@ -0,0 +1,79 @@
import SwiftUI
struct ProfileEditorView: View {
@Environment(\.dismiss) var dismiss
@EnvironmentObject var store: ProfileStore
@State var profile: ConnectionProfile
var onSave: (ConnectionProfile) -> Void
@State private var password: String = ""
@State private var savePassword: Bool = false
init(profile: ConnectionProfile, onSave: @escaping (ConnectionProfile) -> Void) {
_profile = State(initialValue: profile)
self.onSave = onSave
}
var body: some View {
VStack(spacing: 0) {
Text(profile.id.uuidString.prefix(8) == ConnectionProfile().id.uuidString.prefix(8) ? "Profil bearbeiten" : "Profil").font(.headline).padding()
Form {
Section("Allgemein") {
TextField("Name", text: $profile.name)
TextField("Gruppe", text: $profile.group)
Picker("Protokoll", selection: $profile.proto) {
ForEach(ProtocolType.allCases) { p in Text(p.rawValue).tag(p) }
}
.onChange(of: profile.proto) { _, new in
if profile.port == 0 { profile.port = new.defaultPort }
}
Picker("Farb-Tag", selection: $profile.colorTag) {
Text("Blau").tag("blue"); Text("Rot").tag("red")
Text("Grün").tag("green"); Text("Orange").tag("orange")
Text("Lila").tag("purple")
}
}
Section("Verbindung") {
TextField("Host", text: $profile.host)
TextField("Port", value: $profile.port, format: .number)
TextField("Benutzername", text: $profile.username)
TextField("Auflösung (RDP, z. B. 1920x1080 oder Automatisch)", text: $profile.resolution)
TextField("Extra-Argumente", text: $profile.extraArgs)
}
Section("Authentifizierung") {
Picker("SSH-Key", selection: $profile.sshKeyID) {
Text("Kein Key").tag(UUID?.none)
ForEach(store.sshKeys) { k in Text(k.name).tag(UUID?.some(k.id)) }
}
SecureField("Passwort (optional, Keychain)", text: $password)
Toggle("Passwort in Keychain speichern", isOn: $savePassword)
}
}
.formStyle(.grouped)
HStack {
Button("Abbrechen", role: .cancel) { dismiss() }
Spacer()
Button("Speichern") {
var toSave = profile
if toSave.port == 0 { toSave.port = toSave.proto.defaultPort }
if toSave.passwordAccount == nil { toSave.passwordAccount = "profile-\(toSave.id.uuidString)" }
if savePassword, !password.isEmpty, let acct = toSave.passwordAccount {
_ = KeychainHelper.save(password, account: acct)
}
onSave(toSave)
dismiss()
}
.keyboardShortcut(.defaultAction)
.disabled(profile.host.isEmpty || profile.name.isEmpty)
}
.padding()
}
.frame(width: 520, height: 620)
.onAppear {
if let acct = profile.passwordAccount {
password = KeychainHelper.load(account: acct) ?? ""
savePassword = !password.isEmpty
}
}
}
}