import SwiftUI /// Eine Zeile einer flach ausgelegten Baumliste, mit ihrer Tiefe. /// /// Lagerorte und Kategorien sind Baeume, kommen vom Server aber als flache /// Liste nach Namen sortiert. Daraus wird eine Auswahl, in der "Garage → Fach A" /// und "Keller → Fach A" irgendwo zwischen allem anderen stehen - Geschwister /// und Kinder finden nie zusammen. Diese Reihenfolge stellt das her. struct Baumzeile: Identifiable { let item: T let tiefe: Int var id: T.ID { item.id } /// Name mit Einrueckung aus fuehrenden Leerzeichen. /// /// Nur fuer aufklappende Menues, wo man ausser Text nichts abliefern kann. /// Der Nachteil bleibt dort bestehen: Bricht ein langer Name um, faengt die /// zweite Zeile ganz links an. Wo es geht, `BaumZeile` nehmen. 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: View { let zeile: Baumzeile 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. /// /// Waisen - deren Elternteil weggefiltert oder geloescht ist - gelten als /// oberste Ebene. Ohne diese Regel verschwaenden sie lautlos aus der Auswahl. func baum(_ liste: [T]) -> [Baumzeile] { let ids = Set(liste.map(\.id)) var ergebnis: [Baumzeile] = [] func gehe(_ knoten: T, _ tiefe: Int) { ergebnis.append(Baumzeile(item: knoten, tiefe: tiefe)) for kind in liste.filter({ $0.parentId == knoten.id }) { gehe(kind, tiefe + 1) } } for wurzel in liste.filter({ $0.parentId == nil || !ids.contains($0.parentId!) }) { gehe(wurzel, 0) } return ergebnis }