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}