diff options
| author | Christian Cleberg <[email protected]> | 2026-04-13 22:37:22 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-04-13 22:37:22 -0500 |
| commit | 5dcfe0f147c7871eaf5f3a88bd9e9fded38d4633 (patch) | |
| tree | 6bcbda4f02a131d3e3b870a3904ccd42f4af2f26 /Rune/Views/Domains/GlueEditView.swift | |
| parent | fcf864a15b70e4ecb5bd789b1db3116221c34394 (diff) | |
| download | rune-1.2.0.tar.gz rune-1.2.0.tar.bz2 rune-1.2.0.zip | |
v1.2.0 domain management and wallet expansionv1.2.0
Complete v1.1-aligned domain flows with forwards and glue CRUD, improve API payload resilience, and add wallet transaction/payment views.
Harden error handling and UX states across domain screens, remove out-of-scope DNSSEC/renewal record flows for now, and keep auth/session behavior aligned with token-based usage.
Diffstat (limited to 'Rune/Views/Domains/GlueEditView.swift')
| -rw-r--r-- | Rune/Views/Domains/GlueEditView.swift | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/Rune/Views/Domains/GlueEditView.swift b/Rune/Views/Domains/GlueEditView.swift new file mode 100644 index 0000000..b56a5d7 --- /dev/null +++ b/Rune/Views/Domains/GlueEditView.swift @@ -0,0 +1,139 @@ +import SwiftUI + +struct GlueEditView: View { + let domainName: String + let existingRecord: GlueRecord? + @ObservedObject var viewModel: DomainViewModel + let client: NjallaClient + + @Environment(\.dismiss) private var dismiss + @State private var name: String + @State private var address4: String + @State private var address6: String + @State private var localErrorMessage: String? + + init(domainName: String, existingRecord: GlueRecord?, viewModel: DomainViewModel, client: NjallaClient) { + self.domainName = domainName + self.existingRecord = existingRecord + self.viewModel = viewModel + self.client = client + _name = State(initialValue: existingRecord?.name ?? "") + _address4 = State(initialValue: existingRecord?.address4 ?? "") + _address6 = State(initialValue: existingRecord?.address6 ?? "") + } + + var body: some View { + Form { + Section("Record") { + TextField("Name", text: $name) + .textInputAutocapitalization(.never) + .autocorrectionDisabled() + .disabled(existingRecord != nil) + + TextField("IPv4", text: $address4) + .textInputAutocapitalization(.never) + .autocorrectionDisabled() + + TextField("IPv6", text: $address6) + .textInputAutocapitalization(.never) + .autocorrectionDisabled() + } + + Section { + Button("Save") { + Task { + await save() + } + } + .disabled(viewModel.isSaving) + } + } + .navigationTitle(existingRecord == nil ? "Add Glue" : "Edit Glue") + .navigationBarTitleDisplayMode(.inline) + .overlay { + if viewModel.isSaving { + ProgressView() + .controlSize(.large) + } + } + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button("Cancel", role: .cancel) { + dismiss() + } + .disabled(viewModel.isSaving) + } + } + .alert("Invalid Glue Data", isPresented: localErrorBinding) { + Button("OK", role: .cancel) {} + } message: { + Text(localErrorMessage ?? "") + } + .alert("Request Failed", isPresented: mutationErrorBinding) { + Button("OK", role: .cancel) {} + } message: { + Text(viewModel.mutationErrorMessage ?? "") + } + } + + private func save() async { + let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines) + let trimmedAddress4 = address4.trimmingCharacters(in: .whitespacesAndNewlines) + let trimmedAddress6 = address6.trimmingCharacters(in: .whitespacesAndNewlines) + + guard !trimmedName.isEmpty else { + localErrorMessage = "Glue record name is required." + return + } + + guard !trimmedAddress4.isEmpty || !trimmedAddress6.isEmpty else { + localErrorMessage = "Provide at least one address (IPv4 or IPv6)." + return + } + + do { + if existingRecord == nil { + try await viewModel.addGlue( + for: domainName, + name: trimmedName, + address4: trimmedAddress4.isEmpty ? nil : trimmedAddress4, + address6: trimmedAddress6.isEmpty ? nil : trimmedAddress6, + client: client + ) + } else { + try await viewModel.editGlue( + for: domainName, + name: trimmedName, + address4: trimmedAddress4.isEmpty ? nil : trimmedAddress4, + address6: trimmedAddress6.isEmpty ? nil : trimmedAddress6, + client: client + ) + } + dismiss() + } catch { + return + } + } + + private var localErrorBinding: Binding<Bool> { + Binding( + get: { localErrorMessage != nil }, + set: { newValue in + if !newValue { + localErrorMessage = nil + } + } + ) + } + + private var mutationErrorBinding: Binding<Bool> { + Binding( + get: { viewModel.mutationErrorMessage != nil }, + set: { newValue in + if !newValue { + viewModel.dismissMutationError() + } + } + ) + } +} |
