App: Listendarstellung der Auswahl zurueckgenommen - sie warf aus dem Formular

Beim Anlegen eines Artikels fuehrte die Kategoriewahl zurueck in die
Artikelliste: Das Formular steht in einem Blatt, und die geschobene Auswahl
riss beim Zurueckspringen den ganzen Navigationsstapel mit - das Blatt also
gleich dazu. Der Artikel liess sich so nicht mehr anlegen.

Damit ist .pickerStyle(.navigationLink) an allen acht Stellen wieder
draussen. Die Auswahl ist wieder ein Menue und rueckt mit fuehrenden
Leerzeichen ein, wie vor d7002e2.

Der Umbruch langer Namen bleibt damit ungeloest: Faellt "Schublade Links
Unten" auf eine zweite Zeile, faengt die wieder ganz links an. Die Grenze
steht jetzt als Kommentar an Baumzeile.label, damit der naechste Versuch
nicht wieder in dieselbe Falle laeuft. Funktionierendes Anlegen wiegt
schwerer als saubere Einrueckung.

Der mittige Loeschdialog aus demselben Commit bleibt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-15 21:37:11 +02:00
co-authored by Claude Opus 5
parent 38489a5217
commit 75899714b3
7 changed files with 16 additions and 42 deletions
+8 -24
View File
@@ -1,4 +1,4 @@
import SwiftUI import Foundation
/// Eine Zeile einer flach ausgelegten Baumliste, mit ihrer Tiefe. /// Eine Zeile einer flach ausgelegten Baumliste, mit ihrer Tiefe.
/// ///
@@ -12,33 +12,17 @@ struct Baumzeile<T: TreeItem>: Identifiable {
var id: T.ID { item.id } var id: T.ID { item.id }
/// Name mit Einrueckung aus fuehrenden Leerzeichen. /// Name mit Einrueckung je Ebene.
/// ///
/// Nur fuer aufklappende Menues, wo man ausser Text nichts abliefern kann. /// Eingerueckt wird mit fuehrenden Leerzeichen, weil ein aufklappendes
/// Der Nachteil bleibt dort bestehen: Bricht ein langer Name um, faengt die /// Auswahlmenue ausser Text nichts annimmt - Layout ignoriert es.
/// zweite Zeile ganz links an. Wo es geht, `BaumZeile` nehmen. /// Bekannte Grenze: Bricht ein langer Name auf eine zweite Zeile um,
/// faengt die wieder ganz links an. Eine Listendarstellung
/// (`.pickerStyle(.navigationLink)`) koennte das, riss aber im Blatt den
/// ganzen Navigationsstapel mit und ist deshalb wieder draussen.
var label: String { String(repeating: " ", count: tiefe) + item.name } var label: String { String(repeating: " ", count: tiefe) + item.name }
} }
/// Auswahlzeile mit echter Einrueckung.
///
/// Fuehrende Leerzeichen verschieben nur die erste Zeile - ein langer Name
/// bricht um und die Fortsetzung steht wieder ganz links, womit die Hierarchie
/// verloren geht. Ein Innenabstand rueckt dagegen den ganzen Block ein.
///
/// Verlangt eine Auswahl, die als Liste erscheint (`.pickerStyle(.navigationLink)`):
/// In einem aufklappenden Menue zeigt das System nur den Text und ignoriert
/// jedes Layout.
struct BaumZeile<T: TreeItem>: View {
let zeile: Baumzeile<T>
var body: some View {
Text(zeile.item.name)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.leading, CGFloat(zeile.tiefe) * 16)
}
}
/// Bringt eine flache Eltern-Kind-Liste in Baumreihenfolge, mit Tiefe. /// Bringt eine flache Eltern-Kind-Liste in Baumreihenfolge, mit Tiefe.
/// ///
/// Waisen - deren Elternteil weggefiltert oder geloescht ist - gelten als /// Waisen - deren Elternteil weggefiltert oder geloescht ist - gelten als
+1 -4
View File
@@ -14,12 +14,9 @@ struct CategoryPicker: View {
Picker("Kategorie", selection: $selection) { Picker("Kategorie", selection: $selection) {
Text("– keine –").tag(Int?.none) Text("– keine –").tag(Int?.none)
ForEach(baum(gefiltert)) { eintrag in ForEach(baum(gefiltert)) { eintrag in
BaumZeile(zeile: eintrag).tag(Int?.some(eintrag.item.id)) Text(eintrag.label).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] { private var gefiltert: [CategoryItem] {
+1 -2
View File
@@ -212,10 +212,9 @@ struct CheckInFormView: View {
Picker("Lagerort", selection: $locationId) { Picker("Lagerort", selection: $locationId) {
Text("– keiner –").tag(String?.none) Text("– keiner –").tag(String?.none)
ForEach(baum(locations)) { eintrag in ForEach(baum(locations)) { eintrag in
BaumZeile(zeile: eintrag).tag(String?.some(eintrag.item.id)) Text(eintrag.label).tag(String?.some(eintrag.item.id))
} }
} }
.pickerStyle(.navigationLink)
Button { Button {
locScanError = nil locScanError = nil
locScanPaused = false locScanPaused = false
+2 -4
View File
@@ -340,9 +340,8 @@ struct ItemEditView: View {
Section { Section {
Picker("Lagerort", selection: $locationId) { Picker("Lagerort", selection: $locationId) {
Text("– ohne –").tag(String?.none) Text("– ohne –").tag(String?.none)
ForEach(baum(locations)) { e in BaumZeile(zeile: e).tag(String?.some(e.item.id)) } ForEach(baum(locations)) { e in Text(e.label).tag(String?.some(e.item.id)) }
} }
.pickerStyle(.navigationLink)
// Lagerort per QR setzen – ohne den (evtl. nicht vorhandenen) QR // Lagerort per QR setzen – ohne den (evtl. nicht vorhandenen) QR
// des Einzelstücks. Praktisch z.B. bei Kleidung. // des Einzelstücks. Praktisch z.B. bei Kleidung.
Button { locScanShown = true } label: { Button { locScanShown = true } label: {
@@ -879,9 +878,8 @@ struct ItemAddSheet: View {
Stepper("Anzahl: \(count)", value: $count, in: 1...200) Stepper("Anzahl: \(count)", value: $count, in: 1...200)
Picker("Lagerort", selection: $locationId) { Picker("Lagerort", selection: $locationId) {
Text("– ohne –").tag(String?.none) Text("– ohne –").tag(String?.none)
ForEach(baum(locations)) { e in BaumZeile(zeile: e).tag(String?.some(e.item.id)) } ForEach(baum(locations)) { e in Text(e.label).tag(String?.some(e.item.id)) }
} }
.pickerStyle(.navigationLink)
Button { locScanShown = true } label: { Button { locScanShown = true } label: {
Label("Lagerort scannen", systemImage: "qrcode.viewfinder") Label("Lagerort scannen", systemImage: "qrcode.viewfinder")
} }
+2 -4
View File
@@ -447,10 +447,9 @@ struct LocationEditor: View {
Picker("Übergeordnet", selection: $parentId) { Picker("Übergeordnet", selection: $parentId) {
Text("– oberste Ebene –").tag(String?.none) Text("– oberste Ebene –").tag(String?.none)
ForEach(baum(parentOptions)) { eintrag in ForEach(baum(parentOptions)) { eintrag in
BaumZeile(zeile: eintrag).tag(String?.some(eintrag.item.id)) Text(eintrag.label).tag(String?.some(eintrag.item.id))
} }
} }
.pickerStyle(.navigationLink)
} header: { } header: {
Text("Übergeordneter Lagerort (optional)") Text("Übergeordneter Lagerort (optional)")
} }
@@ -787,10 +786,9 @@ struct CategoryEditor: View {
Picker("Übergeordnet", selection: $parentId) { Picker("Übergeordnet", selection: $parentId) {
Text("– oberste Ebene –").tag(Int?.none) Text("– oberste Ebene –").tag(Int?.none)
ForEach(baum(all)) { eintrag in ForEach(baum(all)) { eintrag in
BaumZeile(zeile: eintrag).tag(Int?.some(eintrag.item.id)) Text(eintrag.label).tag(Int?.some(eintrag.item.id))
} }
} }
.pickerStyle(.navigationLink)
} header: { } header: {
Text("Übergeordnete Kategorie (optional)") Text("Übergeordnete Kategorie (optional)")
} footer: { } footer: {
+1 -2
View File
@@ -152,9 +152,8 @@ private struct LocationPicker: View {
var body: some View { var body: some View {
Picker(title, selection: $selection) { Picker(title, selection: $selection) {
Text("– ohne Lagerort –").tag(String?.none) Text("– ohne Lagerort –").tag(String?.none)
ForEach(baum(locations)) { e in BaumZeile(zeile: e).tag(String?.some(e.item.id)) } ForEach(baum(locations)) { e in Text(e.label).tag(String?.some(e.item.id)) }
} }
.pickerStyle(.navigationLink)
} }
} }
+1 -2
View File
@@ -726,9 +726,8 @@ struct LotEditView: View {
Section("Lagerort") { Section("Lagerort") {
Picker("Lagerort", selection: $locationId) { Picker("Lagerort", selection: $locationId) {
Text("– ohne –").tag(String?.none) Text("– ohne –").tag(String?.none)
ForEach(baum(locations)) { e in BaumZeile(zeile: e).tag(String?.some(e.item.id)) } ForEach(baum(locations)) { e in Text(e.label).tag(String?.some(e.item.id)) }
} }
.pickerStyle(.navigationLink)
// Ort per QR am Regal/Fach setzen, statt in der Liste zu suchen. // Ort per QR am Regal/Fach setzen, statt in der Liste zu suchen.
Button { locScanShown = true } label: { Button { locScanShown = true } label: {
Label("Lagerort scannen", systemImage: "qrcode.viewfinder") Label("Lagerort scannen", systemImage: "qrcode.viewfinder")