krz/rune

an ios client for njalla

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

main: Rune/Views/Domains/ForwardAddView.swift · raw

  1import SwiftUI
  2
  3struct ForwardAddView: 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 from = ""
 11    @State private var to = ""
 12
 13    var body: some View {
 14        Form {
 15            Section {
 16                TextField("From", text: $from)
 17                    .textInputAutocapitalization(.never)
 18                    .autocorrectionDisabled()
 19                TextField("To", text: $to)
 20                    .textInputAutocapitalization(.never)
 21                    .keyboardType(.emailAddress)
 22                    .autocorrectionDisabled()
 23            } header: {
 24                Text("Forward")
 25            } footer: {
 26                Text("Creates \(trimmedFrom)@\(domainName) -> \(trimmedTo)")
 27            }
 28
 29            Section {
 30                Button("Save") {
 31                    Task {
 32                        await save()
 33                    }
 34                }
 35                .disabled(viewModel.isSaving || !canSubmit)
 36            }
 37        }
 38        .navigationTitle("Add Forward")
 39        .navigationBarTitleDisplayMode(.inline)
 40        .overlay {
 41            if viewModel.isSaving {
 42                ProgressView()
 43                    .controlSize(.large)
 44            }
 45        }
 46        .toolbar {
 47            ToolbarItem(placement: .cancellationAction) {
 48                Button("Cancel", role: .cancel) {
 49                    dismiss()
 50                }
 51                .disabled(viewModel.isSaving)
 52            }
 53        }
 54        .interactiveDismissDisabled(viewModel.isSaving)
 55        .alert("Request Failed", isPresented: mutationErrorBinding) {
 56            Button("OK", role: .cancel) {}
 57        } message: {
 58            Text(viewModel.mutationErrorMessage ?? "")
 59        }
 60    }
 61
 62    private var trimmedFrom: String {
 63        from.trimmingCharacters(in: .whitespacesAndNewlines)
 64    }
 65
 66    private var trimmedTo: String {
 67        to.trimmingCharacters(in: .whitespacesAndNewlines)
 68    }
 69
 70    private var canSubmit: Bool {
 71        !trimmedFrom.isEmpty && !trimmedTo.isEmpty
 72    }
 73
 74    private func save() async {
 75        guard !viewModel.isSaving, canSubmit else {
 76            return
 77        }
 78
 79        let forward = EmailForward(domain: domainName, from: trimmedFrom, to: trimmedTo)
 80
 81        debugLog("Creating forward \(forward.from)@\(forward.domain) -> \(forward.to)")
 82        do {
 83            try await viewModel.addForward(forward, client: client)
 84            debugLog("Created forward \(forward.from)@\(forward.domain) -> \(forward.to)")
 85            dismiss()
 86        } catch is CancellationError {
 87            debugLog("Create cancelled for \(forward.from)@\(forward.domain) -> \(forward.to)")
 88            return
 89        } catch {
 90            debugLog("Create failed for \(forward.from)@\(forward.domain) -> \(forward.to): \(error.localizedDescription)")
 91            return
 92        }
 93    }
 94
 95    private var mutationErrorBinding: Binding<Bool> {
 96        Binding(
 97            get: { viewModel.mutationErrorMessage != nil },
 98            set: { newValue in
 99                if !newValue {
100                    viewModel.dismissMutationError()
101                }
102            }
103        )
104    }
105
106    private func debugLog(_ message: String) {
107        #if DEBUG
108        debugPrint("[ForwardAddView]", message)
109        #endif
110    }
111}