iOS: "Ort zuordnen" auch ohne Stueck-QR (Einzelstueck aus Liste waehlen)
Bisher musste man im "Ort zuordnen"-Ablauf zuerst den QR des Einzelstuecks scannen. Fuer Stuecke ohne eigenen Code (z.B. Kleidung) gibt es jetzt "Einzelstueck aus Liste waehlen" (durchsuchbare Liste) als Alternative; danach wie gehabt den Lagerort-QR scannen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -9,9 +9,10 @@ struct AssignScanView: View {
|
|||||||
@State private var paused = false
|
@State private var paused = false
|
||||||
@State private var torchOn = false
|
@State private var torchOn = false
|
||||||
@State private var torchLocked = false
|
@State private var torchLocked = false
|
||||||
@State private var pending: Item? // gescanntes Stück, wartet auf Ort
|
@State private var pending: Item? // gescanntes/gewähltes Stück, wartet auf Ort
|
||||||
@State private var status: String?
|
@State private var status: String?
|
||||||
@State private var error: String?
|
@State private var error: String?
|
||||||
|
@State private var showPicker = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
@@ -34,8 +35,14 @@ struct AssignScanView: View {
|
|||||||
.background(Color.accentColor.opacity(0.15))
|
.background(Color.accentColor.opacity(0.15))
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 12)).padding(.horizontal)
|
.clipShape(RoundedRectangle(cornerRadius: 12)).padding(.horizontal)
|
||||||
} else {
|
} else {
|
||||||
Text("Schritt 1: Einzelstück-QR scannen")
|
VStack(spacing: 8) {
|
||||||
|
Text("Schritt 1: Einzelstück-QR scannen – oder ohne Code:")
|
||||||
.font(.caption).foregroundStyle(.secondary)
|
.font(.caption).foregroundStyle(.secondary)
|
||||||
|
// Für Stücke ohne eigenen QR (z.B. Kleidung): aus der Liste wählen.
|
||||||
|
Button { showPicker = true } label: {
|
||||||
|
Label("Einzelstück aus Liste wählen", systemImage: "list.bullet")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let status {
|
if let status {
|
||||||
@@ -55,6 +62,9 @@ struct AssignScanView: View {
|
|||||||
ToolbarItem(placement: .topBarLeading) { Button("Fertig") { dismiss() } }
|
ToolbarItem(placement: .topBarLeading) { Button("Fertig") { dismiss() } }
|
||||||
ToolbarItem(placement: .topBarTrailing) { TorchButton(isOn: $torchOn, locked: $torchLocked) }
|
ToolbarItem(placement: .topBarTrailing) { TorchButton(isOn: $torchOn, locked: $torchLocked) }
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: $showPicker) {
|
||||||
|
ItemPickerSheet { it in pending = it; status = nil; error = nil }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(_ code: String) async {
|
private func handle(_ code: String) async {
|
||||||
@@ -90,3 +100,49 @@ struct AssignScanView: View {
|
|||||||
error = "Unbekannter Code – bitte einen Einzelstück- oder Lagerort-QR scannen."
|
error = "Unbekannter Code – bitte einen Einzelstück- oder Lagerort-QR scannen."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Einzelstück aus einer durchsuchbaren Liste wählen – für Stücke ohne eigenen QR.
|
||||||
|
struct ItemPickerSheet: View {
|
||||||
|
var onPick: (Item) -> Void
|
||||||
|
|
||||||
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
@State private var items: [Item] = []
|
||||||
|
@State private var locations: [StorageLocation] = []
|
||||||
|
@State private var query = ""
|
||||||
|
@State private var busy = true
|
||||||
|
|
||||||
|
private var gefiltert: [Item] {
|
||||||
|
let q = query.trimmingCharacters(in: .whitespaces).lowercased()
|
||||||
|
guard !q.isEmpty else { return items }
|
||||||
|
return items.filter {
|
||||||
|
[$0.productName, $0.uid, $0.productBrand, $0.note]
|
||||||
|
.compactMap { $0 }.joined(separator: " ").lowercased().contains(q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationStack {
|
||||||
|
List {
|
||||||
|
if busy && items.isEmpty { ProgressView() }
|
||||||
|
ForEach(gefiltert) { it in
|
||||||
|
Button { onPick(it); dismiss() } label: {
|
||||||
|
ItemRow(item: it, locations: locations)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
if !busy && gefiltert.isEmpty {
|
||||||
|
Text("Nichts gefunden.").foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.searchable(text: $query, prompt: "Produkt, UID oder Notiz")
|
||||||
|
.navigationTitle("Einzelstück wählen")
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.toolbar { ToolbarItem(placement: .topBarLeading) { Button("Abbrechen") { dismiss() } } }
|
||||||
|
.task {
|
||||||
|
items = (try? await APIClient.shared.allItems()) ?? []
|
||||||
|
locations = (try? await APIClient.shared.locations()) ?? []
|
||||||
|
busy = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user