krz/rune

an ios client for njalla

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

v1.0.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    @State private var localErrorMessage: String?
 14
 15    init(domainName: String, record: DNSRecord, viewModel: DomainViewModel, client: NjallaClient) {
 16        self.domainName = domainName
 17        self.record = record
 18        self.viewModel = viewModel
 19        self.client = client
 20        _draft = State(initialValue: DNSRecordDraft(record: record))
 21    }
 22
 23    var body: some View {
 24        Form {
 25            DNSRecordFormSections(draft: $draft)
 26
 27            Section {
 28                Button("Save") {
 29                    Task {
 30                        await save()
 31                    }
 32                }
 33                .disabled(viewModel.isSaving || !draft.canSubmit)
 34            }
 35
 36            Section {
 37                Button("Delete Record", role: .destructive) {
 38                    showingDeleteConfirmation = true
 39                }
 40                .foregroundStyle(.red)
 41            }
 42        }
 43        .navigationTitle(record.name)
 44        .navigationBarTitleDisplayMode(.inline)
 45        .onChange(of: draft.type) { oldValue, newValue in
 46            guard oldValue != newValue else { return }
 47            draft.resetTypeSpecificFields()
 48        }
 49        .confirmationDialog(
 50            "Delete \(record.type) record \(record.name)?",
 51            isPresented: $showingDeleteConfirmation,
 52            titleVisibility: .visible
 53        ) {
 54            Button("Delete Record", role: .destructive) {
 55                Task {
 56                    await deleteRecord()
 57                }
 58            }
 59        }
 60        .alert("API Error", isPresented: localErrorBinding) {
 61            Button("OK", role: .cancel) {}
 62        } message: {
 63            Text(localErrorMessage ?? "")
 64        }
 65    }
 66
 67    private func save() async {
 68        do {
 69            try await viewModel.editRecord(for: domainName, recordID: record.id, draft: draft, client: client)
 70            dismiss()
 71        } catch is CancellationError {
 72            return
 73        } catch {
 74            if (error as? URLError)?.code == .cancelled {
 75                return
 76            }
 77            localErrorMessage = error.localizedDescription
 78        }
 79    }
 80
 81    private func deleteRecord() async {
 82        do {
 83            try await viewModel.removeRecord(record, client: client)
 84            dismiss()
 85        } catch is CancellationError {
 86            return
 87        } catch {
 88            if (error as? URLError)?.code == .cancelled {
 89                return
 90            }
 91            localErrorMessage = error.localizedDescription
 92        }
 93    }
 94
 95    private var localErrorBinding: Binding<Bool> {
 96        Binding(
 97            get: { localErrorMessage != nil },
 98            set: { newValue in
 99                if !newValue {
100                    localErrorMessage = nil
101                }
102            }
103        )
104    }
105}