krz/rune

an ios client for njalla

clone: git clone https://gitbay.org/krz/rune.git

v1.2.0: Rune/Views/Domains/RecordEditView.swift · raw

  1import SwiftUI
  2
  3struct RecordEditView: View {
  4    let domainName: String
  5    let record: DNSRecord
  6    @ObservedObject var viewModel: DomainViewModel
  7    let client: NjallaClient
  8
  9    @Environment(\.dismiss) private var dismiss
 10
 11    @State private var draft: DNSRecordDraft
 12    @State private var showingDeleteConfirmation = false
 13
 14    init(domainName: String, record: DNSRecord, viewModel: DomainViewModel, client: NjallaClient) {
 15        self.domainName = domainName
 16        self.record = record
 17        self.viewModel = viewModel
 18        self.client = client
 19        _draft = State(initialValue: DNSRecordDraft(record: record))
 20    }
 21
 22    var body: some View {
 23        Form {
 24            DNSRecordFormSections(draft: $draft)
 25
 26            Section {
 27                Button("Save") {
 28                    Task {
 29                        await save()
 30                    }
 31                }
 32                .disabled(viewModel.isSaving || !draft.canSubmit)
 33            }
 34
 35            Section {
 36                Button("Delete Record", role: .destructive) {
 37                    guard !viewModel.isSaving else { return }
 38                    showingDeleteConfirmation = true
 39                }
 40                .foregroundStyle(.red)
 41                .disabled(viewModel.isSaving)
 42            }
 43        }
 44        .navigationTitle(record.name)
 45        .navigationBarTitleDisplayMode(.inline)
 46        .overlay {
 47            if viewModel.isSaving {
 48                ProgressView()
 49                    .controlSize(.large)
 50            }
 51        }
 52        .interactiveDismissDisabled(viewModel.isSaving)
 53        .onChange(of: draft.type) { oldValue, newValue in
 54            guard oldValue != newValue else { return }
 55            draft.resetTypeSpecificFields()
 56        }
 57        .alert(deleteAlertTitle, isPresented: $showingDeleteConfirmation) {
 58            Button("Delete Record", role: .destructive) {
 59                Task {
 60                    await deleteRecord()
 61                }
 62            }
 63            Button("Cancel", role: .cancel) {}
 64        } message: {
 65            Text("This action cannot be undone.")
 66        }
 67        .alert("Request Failed", isPresented: mutationErrorBinding) {
 68            Button("OK", role: .cancel) {}
 69        } message: {
 70            Text(viewModel.mutationErrorMessage ?? "")
 71        }
 72    }
 73
 74    private func save() async {
 75        guard !viewModel.isSaving else {
 76            return
 77        }
 78
 79        do {
 80            try await viewModel.editRecord(for: domainName, recordID: record.id, draft: draft, client: client)
 81            dismiss()
 82        } catch is CancellationError {
 83            return
 84        } catch {
 85            return
 86        }
 87    }
 88
 89    private func deleteRecord() async {
 90        guard !viewModel.isSaving else {
 91            return
 92        }
 93
 94        do {
 95            try await viewModel.removeRecord(record, client: client)
 96            dismiss()
 97        } catch is CancellationError {
 98            return
 99        } catch {
100            return
101        }
102    }
103
104    private var mutationErrorBinding: Binding<Bool> {
105        Binding(
106            get: { viewModel.mutationErrorMessage != nil },
107            set: { newValue in
108                if !newValue {
109                    viewModel.dismissMutationError()
110                }
111            }
112        )
113    }
114
115    private var deleteAlertTitle: String {
116        "Delete \(record.type) record \(record.name)?"
117    }
118}