import Foundation @MainActor final class ProfileStore: ObservableObject { @Published var profiles: [ConnectionProfile] = [] @Published var sshKeys: [StoredSSHKey] = [] @Published var searchText: String = "" @Published var selectedGroup: String = "Alle" private var profilesURL: URL { let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first! .appendingPathComponent("RemminaMac", isDirectory: true) try? FileManager.default.createDirectory(at: base, withIntermediateDirectories: true) return base.appendingPathComponent("profiles.json") } private var keysURL: URL { let base = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first! .appendingPathComponent("RemminaMac", isDirectory: true) try? FileManager.default.createDirectory(at: base, withIntermediateDirectories: true) return base.appendingPathComponent("sshkeys.json") } var groups: [String] { let g = Set(profiles.map { $0.group.isEmpty ? "Allgemein" : $0.group }) return ["Alle"] + g.sorted() } var filteredProfiles: [ConnectionProfile] { profiles.filter { p in let matchGroup = selectedGroup == "Alle" || p.group == selectedGroup let matchSearch = searchText.isEmpty || p.name.localizedCaseInsensitiveContains(searchText) || p.host.localizedCaseInsensitiveContains(searchText) || p.username.localizedCaseInsensitiveContains(searchText) return matchGroup && matchSearch }.sorted { $0.name.localizedCompare($1.name) == .orderedAscending } } func load() { if let data = try? Data(contentsOf: profilesURL), let decoded = try? JSONDecoder().decode([ConnectionProfile].self, from: data) { profiles = decoded } if let data = try? Data(contentsOf: keysURL), let decoded = try? JSONDecoder().decode([StoredSSHKey].self, from: data) { sshKeys = decoded } if profiles.isEmpty { profiles = Self.sampleProfiles } } func save() { if let data = try? JSONEncoder().encode(profiles) { try? data.write(to: profilesURL) } if let data = try? JSONEncoder().encode(sshKeys) { try? data.write(to: keysURL) } } func add(_ profile: ConnectionProfile) { profiles.append(profile) save() } func update(_ profile: ConnectionProfile) { if let i = profiles.firstIndex(where: { $0.id == profile.id }) { profiles[i] = profile save() } } func delete(_ profile: ConnectionProfile) { profiles.removeAll { $0.id == profile.id } save() } func duplicate(_ profile: ConnectionProfile) { var copy = profile copy.id = UUID() copy.name += " (Kopie)" copy.passwordAccount = nil add(copy) } func key(for profile: ConnectionProfile) -> StoredSSHKey? { guard let id = profile.sshKeyID else { return nil } return sshKeys.first { $0.id == id } } static var sampleProfiles: [ConnectionProfile] { [ ConnectionProfile(name: "Webserver", proto: .ssh, host: "192.168.1.10", port: 22, username: "admin", group: "Server"), ConnectionProfile(name: "Büro-PC", proto: .rdp, host: "192.168.1.50", port: 3389, username: "user", group: "Windows"), ConnectionProfile(name: "Dateiserver", proto: .sftp, host: "nas.local", port: 22, username: "nas", group: "Server") ] } }