diff --git a/ios/Sources/DashboardCards.swift b/ios/Sources/DashboardCards.swift index 72569ca..42ddb4e 100644 --- a/ios/Sources/DashboardCards.swift +++ b/ios/Sources/DashboardCards.swift @@ -291,7 +291,7 @@ struct ExpiryCard: View { HStack { VStack(alignment: .leading, spacing: 1) { Text(item.productName).font(.callout) - Text("MHD \(display.formatBestBefore(item.bestBefore, precision: item.bestBeforePrecision))") + Text("\(item.fristLabel) \(display.formatBestBefore(item.warnDate, precision: item.fristPrecision))") .font(.caption2).foregroundStyle(.secondary) } Spacer() diff --git a/ios/Sources/ListViews.swift b/ios/Sources/ListViews.swift index 535cd63..52ca28f 100644 --- a/ios/Sources/ListViews.swift +++ b/ios/Sources/ListViews.swift @@ -146,7 +146,7 @@ struct ExpiringView: View { HStack { VStack(alignment: .leading, spacing: 2) { Text(item.productName) - Text("MHD \(display.formatBestBefore(item.bestBefore, precision: item.bestBeforePrecision)) · \(articleAmount(item))") + Text("\(item.fristLabel) \(display.formatBestBefore(item.warnDate, precision: item.fristPrecision)) · \(articleAmount(item))") .font(.caption).foregroundStyle(.secondary) } Spacer() diff --git a/ios/Sources/Models.swift b/ios/Sources/Models.swift index 9cc84a3..3e0948e 100644 --- a/ios/Sources/Models.swift +++ b/ios/Sources/Models.swift @@ -617,8 +617,19 @@ struct ExpiringItem: Codable, Identifiable { let productName: String let quantity: Double let baseUnit: String - let bestBefore: String + /// Darf fehlen! Eine angebrochene Packung ohne aufgedrucktes MHD hat nur ein + /// Verbrauchsdatum - und genau die gehoert in diese Liste. Stand hier frueher + /// ein nicht-optionaler String, scheiterte das Entschluesseln der GANZEN + /// Liste an einer einzigen solchen Charge, samt Erinnerungen. + let bestBefore: String? let bestBeforePrecision: String? + let openedOn: String? + let consumeBy: String? + /// Das Datum, nach dem gewarnt wird: das fruehere von MHD und + /// Verbrauchsdatum. Immer gesetzt - der Server rechnet es aus. + let warnDate: String + /// "best_before" oder "consume_by" - sagt, welches der beiden Daten gewann. + let warnSource: String? let daysLeft: Int let packageSize: Double? let packageLabel: String? @@ -627,6 +638,17 @@ struct ExpiringItem: Codable, Identifiable { var id: Int { lotId } + /// Ist die Packung angebrochen und draengt deshalb? + var istAngebrochen: Bool { warnSource == "consume_by" } + + /// Beschriftung vor dem Datum. "MHD 05.10." und "verbrauchen bis 05.10." + /// sind zwei verschiedene Aussagen, und die Liste zeigt beide nebeneinander. + var fristLabel: String { istAngebrochen ? "verbrauchen bis" : "MHD" } + + /// Genauigkeit des angezeigten Datums. Ein Verbrauchsdatum ist immer + /// taggenau, auch wenn auf der Packung nur ein Monat stand. + var fristPrecision: String? { istAngebrochen ? "day" : bestBeforePrecision } + /// Restlaufzeit als kurzer Text. „0 Tage" ergibt keinen Sinn - am Ablauftag /// selbst steht „heute". Karte und Liste nutzen dieselbe Formulierung. var restlaufzeitText: String { @@ -644,6 +666,10 @@ struct ExpiringItem: Codable, Identifiable { case baseUnit = "base_unit" case bestBefore = "best_before" case bestBeforePrecision = "best_before_precision" + case openedOn = "opened_on" + case consumeBy = "consume_by" + case warnDate = "warn_date" + case warnSource = "warn_source" case daysLeft = "days_left" case packageSize = "package_size" case packageLabel = "package_label" diff --git a/ios/Sources/NotificationScheduler.swift b/ios/Sources/NotificationScheduler.swift index 5908076..f72d63c 100644 --- a/ios/Sources/NotificationScheduler.swift +++ b/ios/Sources/NotificationScheduler.swift @@ -75,7 +75,9 @@ enum ExpiryPlanner { } for item in snapshot.expiring { - guard let mhd = parseTag(item.bestBefore, calendar: calendar) else { continue } + // Das Warndatum, nicht das MHD: Eine angebrochene Packung ohne + // aufgedrucktes Datum braucht die Erinnerung am dringendsten. + guard let mhd = parseTag(item.warnDate, calendar: calendar) else { continue } let mhdTag = calendar.startOfDay(for: mhd) // Welche Regeln gelten fuer dieses Produkt? Kategorie ersetzt Allgemeine: