fix(widget): le total retombait à zéro après synchronisation
Le widget affiche « snapshot + file d'attente ». La synchronisation vidait la file sans créditer le snapshot : le total repassait donc à zéro juste après que la saisie ait été enregistrée pour de bon. Le pire moment pour douter de son journal. `flush()` reporte désormais dans le snapshot ce qu'il vient d'envoyer, AVANT de vider la file. Seules les entrées du jour sont créditées — le snapshot porte des totaux quotidiens, y verser une saisie d'hier les fausserait. Le pont web repoussera un snapshot exact au prochain chargement de page ; ce report garde l'affichage juste entre-temps. Les optionnels du snapshot reçoivent `= nil` explicitement : sans valeur par défaut, l'init memberwise de Swift les aurait exigés à l'appel. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -54,14 +54,39 @@ enum CoachQuickSync {
|
||||
}
|
||||
|
||||
if !sent.isEmpty {
|
||||
/* Le snapshot AVANT de vider la file. Le widget affiche
|
||||
« snapshot + file » : vider la file sans créditer le snapshot
|
||||
ferait retomber son total à zéro alors que la saisie vient
|
||||
justement d'être enregistrée. C'est exactement ce qui se passait.
|
||||
|
||||
Le pont web repoussera un snapshot exact au prochain chargement
|
||||
de page ; en attendant, ce report garde l'affichage juste. */
|
||||
credit(queue.filter { sent.contains($0.id) })
|
||||
CoachQuickLog.remove(ids: sent)
|
||||
// Le widget doit cesser d'afficher la flèche d'attente, et son
|
||||
// total doit repasser sur la source serveur.
|
||||
WidgetCenter.shared.reloadAllTimelines()
|
||||
}
|
||||
return sent.count
|
||||
}
|
||||
|
||||
/// Reporte dans le snapshot ce qui vient de partir au serveur.
|
||||
///
|
||||
/// Seules les entrées du JOUR comptent : le snapshot porte des totaux
|
||||
/// quotidiens, et y verser une saisie d'hier les fausserait.
|
||||
private static func credit(_ entries: [CoachQuickEntry]) {
|
||||
let calendar = Calendar.current
|
||||
let today = entries.filter { calendar.isDateInToday($0.at) }
|
||||
guard !today.isEmpty else { return }
|
||||
|
||||
var snapshot = CoachWidgetStore.load()
|
||||
?? CoachWidgetSnapshot(updatedAt: Date(), today: nil, forme: nil)
|
||||
let water = today.filter { $0.ref == "water" }.reduce(0) { $0 + $1.amount }
|
||||
let coffees = today.filter { $0.ref == "coffee" }.count
|
||||
if water > 0 { snapshot.waterMlToday = (snapshot.waterMlToday ?? 0) + water }
|
||||
if coffees > 0 { snapshot.coffeeCountToday = (snapshot.coffeeCountToday ?? 0) + coffees }
|
||||
snapshot.updatedAt = Date()
|
||||
CoachWidgetStore.save(snapshot)
|
||||
}
|
||||
|
||||
private static func post(_ entry: CoachQuickEntry) async -> Bool {
|
||||
var request = URLRequest(url: base.appendingPathComponent("api/drinks"))
|
||||
request.httpMethod = "POST"
|
||||
|
||||
@@ -41,8 +41,8 @@ enum CoachWidgetStore {
|
||||
/// le widget n'a pas d'accès réseau, tout vient de ce snapshot poussé par l'app.
|
||||
struct CoachWidgetSnapshot: Codable {
|
||||
var updatedAt: Date
|
||||
var today: TodaySession?
|
||||
var forme: FormeScore?
|
||||
var today: TodaySession? = nil
|
||||
var forme: FormeScore? = nil
|
||||
|
||||
/// Boissons du jour DÉJÀ connues du serveur, en millilitres et en nombre de
|
||||
/// cafés. Le widget de saisie rapide y ajoute ce qui attend encore dans la
|
||||
@@ -50,14 +50,14 @@ struct CoachWidgetSnapshot: Codable {
|
||||
/// « 1,5 L » tant que l'app n'a pas resynchronisé, et l'utilisateur
|
||||
/// douterait de saisies pourtant enregistrées.
|
||||
/// Optionnels : un snapshot écrit par une version antérieure reste lisible.
|
||||
var waterMlToday: Double?
|
||||
var coffeeCountToday: Int?
|
||||
var waterMlToday: Double? = nil
|
||||
var coffeeCountToday: Int? = nil
|
||||
|
||||
/// Énergie du jour et objectif, poussés par l'app depuis le journal.
|
||||
/// `kcalGoal` vient des objectifs nutritionnels réels (1950 au 06/08/2026) :
|
||||
/// il n'est pas écrit en dur ici, pour qu'un changement d'objectif suive.
|
||||
var kcalToday: Double?
|
||||
var kcalGoal: Double?
|
||||
var kcalToday: Double? = nil
|
||||
var kcalGoal: Double? = nil
|
||||
|
||||
|
||||
/// Séance planifiée du jour (nil = jour OFF / pas de séance).
|
||||
|
||||
Reference in New Issue
Block a user