Files
Vorrania/ios/Sources/CategoryPicker.swift
T
ScarriffleandClaude Opus 5 d7002e2252 App: Einrueckung haelt auch bei Umbruch, Loeschen fragt mittig
Eingerueckt wurde mit fuehrenden Leerzeichen. Die verschieben aber nur die
ERSTE Zeile: Bricht ein langer Name um ("Schublade Links Unten"), faengt die
Fortsetzung wieder ganz links an und die Hierarchie ist weg.

In einem aufklappenden Menue laesst sich das nicht loesen - dort liefert man
nur Text ab, das System ignoriert jedes Layout (auch lineLimit). Die
Lagerort- und Kategorieauswahl erscheint deshalb jetzt als Liste
(.pickerStyle(.navigationLink)). Dort ist jede Zeile eine echte Ansicht, ein
Innenabstand rueckt den ganzen Block ein - auch die zweite Zeile. Das liest
sich bei vielen Lagerorten ohnehin besser als ein langes Aufklappmenue.

Zwei enge Zeilen bleiben Menues: Mindestbestand je Ort bei Artikel und
Gruppe, wo direkt daneben das Mengenfeld steht. Dort wuerde eine
Listenauswahl die Zeile sprengen; sie behalten die Leerzeichen-Einrueckung.

Der Loeschdialog war ein confirmationDialog und fuhr als Blase von unten
herein. Jetzt ein alert: steht mittig und will gelesen werden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-15 21:12:29 +02:00

99 lines
3.3 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import SwiftUI
/// Auswahl einer Kategorie mit eingerueckten Unterkategorien.
///
/// Kategorie und Gruppe sind zwei verschiedene Dinge: Die Kategorie ordnet nur
/// die Artikelliste, die Gruppe zaehlt Bestaende mehrerer Marken zusammen.
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) {
Text("– keine –").tag(Int?.none)
ForEach(baum(gefiltert)) { eintrag in
BaumZeile(zeile: eintrag).tag(Int?.some(eintrag.item.id))
}
}
// Als Liste statt als Menue: Nur so rueckt ein umbrechender langer
// Name auch in der zweiten Zeile ein.
.pickerStyle(.navigationLink)
}
private var gefiltert: [CategoryItem] {
guard let tracking else { return categories }
return categories.filter { $0.tracking == tracking }
}
}
/// Legt eine Gruppe an Ort und Stelle an, damit man das Formular nicht
/// verlassen muss. Nur fuer Administratoren - POST /groups verlangt das.
struct NewGroupSheet: View {
let units: [Unit]
var onCreated: (GroupItem) -> Void
@Environment(\.dismiss) private var dismiss
@State private var name = ""
@State private var minStock = ""
@State private var unitId: Int?
@State private var busy = false
@State private var error: String?
var body: some View {
Form {
Section {
LabeledField(label: "Name", text: $name)
} footer: {
Text("Eine Gruppe zählt Bestände mehrerer Marken zusammen – "
+ "z. B. Mehl von verschiedenen Herstellern als „5 kg Mehl“.")
}
Section("Mindestbestand (optional)") {
QuantityField(label: "Menge", text: $minStock)
Picker("Einheit", selection: $unitId) {
Text("– Basiseinheit –").tag(Int?.none)
ForEach(units) { unit in
Text(unit.name).tag(Int?.some(unit.id))
}
}
}
if let error {
Section { Text(error).foregroundStyle(.red).font(.callout) }
}
Section {
Button(busy ? "Anlegen…" : "Anlegen") { Task { await create() } }
.disabled(busy || name.trimmingCharacters(in: .whitespaces).isEmpty)
}
}
.navigationTitle("Neue Gruppe")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarLeading) { Button("Abbrechen") { dismiss() } }
}
}
private func create() async {
error = nil
busy = true
defer { busy = false }
do {
let created = try await APIClient.shared.createGroup(
NewGroupRequest(
name: name.trimmingCharacters(in: .whitespaces),
minStock: Double(minStock.replacingOccurrences(of: ",", with: ".")),
minStockUnitId: unitId
)
)
onCreated(created)
dismiss()
} catch {
self.error = error.localizedDescription
}
}
}