NFC-Tags fuer Einzelstuecke: beschreiben und lesen
Ein aufgeklebtes QR-Etikett uebersteht keine Waesche. Kleidungsstuecke bekommen deshalb eingenaehte NFC-Tags. Auf das Tag kommt genau das, was auch im QR steckt (vorrania://i/<UID>) - damit bleibt das Einlesen inhaltlich unveraendert, nur die Erfassungsart ist neu. Backend und Web brauchten nichts: die UID vergibt der Server, und GET /items/by-uid/<UID> gibt es laengst. Gelesen wird nur bei geoeffneter App. iOS startet Apps beim Antippen im Hintergrund ausschliesslich ueber https-Universal-Links auf einer beanspruchten Domain und ignoriert eigene Schemes dabei - eine feste Domain ist fuer einen selbstgehosteten Dienst aber gerade der falsche Weg (siehef981f41). Die /i/-Zerlegung lag dreifach kopiert in CheckInView, LookupScanView und AssignScanView und steckt jetzt in einzelstueckCode(aus:). Die nackte UID wird nur fuer NFC akzeptiert: eine achtstellige EAN-8 kann zufaellig genau wie eine UID aussehen, und die Kamera sieht fremde Barcodes - ein Tag haben wir selbst beschrieben. Zwei Altlasten in denselben Dateien mit erledigt: - project.yml deklarierte die applinks-Domain weiter, obwohlf981f41sie entfernt hat. XcodeGen erzeugt die Entitlements aus diesem Block und schrieb sie bei jedem "generate" zurueck; die Domain existiert laengst nicht mehr. - AssignScanView sendete ItemUpdateRequest ohne priceCents/currency. Da encode immer alle Felder schreibt (auch null), hat ein Zuordnen per Scan Kaufpreis und Waehrung stillschweigend geloescht. Ebenfalls raus: QRImage und qrLink(forUid:) in ItemViews - ungenutzt, und qrLink baute noch das alte https-Format. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9be772557e
commit
09a763a823
@@ -38,7 +38,19 @@ struct AssignScanView: View {
|
||||
VStack(spacing: 8) {
|
||||
Text("Schritt 1: Einzelstück-QR scannen – oder ohne Code:")
|
||||
.font(.caption).foregroundStyle(.secondary)
|
||||
// Für Stücke ohne eigenen QR (z.B. Kleidung): aus der Liste wählen.
|
||||
// Kleidung trägt keinen QR, aber ein eingenähtes NFC-Tag.
|
||||
NFCLesenButton(titel: "Einzelstück-Tag lesen") { uid in
|
||||
Task {
|
||||
let gefunden = await waehle(uid: uid)
|
||||
if !gefunden {
|
||||
error = "Kein Einzelstück mit der UID \(uid)."
|
||||
status = nil
|
||||
}
|
||||
}
|
||||
} onFehler: { meldung in
|
||||
error = meldung; status = nil
|
||||
}
|
||||
// Für Stücke ohne Code jeder Art: aus der Liste wählen.
|
||||
Button { showPicker = true } label: {
|
||||
Label("Einzelstück aus Liste wählen", systemImage: "list.bullet")
|
||||
}
|
||||
@@ -78,9 +90,14 @@ struct AssignScanView: View {
|
||||
error = "Erst ein Einzelstück scannen."; status = nil; return
|
||||
}
|
||||
do {
|
||||
// Alle Felder mitsenden: ItemUpdateRequest schreibt auch null
|
||||
// mit, damit sich Felder leeren lassen. Kaufpreis und Waehrung
|
||||
// fehlten hier – ein Zuordnen per Scan hat sie stillschweigend
|
||||
// geloescht.
|
||||
_ = try await APIClient.shared.updateItem(id: it.id, ItemUpdateRequest(
|
||||
locationId: locCode, shopId: it.shopId,
|
||||
acquiredOn: it.acquiredOn, warrantyUntil: it.warrantyUntil, note: it.note))
|
||||
acquiredOn: it.acquiredOn, warrantyUntil: it.warrantyUntil, note: it.note,
|
||||
priceCents: it.priceCents, currency: it.currency))
|
||||
status = "\(it.uid) zugeordnet. Nächstes Stück scannen."
|
||||
error = nil
|
||||
pending = nil
|
||||
@@ -89,16 +106,23 @@ struct AssignScanView: View {
|
||||
}
|
||||
}
|
||||
// Einzelstück-QR (…/i/<UID>)?
|
||||
if let r = code.range(of: "/i/") {
|
||||
let uid = String(code[r.upperBound...])
|
||||
.trimmingCharacters(in: CharacterSet(charactersIn: "/ ")).uppercased()
|
||||
if !uid.isEmpty, let it = try? await APIClient.shared.itemByUid(uid: uid) {
|
||||
pending = it; status = nil; error = nil
|
||||
return
|
||||
}
|
||||
if let uid = einzelstueckCode(aus: code), await waehle(uid: uid) {
|
||||
return
|
||||
}
|
||||
error = "Unbekannter Code – bitte einen Einzelstück- oder Lagerort-QR scannen."
|
||||
}
|
||||
|
||||
/// Einzelstück als „wartet auf Lagerort" vormerken – aus Scan, NFC oder Liste.
|
||||
/// Gibt zurueck, ob es gefunden wurde; der Aufrufer entscheidet ueber die
|
||||
/// Fehlermeldung, weil ein Scan noch andere Deutungen zulaesst als ein Tag.
|
||||
@discardableResult
|
||||
private func waehle(uid: String) async -> Bool {
|
||||
guard let it = try? await APIClient.shared.itemByUid(uid: uid) else { return false }
|
||||
pending = it
|
||||
status = nil
|
||||
error = nil
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/// Einzelstück aus einer durchsuchbaren Liste wählen – für Stücke ohne eigenen QR.
|
||||
|
||||
Reference in New Issue
Block a user