Lagerort- und Kategorieauswahl zeigen den Baum statt einer Mischung
Die Auswahl war nicht flach, weil die Beschriftung gefehlt haette - der volle Pfad stand laengst drin. Sie kam vom Server nach dem BLATTnamen sortiert, und so standen "Garage -> Fach A" und "Keller -> Fach A" irgendwo zwischen allem anderen. Geschwister und Kinder fanden nie zusammen. Neu ist baum() in Baum.swift: bringt eine flache Eltern-Kind-Liste in Baumreihenfolge und rueckt je Ebene ein. Waisen gelten als oberste Ebene, damit nichts lautlos aus der Auswahl faellt. Derselbe Lauf lag bisher dreimal im Projekt (CategoryPicker, TreeMasterView, LocationEditor). Alle drei zeigen jetzt auf den einen - unterm Strich verschwinden mehr Zeilen als dazukommen. Zwei der Kopien waren auch nicht gleichwertig: LocationEditor.pfad hatte den Zyklusschutz von path(in:) nicht und waere bei einer ringfoermigen Elternkette endlos gelaufen. Umgestellt sind neun Auswahlfelder. Die Lagerortzeile beim Kassenzettel zeigte nur den nackten Namen und bekommt den vollen Pfad - dort ist kein Platz zum Einruecken. MARKETING_VERSION stand auf 1.2 in der project.pbxproj, aber auf 1.1 in der project.yml, aus der sie erzeugt wird. Die Quelle nachgezogen, sonst haette das naechste "xcodegen generate" die Anhebung zurueckgedreht. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
264d3886f3
commit
501d80a9b8
@@ -197,33 +197,11 @@ struct TreeMasterView<Item: TreeItem, Header: View, Editor: View>: View {
|
||||
@State private var addShown = false
|
||||
@State private var pendingDeletion: Item?
|
||||
|
||||
private struct Node: Identifiable {
|
||||
let item: Item
|
||||
let depth: Int
|
||||
var id: Item.ID { item.id }
|
||||
}
|
||||
|
||||
private var shown: [Item] { items.filter(include) }
|
||||
|
||||
/// Baumreihenfolge mit Tiefe. Waisen (Elternteil gefiltert/gelöscht) gelten
|
||||
/// als oberste Ebene, damit nichts verschwindet.
|
||||
private var nodes: [Node] {
|
||||
let list = shown
|
||||
let ids = Set(list.map(\.id))
|
||||
var result: [Node] = []
|
||||
func walk(_ n: Item, _ depth: Int) {
|
||||
result.append(Node(item: n, depth: depth))
|
||||
for child in list.filter({ $0.parentId == n.id }) { walk(child, depth + 1) }
|
||||
}
|
||||
for root in list.filter({ $0.parentId == nil || !ids.contains($0.parentId!) }) {
|
||||
walk(root, 0)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private func childCount(_ id: Item.ID) -> Int { shown.filter { $0.parentId == id }.count }
|
||||
|
||||
private var visible: [Node] {
|
||||
private var visible: [Baumzeile<Item>] {
|
||||
let parent = Dictionary(uniqueKeysWithValues: shown.map { ($0.id, $0.parentId) })
|
||||
func hidden(_ id: Item.ID) -> Bool {
|
||||
var p = parent[id] ?? nil
|
||||
@@ -233,7 +211,7 @@ struct TreeMasterView<Item: TreeItem, Header: View, Editor: View>: View {
|
||||
}
|
||||
return false
|
||||
}
|
||||
return nodes.filter { !hidden($0.item.id) }
|
||||
return baum(shown).filter { !hidden($0.item.id) }
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
@@ -286,7 +264,7 @@ struct TreeMasterView<Item: TreeItem, Header: View, Editor: View>: View {
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func row(_ node: Node) -> some View {
|
||||
private func row(_ node: Baumzeile<Item>) -> some View {
|
||||
let kinder = childCount(node.item.id)
|
||||
let zu = collapsed.contains(node.item.id)
|
||||
HStack(spacing: 8) {
|
||||
@@ -321,7 +299,7 @@ struct TreeMasterView<Item: TreeItem, Header: View, Editor: View>: View {
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
.padding(.leading, CGFloat(node.depth) * 16)
|
||||
.padding(.leading, CGFloat(node.tiefe) * 16)
|
||||
}
|
||||
|
||||
private func toggle(_ id: Item.ID) {
|
||||
@@ -468,8 +446,8 @@ struct LocationEditor: View {
|
||||
Section {
|
||||
Picker("Übergeordnet", selection: $parentId) {
|
||||
Text("– oberste Ebene –").tag(String?.none)
|
||||
ForEach(parentOptions) { loc in
|
||||
Text(LocationEditor.pfad(loc, in: all)).tag(String?.some(loc.id))
|
||||
ForEach(baum(parentOptions)) { eintrag in
|
||||
Text(eintrag.label).tag(String?.some(eintrag.item.id))
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
@@ -523,19 +501,6 @@ struct LocationEditor: View {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/// "Keller → Regal" – der Pfad macht gleiche Namen im flachen Picker
|
||||
/// unterscheidbar.
|
||||
private static func pfad(_ loc: StorageLocation, in all: [StorageLocation]) -> String {
|
||||
let byId = Dictionary(uniqueKeysWithValues: all.map { ($0.id, $0) })
|
||||
var teile = [loc.name]
|
||||
var pid = loc.parentId
|
||||
while let cur = pid, let parent = byId[cur] {
|
||||
teile.insert(parent.name, at: 0)
|
||||
pid = parent.parentId
|
||||
}
|
||||
return teile.joined(separator: " → ")
|
||||
}
|
||||
}
|
||||
|
||||
struct UnitsView: View {
|
||||
@@ -820,8 +785,8 @@ struct CategoryEditor: View {
|
||||
Section {
|
||||
Picker("Übergeordnet", selection: $parentId) {
|
||||
Text("– oberste Ebene –").tag(Int?.none)
|
||||
ForEach(all) { c in
|
||||
Text(CategoryEditor.pfad(c, in: all)).tag(Int?.some(c.id))
|
||||
ForEach(baum(all)) { eintrag in
|
||||
Text(eintrag.label).tag(Int?.some(eintrag.item.id))
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
@@ -896,17 +861,6 @@ struct CategoryEditor: View {
|
||||
self.error = error.localizedDescription
|
||||
}
|
||||
}
|
||||
|
||||
private static func pfad(_ c: CategoryItem, in all: [CategoryItem]) -> String {
|
||||
let byId = Dictionary(uniqueKeysWithValues: all.map { ($0.id, $0) })
|
||||
var teile = [c.name]
|
||||
var pid = c.parentId
|
||||
while let cur = pid, let parent = byId[cur] {
|
||||
teile.insert(parent.name, at: 0)
|
||||
pid = parent.parentId
|
||||
}
|
||||
return teile.joined(separator: " → ")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Eigene Felder je Kategorie
|
||||
|
||||
Reference in New Issue
Block a user