krz/rune

an ios client for njalla

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

v1.0.0: Rune/Views/Domains/RecordAddView.swift · raw

  1import SwiftUI
  2
  3struct RecordAddView: View {
  4    let domainName: String
  5    @ObservedObject var viewModel: DomainViewModel
  6    let client: NjallaClient
  7
  8    @Environment(\.dismiss) private var dismiss
  9
 10    @State private var draft = DNSRecordDraft()
 11    @State private var localErrorMessage: String?
 12    var body: some View {
 13        Form {
 14            DNSRecordFormSections(draft: $draft)
 15
 16            Section {
 17                Button("Save") {
 18                    Task {
 19                        await save()
 20                    }
 21                }
 22                .disabled(viewModel.isSaving || !draft.canSubmit)
 23            }
 24        }
 25        .navigationTitle("Add Record")
 26        .navigationBarTitleDisplayMode(.inline)
 27        .toolbar {
 28            ToolbarItem(placement: .cancellationAction) {
 29                Button("Cancel", role: .cancel) {
 30                    dismiss()
 31                }
 32            }
 33        }
 34        .onChange(of: draft.type) { oldValue, newValue in
 35            guard oldValue != newValue else { return }
 36            draft.resetTypeSpecificFields()
 37        }
 38        .alert("API Error", isPresented: localErrorBinding) {
 39            Button("OK", role: .cancel) {}
 40        } message: {
 41            Text(localErrorMessage ?? "")
 42        }
 43    }
 44
 45    private func save() async {
 46        do {
 47            try await viewModel.addRecord(for: domainName, draft: draft, client: client)
 48            dismiss()
 49        } catch is CancellationError {
 50            return
 51        } catch {
 52            if (error as? URLError)?.code == .cancelled {
 53                return
 54            }
 55            localErrorMessage = error.localizedDescription
 56        }
 57    }
 58
 59    private var localErrorBinding: Binding<Bool> {
 60        Binding(
 61            get: { localErrorMessage != nil },
 62            set: { newValue in
 63                if !newValue {
 64                    localErrorMessage = nil
 65                }
 66            }
 67        )
 68    }
 69}
 70
 71struct DNSRecordFormSections: View {
 72    @Binding var draft: DNSRecordDraft
 73
 74    var body: some View {
 75        Section("Record") {
 76            Picker("Type", selection: $draft.type) {
 77                ForEach(DNSRecordType.allCases) { type in
 78                    Text(type.rawValue).tag(type)
 79                }
 80            }
 81
 82            TextField("Name", text: $draft.name)
 83                .textInputAutocapitalization(.never)
 84                .autocorrectionDisabled()
 85        }
 86
 87        if draft.type.usesContent {
 88            Section("Content") {
 89                TextField("Content", text: $draft.content, axis: .vertical)
 90                    .textInputAutocapitalization(.never)
 91                    .autocorrectionDisabled()
 92            }
 93        }
 94
 95        if draft.type.usesTTL {
 96            Section("TTL") {
 97                TextField("TTL", text: $draft.ttl)
 98                    .keyboardType(.numberPad)
 99            }
100        }
101
102        if draft.type.usesPriority {
103            Section("Priority") {
104                TextField("Priority", text: $draft.prio)
105                    .keyboardType(.numberPad)
106            }
107        }
108
109        if draft.type.usesWeight {
110            Section("Weight") {
111                TextField("Weight", text: $draft.weight)
112                    .keyboardType(.numberPad)
113            }
114        }
115
116        if draft.type.usesPort {
117            Section("Port") {
118                TextField("Port", text: $draft.port)
119                    .keyboardType(.numberPad)
120            }
121        }
122
123        if draft.type.usesTarget {
124            Section("Target") {
125                TextField("Target", text: $draft.target)
126                    .textInputAutocapitalization(.never)
127                    .autocorrectionDisabled()
128            }
129        }
130
131        if draft.type.usesSSHFields {
132            Section {
133                TextField("SSH Algorithm", text: $draft.sshAlgorithm)
134                    .keyboardType(.numberPad)
135                TextField("SSH Type", text: $draft.sshType)
136                    .keyboardType(.numberPad)
137            } header: {
138                Text("SSHFP")
139            } footer: {
140                Text("Algorithm values: 1-5. Type values: 1-2.")
141            }
142        }
143    }
144}