iOS: eigene, gestaltbare App-Uebersicht mit nativen Diagrammen

Der Start-Tab spiegelte bisher fest die Web-Dashboards - dieselbe gespeicherte
Anordnung, und Diagramme gab es nur den Hinweis "im Web". Das war der Punkt,
der geaergert hat.

Jetzt ist der Modus je Server umschaltbar: "Web-Uebersicht spiegeln" (weiter
Standard, damit nach dem Update nichts ueberrascht) oder "Eigene
App-Uebersicht". Die eigene Uebersicht liegt nur auf dem Geraet (pro Server),
unabhaengig vom Web und nicht synchronisiert. Beim ersten Umschalten entsteht
gleich eine sinnvolle Startanordnung.

Sie funktioniert wie im Web, nur fuers Telefon: mehrere Dashboards, Karten
einspaltig untereinander, im Bearbeiten-Modus hinzufuegen, per Ziehen sortieren
und loeschen; Artikelkarten bekommen ihren Artikel zugewiesen. Anzeigen und
Bearbeiten sind getrennt - so laufen Sortieren und Loeschen sauber, statt an
Sektionsgrenzen zu haken.

Die Diagramme sind nativ mit Swift Charts: Ablauf- und Kategorien-Anteile
(Ring ab iOS 17, sonst ein 100-%-Balken - das Ziel ist iOS 16, deshalb kein
stilles Anheben), Kategorien nach Zustand als gestapelte Balken, Bestands- und
Artikelverlauf als Linie, Ein-/Auslagerungen als gruppierte Balken. Dieselben
Endpunkte wie das Web-Dashboard, kein Backend-Eingriff. Der "gibt es nur im
Web"-Hinweis faellt damit weg - auch beim Spiegeln werden die Diagramme jetzt
nativ gezeichnet.

Geprueft: Build; alle vier Diagramm-Modelle gegen echte Serverantworten
dekodiert (auch der Zeitstempel mit Z und Sekundenbruchteilen); refactorte
DashboardCardView ohne alte Aufrufstellen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-23 21:29:37 +02:00
parent 96172c6fa0
commit 580afcc133
8 changed files with 856 additions and 69 deletions

View File

@@ -516,6 +516,69 @@ struct DashboardList: Codable {
}
}
// MARK: - Diagrammdaten (Übersicht)
/// Artikeleinheiten je Ablaufzustand (GET /dashboard/expiry-split).
struct ExpirySplit: Codable {
let ok: Double
let soon: Double
let expired: Double
let noDate: Double
enum CodingKeys: String, CodingKey {
case ok, soon, expired
case noDate = "no_date"
}
}
/// Anteil einer Kategorie am Bestand (GET /dashboard/by-category).
struct CategoryShare: Codable, Identifiable {
let categoryId: Int?
let name: String
let articleUnits: Double
let ok: Double
let soon: Double
let expired: Double
let noDate: Double
var id: Int { categoryId ?? -1 }
enum CodingKeys: String, CodingKey {
case name, ok, soon, expired
case categoryId = "category_id"
case articleUnits = "article_units"
case noDate = "no_date"
}
}
/// Ein Punkt des Bestandsverlaufs (GET /dashboard/timeline).
struct TimelinePoint: Codable, Identifiable {
let at: String
let articleUnits: Double
var id: String { at }
enum CodingKeys: String, CodingKey {
case at
case articleUnits = "article_units"
}
}
/// Ein- und Auslagerungen je Zeitpunkt (GET /dashboard/activity).
struct ActivityPoint: Codable, Identifiable {
let at: String
let checkedIn: Int
let checkedOut: Int
var id: String { at }
enum CodingKeys: String, CodingKey {
case at
case checkedIn = "checked_in"
case checkedOut = "checked_out"
}
}
// MARK: - Stammdaten
/// Gebinde (Packung, Glas, ...) mit Einzahl und Mehrzahl.