iOS: getrennte Lebensmittel/Gegenstaende-Listen + anklickbarer Verlauf

Listen-Tab: zwei halbe Kacheln "Lebensmittel" und "Gegenstaende" (ProductListView
mit fixedType, clientseitig ueber isObject gefiltert wie im Web); Neuanlage
uebernimmt den Typ. Einzelstuecke bleiben unveraendert (reine Gegenstands-Welt).

Verlauf und "Letzte Bewegungen" auf der Startseite: Tippen auf eine Bewegung
oeffnet ueber den neuen Lader ProductByIdView das jeweilige Produkt. Der
artikel-eigene Verlauf bleibt ohne Link.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-28 07:29:49 +02:00
parent c28ac7d7dd
commit 0ea188374a
6 changed files with 119 additions and 13 deletions

View File

@@ -191,6 +191,10 @@ struct ExpiringView: View {
// MARK: - Produktliste
struct ProductListView: View {
/// nil = alle, "food" = nur Lebensmittel, "object" = nur Gegenstände.
/// Getrennte Listen wie im Web (dort über `fixedType`/`p.tracking`).
var fixedType: String? = nil
@EnvironmentObject private var session: Session
@State private var query = ""
@State private var products: [Product] = []
@@ -200,6 +204,20 @@ struct ProductListView: View {
@State private var busy = false
@State private var showNew = false
/// Auf den festen Typ gefiltert (clientseitig, wie im Web).
private var sichtbar: [Product] {
guard let fixedType else { return products }
return products.filter { ($0.isObject ? "object" : "food") == fixedType }
}
private var titel: String {
switch fixedType {
case "food": return "Lebensmittel"
case "object": return "Gegenstände"
default: return "Produkte"
}
}
private var filterLabel: String {
if categoryId == 0 { return "Ohne Kategorie" }
if let id = categoryId, let treffer = categories.first(where: { $0.id == id }) {
@@ -228,21 +246,21 @@ struct ProductListView: View {
}
Section {
ForEach(products) { product in
ForEach(sichtbar) { product in
NavigationLink {
ProductDetailView(product: product)
} label: {
ProductRow(product: product)
}
}
if products.isEmpty && !busy {
if sichtbar.isEmpty && !busy {
Text("Keine Treffer").foregroundStyle(.secondary)
}
}
}
.searchable(text: $query, prompt: "Artikel suchen")
.onChange(of: query) { _ in Task { await load() } }
.navigationTitle("Produkte")
.navigationTitle(titel)
.navigationBarTitleDisplayMode(.inline)
.refreshable { await load() }
.toolbar {
@@ -256,9 +274,10 @@ struct ProductListView: View {
}
.sheet(isPresented: $showNew) {
NavigationStack {
// Ohne Barcode: nur Name + Kategorie nötig. Nach dem Anlegen
// schließt sich das Formular und die Liste wird aufgefrischt.
ProductFormView(prefillBarcode: nil, groupId: nil) { _ in
// Ohne Barcode: nur Name + Kategorie nötig. Typ aus der Liste
// vorbelegen. Nach dem Anlegen schließt sich das Formular und die
// Liste wird aufgefrischt.
ProductFormView(prefillBarcode: nil, groupId: nil, initialType: fixedType) { _ in
showNew = false
Task { await load() }
}