Verwendungsstatus: in der App umstellen, filtern und nachsehen

Im Einzelstueck steht jetzt ueber dem Verleih ein Abschnitt "Verwendung"
mit vier Symbolen: verfuegbar, in Verwendung, in Reinigung, in Reparatur.
Ein Tipp bucht sofort, ohne "Speichern" - wie beim Verleih, denn alle
Scan-Wege (QR, NFC, vorrania://i/<UID>) landen genau in dieser Ansicht.
Vier Woerter waeren auf einem iPhone zu breit, vier Symbole passen immer;
darunter steht der Name im Klartext samt "seit wann".

Dazu der Verwendungs-Verlauf mit Zeitstempeln und Konto, und in der
Einzelstueck-Liste ein Filter ueber alle vier Zustaende plus die Zeile
unter dem Namen, solange etwas laeuft. Stuecke ohne Verwendungsstatus
fallen aus dem Filter "Verfuegbar" heraus - ein Schraubenzieher ist nicht
verfuegbar, er fuehrt den Zustand gar nicht.

Der Haken je Kategorie sitzt im Kategorie-Editor und gilt beim Bearbeiten
auch fuer die Unterkategorien.

Zwei Dinge, die beim Pruefen am Simulator auffielen: Die Leiste haette
beim Oeffnen jedes Mal einmal ins Leere gebucht, weil onChange auch beim
Laden feuert - dagegen der Abgleich mit dem zuletzt gemeldeten Stand. Und
SQLite liefert Zeitstempel ohne Zeitzone, woran ISO8601DateFormatter
scheitert; in der App stand deshalb der rohe ISO-Text.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-20 22:07:27 +02:00
co-authored by Claude Opus 5
parent b9d097fe96
commit 290ff9341a
5 changed files with 343 additions and 4 deletions
+96 -1
View File
@@ -1079,13 +1079,18 @@ struct CategoryItem: Codable, Identifiable, Hashable {
let name: String
let parentId: Int?
let tracking: String?
/// Ob Einzelstuecke dieser Kategorie einen Verwendungsstatus fuehren.
/// Optional, weil ein aelterer Server das Feld nicht schickt.
var usageTracking: Bool?
enum CodingKeys: String, CodingKey {
case id, name, tracking
case parentId = "parent_id"
case usageTracking = "usage_tracking"
}
var isObject: Bool { tracking == "object" }
var fuehrtVerwendung: Bool { usageTracking ?? false }
}
// MARK: - Hierarchische Stammdaten
@@ -1266,6 +1271,73 @@ struct ItemDocument: Codable, Identifiable, Hashable {
///
/// `daysOverdue` rechnet der Server, damit App und Web nicht getrennt rechnen -
/// nil heisst: ohne Frist, zurueck, oder noch nicht faellig.
/// Woran ein Einzelstueck gerade ist.
///
/// "Verfuegbar" ist bewusst kein Serverwert, sondern das Fehlen eines
/// laufenden Zeitraums - deshalb traegt der Ruhezustand hier `nil`. Absichtlich
/// allgemein und nicht auf Kleidung zugeschnitten: Eine Bohrmaschine auf der
/// Baustelle ist genauso "in Verwendung".
enum VerwendungStatus: String, Codable, CaseIterable, Identifiable, Hashable {
case inUse = "in_use"
case cleaning = "cleaning"
case repair = "repair"
var id: String { rawValue }
var label: String {
switch self {
case .inUse: return "In Verwendung"
case .cleaning: return "In Reinigung"
case .repair: return "In Reparatur"
}
}
var symbol: String {
switch self {
case .inUse: return "figure.walk"
case .cleaning: return "drop"
case .repair: return "wrench.and.screwdriver"
}
}
/// Die vier Schaltstellungen inklusive des Ruhezustands (nil).
static let auswahl: [VerwendungStatus?] = [nil] + allCases.map { Optional($0) }
static func label(_ status: VerwendungStatus?) -> String {
status?.label ?? "Verfügbar"
}
static func symbol(_ status: VerwendungStatus?) -> String {
status?.symbol ?? "checkmark.circle"
}
}
/// Ein Zeitraum in einem Verwendungszustand - laufend oder abgeschlossen.
struct Verwendung: Codable, Identifiable, Hashable {
let id: Int
let itemId: Int
let status: VerwendungStatus
let startedAt: String
/// nil = laeuft noch.
let endedAt: String?
let username: String?
var laeuft: Bool { endedAt == nil }
enum CodingKeys: String, CodingKey {
case id, status, username
case itemId = "item_id"
case startedAt = "started_at"
case endedAt = "ended_at"
}
}
struct VerwendungSetzenRequest: Encodable {
/// nil = verfuegbar. Muss AUCH dann mitgeschickt werden, sonst liest der
/// Server den Vorgabewert und nicht "verfuegbar".
let status: String?
}
struct Loan: Codable, Identifiable, Hashable {
let id: Int
let itemId: Int
@@ -1391,15 +1463,28 @@ struct Item: Codable, Identifiable, Hashable {
/// Swift nimmt den Vorgabewert beim Dekodieren nicht her, es wuerde werfen.
var zubehoer: [ItemKurz]?
var gehoertZu: ItemKurz?
/// Der laufende Verwendungszustand - nil heisst verfuegbar. Anders als beim
/// Verleih bleibt das Stueck dabei im Bestand: getragen ist nicht weg.
///
/// Beide Felder optional, aus demselben Grund wie `zubehoer` oben: ein
/// aelterer Server schickt sie gar nicht.
var verwendung: Verwendung?
/// Ob die Kategorie dieses Stuecks ueberhaupt einen Verwendungsstatus fuehrt.
var verwendungMoeglich: Bool?
/// Zubehoer ohne Optional-Gehampel an der Aufrufstelle.
var teile: [ItemKurz] { zubehoer ?? [] }
var istVerliehen: Bool { loan != nil }
/// Ohne Optional-Gehampel an der Aufrufstelle.
var zeigtVerwendung: Bool { verwendungMoeglich ?? false }
var verwendungStatus: VerwendungStatus? { verwendung?.status }
enum CodingKeys: String, CodingKey {
case id, uid, note, currency, documents, loan, zubehoer
case id, uid, note, currency, documents, loan, zubehoer, verwendung
case gehoertZu = "gehoert_zu"
case verwendungMoeglich = "verwendung_moeglich"
case productId = "product_id"
case locationId = "location_id"
case locationName = "location_name"
@@ -1780,16 +1865,26 @@ struct NewCategoryRequest: Codable {
let name: String
let parentId: Int?
var tracking: String? = nil
/// nil = erbt vom Elternteil bzw. neue Oberkategorie = aus.
var usageTracking: Bool? = nil
enum CodingKeys: String, CodingKey {
case name, tracking
case parentId = "parent_id"
case usageTracking = "usage_tracking"
}
}
struct CategoryUpdateRequest: Codable {
let name: String?
let tracking: String?
/// Wird vom Server in den ganzen Unterbaum uebernommen.
var usageTracking: Bool? = nil
enum CodingKeys: String, CodingKey {
case name, tracking
case usageTracking = "usage_tracking"
}
}
struct NewShopRequest: Codable {