iOS: Umschalter Lebensmittel/Gegenstand im Artikelformular

Gleiche Idee wie im Web: ein Typ-Umschalter filtert die Kategorieauswahl, statt
Werkzeug & Co. zwischen den Lebensmittel-Kategorien zu suchen. Im Anlege-Formular
blenden sich zudem die Lebensmittel-Felder (Gruppe, Einheit, MHD) aus, wenn
"Gegenstand" gewaehlt ist. Die Detailansicht filtert die Kategorieliste auf den
Typ des Artikels. CategoryPicker bekam dafuer einen optionalen Typ-Filter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-25 23:40:32 +02:00
parent 8d75ad63ce
commit c532492286
3 changed files with 71 additions and 37 deletions

View File

@@ -7,6 +7,8 @@ import SwiftUI
struct CategoryPicker: View {
let categories: [CategoryItem]
@Binding var selection: Int?
/// Nur Kategorien dieses Typs zeigen ("food"/"object"); nil = alle.
var tracking: String? = nil
var body: some View {
Picker("Kategorie", selection: $selection) {
@@ -18,17 +20,23 @@ struct CategoryPicker: View {
}
}
private var gefiltert: [CategoryItem] {
guard let tracking else { return categories }
return categories.filter { $0.tracking == tracking }
}
private func flattened() -> [(item: CategoryItem, depth: Int)] {
let ids = Set(categories.map(\.id))
let quelle = gefiltert
let ids = Set(quelle.map(\.id))
var result: [(CategoryItem, Int)] = []
func walk(_ node: CategoryItem, _ depth: Int) {
result.append((node, depth))
for child in categories.filter({ $0.parentId == node.id }) {
for child in quelle.filter({ $0.parentId == node.id }) {
walk(child, depth + 1)
}
}
for root in categories.filter({ $0.parentId == nil || !ids.contains($0.parentId!) }) {
for root in quelle.filter({ $0.parentId == nil || !ids.contains($0.parentId!) }) {
walk(root, 0)
}
return result

View File

@@ -84,11 +84,12 @@ struct ProductDetailView: View {
}
Section {
CategoryPicker(categories: categories, selection: $categoryId)
CategoryPicker(categories: categories, selection: $categoryId,
tracking: current.tracking)
} footer: {
Text(current.isObject
? "Kategorie bestimmt die Verwaltungsart (Gegenstand) und die eigenen Felder."
: "Kategorie: nur für den Überblick in der Artikelliste.")
? "Nur Gegenstands-Kategorien. Bestimmt die eigenen Felder."
: "Nur Lebensmittel-Kategorien.")
}
if current.isObject {

View File

@@ -70,6 +70,8 @@ struct ProductFormView: View {
@State private var datePrecision = "day"
@State private var selectedGroupId: Int?
@State private var selectedCategoryId: Int?
// Umschalter Lebensmittel/Gegenstand: filtert die Kategorieauswahl.
@State private var modus = "object"
@State private var groups: [GroupItem] = []
@State private var categories: [CategoryItem] = []
@State private var units: [Unit] = []
@@ -89,10 +91,27 @@ struct ProductFormView: View {
LabeledField(label: "Marke", text: $brand)
}
Section {
CategoryPicker(categories: categories, selection: $selectedCategoryId)
} footer: {
Text("Kategorie: nur für den Überblick in der Artikelliste.")
Picker("Typ", selection: $modus) {
Text("Lebensmittel").tag("food")
Text("Gegenstand").tag("object")
}
.pickerStyle(.segmented)
CategoryPicker(categories: categories, selection: $selectedCategoryId, tracking: modus)
} footer: {
Text(modus == "object"
? "Gegenstand: Menge je Lagerort und eigene Felder."
: "Lebensmittel: Chargen mit Mindesthaltbarkeit.")
}
.onChange(of: modus) { neu in
// Passt die gewählte Kategorie nicht mehr zum Typ, Auswahl leeren.
if let cid = selectedCategoryId,
categories.first(where: { $0.id == cid })?.tracking != neu {
selectedCategoryId = nil
}
}
// Lebensmittel-Felder (Gruppe, Einheit, MHD) nur im Lebensmittel-Modus.
// Fuer Gegenstaende irrelevant - sie zaehlen in Stueck je Lagerort.
if modus == "food" {
Section {
Picker("Gruppe", selection: $selectedGroupId) {
Text(" keine ").tag(Int?.none)
@@ -127,6 +146,7 @@ struct ProductFormView: View {
Text("nur Monat/Jahr").tag("month")
}
}
}
if let error {
Section { Text(error).foregroundStyle(.red).font(.callout) }
}
@@ -142,6 +162,11 @@ struct ProductFormView: View {
groups = (try? await APIClient.shared.groups()) ?? []
categories = (try? await APIClient.shared.categories()) ?? []
units = (try? await APIClient.shared.units()) ?? []
// Kam eine Kategorie aus dem Barcode-Vorschlag, den Typ dazu setzen.
if let cid = selectedCategoryId,
let t = categories.first(where: { $0.id == cid })?.tracking {
modus = t
}
}
.sheet(isPresented: $newGroupShown) {
NavigationStack {