// // TankEditor.swift // GasTankAR // // Created by Dennis Nemec on 25.08.26. // import SwiftUI /// Wiederverwendbare Auswahl für die Tank-Eigenschaften (Größe, Farbe /// und Aufstellungsart). Die verfügbaren Optionen /// stammen dynamisch aus dem `TankCatalog`. struct TankEditor: View { @Binding var tank: Tank @Environment(\.tankCatalog) private var catalog /// Für die aktuelle Aufstellungsart verfügbare Größen. private var availableSizes: [TankSize] { catalog.sizes(for: tank.placement) } /// Für aktuelle Größe & Aufstellungsart verfügbare Farben. private var availableColors: [TankColor] { catalog.colors(for: tank.size, placement: tank.placement) } var body: some View { Picker("Größe", selection: $tank.size) { ForEach(availableSizes) { size in Text(catalog.displayName(for: size)).tag(size) } } Picker("Farbe", selection: $tank.color) { ForEach(availableColors) { color in Text(catalog.displayName(for: color)).tag(color) } } VStack(alignment: .leading, spacing: 8) { Text("Aufstellungsart") HStack(spacing: 12) { ForEach(catalog.placements) { placement in PlacementOption( placement: placement, isSelected: tank.placement == placement ) { tank.placement = placement } } } } .padding(.vertical, 4) // Auswahl bei jeder Änderung auf eine gültige Katalog-Variante bringen … .onChange(of: tank.placement) { _, _ in normalizeSelection() } .onChange(of: tank.size) { _, _ in normalizeSelection() } // … und Altdaten beim Öffnen selbstheilen. .onAppear { normalizeSelection() } } /// Sorgt dafür, dass die aktuelle Auswahl einer existierenden Definition /// entspricht, und setzt die „nur Deckel"-Option außerhalb unterirdischer /// Tanks zurück. private func normalizeSelection() { let normalized = catalog.normalized(tank) if normalized != tank { tank = normalized } if tank.placement != .belowGround && tank.showLidOnly { tank.showLidOnly = false } } } /// Auswahlkachel für eine Aufstellungsart mit Icon und umrahmter Auswahl. private struct PlacementOption: View { let placement: TankPlacement let isSelected: Bool let action: () -> Void var body: some View { Button(action: action) { VStack(spacing: 8) { Image(placement.imageName) .renderingMode(.template) .resizable() .scaledToFit() .foregroundStyle(Color.accentColor) .frame(height: 72) .scaleEffect(1.25) .padding(8) Text(placement.displayName) .font(.caption) .foregroundStyle(isSelected ? .primary : .secondary) } .frame(maxWidth: .infinity) .padding(8) .background( (isSelected ? Color.accentColor.opacity(0.12) : Color.clear), in: .rect(cornerRadius: 12) ) .overlay { RoundedRectangle(cornerRadius: 12) .stroke( isSelected ? Color.accentColor : Color.secondary.opacity(0.4), lineWidth: isSelected ? 2 : 1 ) } .contentShape(.rect(cornerRadius: 12)) } .buttonStyle(.plain) } } #Preview { @Previewable @State var tank = Tank() return Form { Section("Tankauswahl") { TankEditor(tank: $tank) } } }