ContactDraftFieldsView.swift
130 lignes · 5133 octets
import SwiftUI // Port of ui/ContactDraftFields.kt. When `phonesAsList` is set (edit screen), // phones/e-mails render as editable per-item lists instead of the Android // comma-joined single field. struct ContactDraftFieldsView: View { @Binding var card: ContactCard var phonesAsList: Bool = false /// Kotlin `scan_champ_a_verifier` — hint under low-confidence OCR fields, /// cleared as soon as the user corrects the field. private static let aVerifier = "À vérifier — lecture incertaine" var body: some View { VStack(alignment: .leading, spacing: 10) { C2VTextField( label: "Nom complet", text: optionalBinding(\.fullName, douteuxKey: "fullName"), supportingText: sousTexte("fullName") ) C2VTextField(label: "Prénom", text: optionalBinding(\.firstName)) C2VTextField(label: "Nom de famille", text: optionalBinding(\.lastName)) C2VTextField( label: "Société", text: optionalBinding(\.company, douteuxKey: "company"), supportingText: sousTexte("company") ) C2VTextField( label: "Poste", text: optionalBinding(\.jobTitle, douteuxKey: "jobTitle"), supportingText: sousTexte("jobTitle") ) if phonesAsList { EditableStringList(label: "Téléphone(s)", items: $card.phones) EditableStringList(label: "E-mail(s)", items: $card.emails) } else { C2VTextField(label: "Téléphone(s)", text: joinedBinding(\.phones)) .keyboardType(.phonePad) C2VTextField(label: "E-mail(s)", text: joinedBinding(\.emails)) .keyboardType(.emailAddress) .textInputAutocapitalization(.never) } C2VTextField(label: "Site web", text: optionalBinding(\.website)) .keyboardType(.URL) .textInputAutocapitalization(.never) C2VTextField( label: "Adresse", text: optionalBinding(\.address, douteuxKey: "address"), supportingText: sousTexte("address") ) C2VTextField(label: "Note", text: optionalBinding(\.note), minLines: 2) } } private func sousTexte(_ cle: String) -> String? { card.champsDouteux.contains(cle) ? Self.aVerifier : nil } /// `douteuxKey`: editing the field clears its « à vérifier » flag. private func optionalBinding( _ keyPath: WritableKeyPath<ContactCard, String?>, douteuxKey: String? = nil ) -> Binding<String> { Binding( get: { card[keyPath: keyPath] ?? "" }, set: { value in card[keyPath: keyPath] = value.nilIfBlank if let douteuxKey { card.champsDouteux.remove(douteuxKey) } } ) } // Kotlin joined with ", " and split on ','/';'. private func joinedBinding(_ keyPath: WritableKeyPath<ContactCard, [String]>) -> Binding<String> { Binding( get: { card[keyPath: keyPath].joined(separator: ", ") }, set: { value in card[keyPath: keyPath] = value .split(whereSeparator: { $0 == "," || $0 == ";" }) .map { $0.trimmingCharacters(in: .whitespaces) } .filter { !$0.isEmpty } } ) } } /// Editable list of strings: one square field per entry, remove button, add row. struct EditableStringList: View { let label: String @Binding var items: [String] var body: some View { VStack(alignment: .leading, spacing: 6) { Text(label) .font(C2VFont.labelSmall) .foregroundColor(C2VColor.body) ForEach(items.indices, id: \.self) { index in HStack(spacing: 8) { C2VTextField(label: "", text: Binding( get: { index < items.count ? items[index] : "" }, set: { value in if index < items.count { items[index] = value } } )) Button { if index < items.count { items.remove(at: index) } } label: { Image(systemName: "minus") .foregroundColor(C2VColor.ink) .frame(width: 32, height: 32) .overlay(Rectangle().stroke(C2VColor.bordure, lineWidth: 1)) } .accessibilityLabel("Supprimer") } } Button { items.append("") } label: { Text("Ajouter") .font(C2VFont.labelMedium) .foregroundColor(C2VColor.ink) .padding(.vertical, 4) } .buttonStyle(.plain) } } }
GitRust