From 80aa857bb03d90e58994ce5674714ee4eafcf8ae Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Fri, 31 Jul 2026 22:45:09 +0200 Subject: [PATCH] iOS: Diagramm-Einstellungen im lokalen App-Editor Der lokale Uebersicht-Editor kann jetzt pro Diagramm-Karte einstellen, wie im Web-Editor: - Ablauf-Ring: 'Ohne MHD einbeziehen' - Kategorien-Ring: 'Detailansicht' (alle einzeln) + 'Kategorie-Tiefe' AppCard speichert die Optionen (optional -> alte Uebersichten dekodieren weiter) und reicht sie an DashboardCardView durch. Co-Authored-By: Claude Opus 4.8 --- ios/Sources/AppDashboards.swift | 12 ++++- ios/Sources/LocalOverview.swift | 85 +++++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/ios/Sources/AppDashboards.swift b/ios/Sources/AppDashboards.swift index f988ece..6f73c10 100644 --- a/ios/Sources/AppDashboards.swift +++ b/ios/Sources/AppDashboards.swift @@ -16,11 +16,21 @@ struct AppCard: Codable, Identifiable, Equatable { let id: UUID var type: String var productId: Int? + // Diagramm-Einstellungen (nur fuer bestimmte Diagramme relevant). Optional, + // damit aeltere gespeicherte Uebersichten ohne diese Schluessel weiter + // dekodieren. Bedeutung wie im Web-Editor: + var mitOhneMhd: Bool? // Ablauf-Ring: „Ohne MHD" einbeziehen (nil = ja) + var detail: Bool? // Kategorien-Ring: Detailansicht, alle einzeln (nil = nein) + var tiefe: Int? // Kategorien-Ring: Tiefe (nil = feinste Ebene) - init(id: UUID = UUID(), type: String, productId: Int? = nil) { + init(id: UUID = UUID(), type: String, productId: Int? = nil, + mitOhneMhd: Bool? = nil, detail: Bool? = nil, tiefe: Int? = nil) { self.id = id self.type = type self.productId = productId + self.mitOhneMhd = mitOhneMhd + self.detail = detail + self.tiefe = tiefe } } diff --git a/ios/Sources/LocalOverview.swift b/ios/Sources/LocalOverview.swift index 76f10a0..e0c4f02 100644 --- a/ios/Sources/LocalOverview.swift +++ b/ios/Sources/LocalOverview.swift @@ -59,7 +59,10 @@ struct LocalOverview: View { ForEach(aktives.cards) { karte in Section { DashboardCardView(type: karte.type, productId: karte.productId, - stand: stand) { stand += 1 } + stand: stand, + detail: karte.detail ?? false, + tiefe: karte.tiefe, + mitOhneMhd: karte.mitOhneMhd ?? true) { stand += 1 } } header: { Text(titel(karte)) } @@ -82,14 +85,12 @@ struct LocalOverview: View { } Section { ForEach(aktives?.cards ?? []) { karte in - HStack { - VStack(alignment: .leading, spacing: 2) { - Text(CardCatalog.titel(karte.type)) - if CardCatalogList.kind(for: karte.type)?.needsProduct == true { - artikelWahl(fuer: karte) - } + VStack(alignment: .leading, spacing: 6) { + Text(CardCatalog.titel(karte.type)) + if CardCatalogList.kind(for: karte.type)?.needsProduct == true { + artikelWahl(fuer: karte) } - Spacer() + diagrammEinstellungen(fuer: karte) } } .onDelete(perform: loesche) @@ -158,6 +159,53 @@ struct LocalOverview: View { } } + // MARK: - Diagramm-Einstellungen (nur bestimmte Ringe, wie im Web-Editor) + + private struct TiefeOption: Identifiable { + let tiefe: Int? + let label: String + var id: String { label } + } + + private static let tiefeOptionen: [TiefeOption] = [ + .init(tiefe: nil, label: "Feinste (jede Kategorie einzeln)"), + .init(tiefe: 1, label: "Nur oberste Stufe"), + .init(tiefe: 2, label: "Bis 2. Stufe"), + .init(tiefe: 3, label: "Bis 3. Stufe"), + ] + + @ViewBuilder private func diagrammEinstellungen(fuer karte: AppCard) -> some View { + switch karte.type { + case "expiry-donut": + Toggle(isOn: Binding( + get: { karte.mitOhneMhd ?? true }, + set: { setzeMitOhneMhd(karte, $0) } + )) { + Text("„Ohne MHD“ einbeziehen").font(.caption) + } + case "category-donut": + Toggle(isOn: Binding( + get: { karte.detail ?? false }, + set: { setzeDetail(karte, $0) } + )) { + Text("Detailansicht (alle einzeln)").font(.caption) + } + Menu { + ForEach(Self.tiefeOptionen) { opt in + Button(opt.label) { setzeTiefe(karte, opt.tiefe) } + } + } label: { + HStack(spacing: 4) { + Text("Tiefe:").font(.caption).foregroundStyle(.secondary) + Text(Self.tiefeOptionen.first { $0.tiefe == karte.tiefe }?.label ?? "Feinste") + .font(.caption).foregroundStyle(Color.marke) + } + } + default: + EmptyView() + } + } + // MARK: - Datenänderungen (alle sofort gespeichert) private func mutiere(_ block: (inout AppDashboard) -> Void) { @@ -169,15 +217,32 @@ struct LocalOverview: View { private func fuegeHinzu(_ karte: AppCard) { mutiere { $0.cards.append(karte) } } - private func setzeProdukt(_ karte: AppCard, _ pid: Int?) { + /// Ändert genau eine Karte und lädt die Anzeige neu. + private func mutiereKarte(_ karte: AppCard, _ block: (inout AppCard) -> Void) { mutiere { dash in if let i = dash.cards.firstIndex(where: { $0.id == karte.id }) { - dash.cards[i].productId = pid + block(&dash.cards[i]) } } stand += 1 } + private func setzeProdukt(_ karte: AppCard, _ pid: Int?) { + mutiereKarte(karte) { $0.productId = pid } + } + + private func setzeMitOhneMhd(_ karte: AppCard, _ wert: Bool) { + mutiereKarte(karte) { $0.mitOhneMhd = wert } + } + + private func setzeDetail(_ karte: AppCard, _ wert: Bool) { + mutiereKarte(karte) { $0.detail = wert } + } + + private func setzeTiefe(_ karte: AppCard, _ wert: Int?) { + mutiereKarte(karte) { $0.tiefe = wert } + } + private func loesche(at offsets: IndexSet) { mutiere { $0.cards.remove(atOffsets: offsets) } } private func verschiebe(from: IndexSet, to: Int) { mutiere { $0.cards.move(fromOffsets: from, toOffset: to) } }