summaryrefslogtreecommitdiff
path: root/Rune/Views/Domains/DomainEditView.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Rune/Views/Domains/DomainEditView.swift')
-rw-r--r--Rune/Views/Domains/DomainEditView.swift117
1 files changed, 99 insertions, 18 deletions
diff --git a/Rune/Views/Domains/DomainEditView.swift b/Rune/Views/Domains/DomainEditView.swift
index 3f197e3..0b3b1f8 100644
--- a/Rune/Views/Domains/DomainEditView.swift
+++ b/Rune/Views/Domains/DomainEditView.swift
@@ -8,10 +8,15 @@ struct DomainEditView: View {
@Environment(\.dismiss) private var dismiss
@State private var autorenew: Bool
+ @State private var autorenewDirty = false
@State private var mailforwarding: Bool
+ @State private var mailforwardingDirty = false
@State private var dnssec: Bool
+ @State private var dnssecDirty = false
@State private var lock: Bool
+ @State private var lockDirty = false
@State private var nameserversText: String
+ @State private var nameserversDirty = false
@State private var localErrorMessage: String?
init(domain: Domain, viewModel: DomainViewModel, client: NjallaClient) {
@@ -28,14 +33,14 @@ struct DomainEditView: View {
var body: some View {
Form {
Section("Settings") {
- Toggle("Autorenew", isOn: $autorenew)
- Toggle("Mail Forwarding", isOn: $mailforwarding)
- Toggle("DNSSEC", isOn: $dnssec)
- Toggle("Registrar Lock", isOn: $lock)
+ Toggle("Autorenew", isOn: dirtyBinding(for: $autorenew, dirty: $autorenewDirty, original: originalAutorenew))
+ Toggle("Mail Forwarding", isOn: dirtyBinding(for: $mailforwarding, dirty: $mailforwardingDirty, original: originalMailForwarding))
+ Toggle("DNSSEC", isOn: dirtyBinding(for: $dnssec, dirty: $dnssecDirty, original: originalDNSSEC))
+ Toggle("Registrar Lock", isOn: dirtyBinding(for: $lock, dirty: $lockDirty, original: originalLock))
}
Section {
- TextEditor(text: $nameserversText)
+ TextEditor(text: nameserversBinding)
.frame(minHeight: 120)
} header: {
Text("Nameservers")
@@ -49,12 +54,27 @@ struct DomainEditView: View {
await save()
}
}
- .disabled(viewModel.isSaving)
+ .disabled(viewModel.isSaving || !request.hasChanges)
}
}
.navigationTitle("Edit Domain")
.navigationBarTitleDisplayMode(.inline)
- .alert("API Error", isPresented: localErrorBinding) {
+ .overlay {
+ if viewModel.isSaving {
+ ProgressView()
+ .controlSize(.large)
+ }
+ }
+ .toolbar {
+ ToolbarItem(placement: .cancellationAction) {
+ Button("Cancel", role: .cancel) {
+ dismiss()
+ }
+ .disabled(viewModel.isSaving)
+ }
+ }
+ .interactiveDismissDisabled(viewModel.isSaving)
+ .alert("Request Failed", isPresented: localErrorBinding) {
Button("OK", role: .cancel) {}
} message: {
Text(localErrorMessage ?? "")
@@ -62,16 +82,16 @@ struct DomainEditView: View {
}
private func save() async {
- let request = DomainUpdateRequest(
- autorenew: autorenew,
- mailforwarding: mailforwarding,
- dnssec: dnssec,
- lock: lock,
- nameservers: nameserversText
- .split(whereSeparator: \.isNewline)
- .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
- .filter { !$0.isEmpty }
- )
+ guard !viewModel.isSaving else {
+ return
+ }
+
+ let request = request
+
+ guard request.hasChanges else {
+ dismiss()
+ return
+ }
do {
try await viewModel.updateDomain(named: domain.name, request: request, client: client)
@@ -82,7 +102,7 @@ struct DomainEditView: View {
if (error as? URLError)?.code == .cancelled {
return
}
- localErrorMessage = error.localizedDescription
+ localErrorMessage = error.userFacingMessage
}
}
@@ -96,4 +116,65 @@ struct DomainEditView: View {
}
)
}
+
+ private var originalAutorenew: Bool {
+ domain.autorenew ?? false
+ }
+
+ private var originalMailForwarding: Bool {
+ domain.mailforwarding ?? false
+ }
+
+ private var originalDNSSEC: Bool {
+ domain.dnssec ?? false
+ }
+
+ private var originalLock: Bool {
+ domain.lock ?? false
+ }
+
+ private var originalNameservers: [String] {
+ normalizedNameservers(from: (domain.nameservers ?? []).joined(separator: "\n"))
+ }
+
+ private var request: DomainUpdateRequest {
+ DomainUpdateRequest(
+ autorenew: autorenewDirty ? autorenew : nil,
+ mailforwarding: mailforwardingDirty ? mailforwarding : nil,
+ dnssec: dnssecDirty ? dnssec : nil,
+ lock: lockDirty ? lock : nil,
+ nameservers: nameserversDirty ? normalizedNameservers(from: nameserversText) : nil
+ )
+ }
+
+ private var nameserversBinding: Binding<String> {
+ Binding(
+ get: { nameserversText },
+ set: { newValue in
+ nameserversText = newValue
+ nameserversDirty = normalizedNameservers(from: newValue) != originalNameservers
+ }
+ )
+ }
+
+ private func dirtyBinding(
+ for value: Binding<Bool>,
+ dirty: Binding<Bool>,
+ original: Bool
+ ) -> Binding<Bool> {
+ Binding(
+ get: { value.wrappedValue },
+ set: { newValue in
+ value.wrappedValue = newValue
+ dirty.wrappedValue = newValue != original
+ }
+ )
+ }
+
+ private func normalizedNameservers(from text: String) -> [String] {
+ text
+ .split(whereSeparator: \.isNewline)
+ .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
+ .filter { !$0.isEmpty }
+ }
}