Refactor project structure and API
This commit is contained in:
246
Views/ServerFormView.swift
Normal file
246
Views/ServerFormView.swift
Normal file
@@ -0,0 +1,246 @@
|
||||
//
|
||||
// EditServerView.swift
|
||||
// iKeyMon
|
||||
//
|
||||
// Created by tracer on 30.03.25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ServerFormView: View {
|
||||
|
||||
enum Mode {
|
||||
case add
|
||||
case edit(Server)
|
||||
}
|
||||
var mode: Mode
|
||||
|
||||
@Binding var servers: [Server]
|
||||
|
||||
@State private var hostname: String
|
||||
@State private var apiKey: String
|
||||
@State private var connectionOK: Bool = false
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
|
||||
init(
|
||||
mode: Mode,
|
||||
servers: Binding<[Server]>,
|
||||
dismiss: @escaping () -> Void
|
||||
) {
|
||||
self.mode = mode
|
||||
self._servers = servers
|
||||
|
||||
switch mode {
|
||||
case .add:
|
||||
self._hostname = State(initialValue: "")
|
||||
self._apiKey = State(initialValue: "")
|
||||
case .edit(let server):
|
||||
self._hostname = State(initialValue: server.hostname)
|
||||
self._apiKey = State(initialValue: KeychainHelper.loadApiKey(for: server.hostname) ?? "")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Edit Server")
|
||||
.font(.headline)
|
||||
|
||||
TextField("Hostname", text: $hostname)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
.padding(.top)
|
||||
|
||||
SecureField("API Key", text: $apiKey)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
|
||||
HStack {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
Spacer()
|
||||
Button("Test connection") {
|
||||
Task {
|
||||
await testConnection()
|
||||
}
|
||||
}
|
||||
Button("Save") {
|
||||
saveServer()
|
||||
updateServer()
|
||||
saveServers()
|
||||
dismiss()
|
||||
}
|
||||
.disabled(hostname.isEmpty || apiKey.isEmpty || !connectionOK)
|
||||
}
|
||||
.padding(.top)
|
||||
}
|
||||
.padding()
|
||||
.frame(width: 300)
|
||||
.onAppear {
|
||||
print("on appear")
|
||||
if case let .edit(server) = mode {
|
||||
print("serve \(server)")
|
||||
hostname = server.hostname
|
||||
apiKey = KeychainHelper.loadApiKey(for: server.hostname) ?? ""
|
||||
print("💡 Loaded server: \(hostname)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var modeTitle: String {
|
||||
switch mode {
|
||||
case .add:
|
||||
return "Add Server"
|
||||
case .edit(let server):
|
||||
return "Edit \(server.hostname)"
|
||||
}
|
||||
}
|
||||
|
||||
private func testConnection() async {
|
||||
let host = hostname.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let key = apiKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
let pinger = ServerAPI(hostname: host, apiKey: key)
|
||||
connectionOK = await pinger.ping()
|
||||
//
|
||||
// guard let url = URL(string: "https://\(host)/api/v2/ping") else {
|
||||
// print("❌ Invalid URL")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// var request = URLRequest(url: url)
|
||||
// request.httpMethod = "GET"
|
||||
// request.setValue(key, forHTTPHeaderField: "X-API-KEY")
|
||||
// request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
//
|
||||
// print("🔍 Headers: \(request.allHTTPHeaderFields ?? [:])")
|
||||
//
|
||||
// Task {
|
||||
// do {
|
||||
// let (data, response) = try await URLSession.shared.data(for: request)
|
||||
// if let httpResponse = response as? HTTPURLResponse {
|
||||
// print("🔄 Status: \(httpResponse.statusCode)")
|
||||
// }
|
||||
//
|
||||
// if let result = try? JSONDecoder().decode([String: String].self, from: data),
|
||||
// result["response"] == "pong" {
|
||||
// print("✅ Pong received")
|
||||
// connectionOK = true
|
||||
// } else {
|
||||
// print("⚠️ Unexpected response")
|
||||
// connectionOK = false
|
||||
// }
|
||||
// } catch {
|
||||
// print("❌ Error: \(error)")
|
||||
// connectionOK = false
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// func testKeyHelpConnection() {
|
||||
// let url = URL(string: "https://keyhelp.lab.24unix.net/api/v2/ping")!
|
||||
// var request = URLRequest(url: url)
|
||||
// request.httpMethod = "GET"
|
||||
//
|
||||
// // @State is no reliable source
|
||||
// let key = apiKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
// request.setValue(key, forHTTPHeaderField: "X-API-KEY")
|
||||
//
|
||||
// request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
//
|
||||
// print("🔍 Headers: \(request.allHTTPHeaderFields ?? [:])")
|
||||
//
|
||||
// let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
// if let error = error {
|
||||
// print("❌ Error: \(error.localizedDescription)")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if let httpResponse = response as? HTTPURLResponse {
|
||||
// print("🔄 Status Code: \(httpResponse.statusCode)")
|
||||
// }
|
||||
//
|
||||
// if let data = data,
|
||||
// let json = try? JSONSerialization.jsonObject(with: data) {
|
||||
// print("✅ Response: \(json)")
|
||||
// } else {
|
||||
// print("⚠️ No JSON response")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// task.resume()
|
||||
// }
|
||||
|
||||
private func saveServer() {
|
||||
print("in save server")
|
||||
let trimmedHost = hostname.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let trimmedKey = apiKey.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
switch mode {
|
||||
case .add:
|
||||
print("adding server")
|
||||
let newServer = Server(hostname: trimmedHost)
|
||||
servers.append(newServer)
|
||||
KeychainHelper.save(apiKey: trimmedKey, for: trimmedHost)
|
||||
saveServers()
|
||||
case .edit(let oldServer):
|
||||
if let index = servers.firstIndex(where: { $0.id == oldServer.id }) {
|
||||
let oldHostname = servers[index].hostname
|
||||
servers[index].hostname = trimmedHost
|
||||
if oldHostname != trimmedHost {
|
||||
KeychainHelper.deleteApiKey(for: oldHostname)
|
||||
}
|
||||
KeychainHelper.save(apiKey: trimmedKey, for: trimmedHost)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateServer() {
|
||||
print ("in edit server")
|
||||
guard case let .edit(server) = mode else {
|
||||
return
|
||||
}
|
||||
|
||||
if let index = servers.firstIndex(where: { $0.id == server.id }) {
|
||||
// Only replace hostname if changed
|
||||
let oldHostname = servers[index].hostname
|
||||
servers[index].hostname = hostname
|
||||
|
||||
// Update Keychain
|
||||
if oldHostname != hostname {
|
||||
KeychainHelper.deleteApiKey(for: oldHostname)
|
||||
}
|
||||
KeychainHelper.save(apiKey: apiKey, for: hostname)
|
||||
saveServers()
|
||||
}
|
||||
}
|
||||
|
||||
private func saveServers() {
|
||||
if let data = try? JSONEncoder().encode(servers) {
|
||||
UserDefaults.standard.set(data, forKey: "storedServers")
|
||||
}
|
||||
}
|
||||
|
||||
static func delete(server: Server, from servers: inout [Server]) {
|
||||
if let index = servers.firstIndex(where: { $0.id == server.id }) {
|
||||
servers.remove(at: index)
|
||||
|
||||
if let data = try? JSONEncoder().encode(servers) {
|
||||
UserDefaults.standard.set(data, forKey: "storedServers")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ServerFormView(
|
||||
mode: .edit(Server(hostname: "example.com")),
|
||||
servers: .constant([
|
||||
Server(hostname: "example.com")
|
||||
]),
|
||||
dismiss: {}
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user