fix(watch): transmet les blocs de routine, pas seulement l'état coché
pushToWatch ne lisait que `date` et `done` dans l'appel JS et ignorait `blocks`. La montre recevait donc un snapshot sans aucun bloc et restait sur son écran vide « Ouvre l'app Coach sur l'iPhone » — alors que le log confirmait que l'envoi partait bien (constaté sur device le 2026-08-03). sanitizeBlocks ne garde que les clés attendues en types property-list stricts : updateApplicationContext lève une exception ObjC sur tout ce qui ne l'est pas, et les entiers venus du JS arrivent en NSNumber — un `as? Int` direct échoue quand JavaScriptCore les passe en double (même piège que le score perdu dans CoachWidgetBridge). Le log distingue désormais blocs transmis et blocs faits : « 0 blocs » était ambigu et désignait le compte des cochés, pas celui des blocs envoyés. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -54,10 +54,14 @@ public class CoachRoutineBridgePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
|
||||
// MARK: - JS → natif
|
||||
|
||||
/// `pushToWatch({ date: "2026-08-03", done: ["hanches", ...] })`
|
||||
/// `pushToWatch({ date, done: [...], blocks: [{id, num, title, duration_min, moment}] })`
|
||||
///
|
||||
/// Les blocs voyagent avec l'état : la montre n'a aucune liste codée en dur,
|
||||
/// modifier la routine côté web ne demande donc pas de rebuild watchOS.
|
||||
@objc func pushToWatch(_ call: CAPPluginCall) {
|
||||
let date = call.getString("date") ?? Self.todayISO()
|
||||
let done = call.getArray("done", String.self) ?? []
|
||||
let blocks = Self.sanitizeBlocks(call.getArray("blocks") as? [[String: Any]] ?? [])
|
||||
|
||||
guard WCSession.isSupported() else {
|
||||
call.resolve(["pushed": false, "reason": "WCSession non supporté"])
|
||||
@@ -75,10 +79,10 @@ public class CoachRoutineBridgePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
|
||||
do {
|
||||
try session.updateApplicationContext([
|
||||
"routineSnapshot": ["date": date, "done": done]
|
||||
"routineSnapshot": ["date": date, "done": done, "blocks": blocks]
|
||||
])
|
||||
routineLog.info("routine poussée vers la Watch (\(done.count, privacy: .public) blocs)")
|
||||
call.resolve(["pushed": true, "count": done.count])
|
||||
routineLog.info("routine poussée vers la Watch : \(blocks.count, privacy: .public) blocs, \(done.count, privacy: .public) faits")
|
||||
call.resolve(["pushed": true, "blocks": blocks.count, "done": done.count])
|
||||
} catch {
|
||||
routineLog.error("updateApplicationContext a échoué : \(error.localizedDescription, privacy: .public)")
|
||||
call.reject("Envoi vers la Watch impossible : \(error.localizedDescription)")
|
||||
@@ -151,6 +155,23 @@ public class CoachRoutineBridgePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
}.resume()
|
||||
}
|
||||
|
||||
/// Ne garde que les clés attendues, en types property-list stricts.
|
||||
///
|
||||
/// Deux raisons : `updateApplicationContext` rejette (exception ObjC) tout
|
||||
/// ce qui n'est pas plist-compatible, et les entiers venus du JS arrivent en
|
||||
/// `NSNumber` — un `as? Int` direct échoue quand JavaScriptCore les a passés
|
||||
/// en double. Même piège que le score perdu dans `CoachWidgetBridge`.
|
||||
private static func sanitizeBlocks(_ raw: [[String: Any]]) -> [[String: Any]] {
|
||||
raw.compactMap { b in
|
||||
guard let id = b["id"] as? String, let title = b["title"] as? String else { return nil }
|
||||
var out: [String: Any] = ["id": id, "title": title]
|
||||
out["num"] = (b["num"] as? NSNumber)?.intValue ?? 0
|
||||
out["duration_min"] = (b["duration_min"] as? NSNumber)?.intValue ?? 0
|
||||
out["moment"] = (b["moment"] as? String) ?? "matin"
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
private static func todayISO() -> String {
|
||||
let fmt = DateFormatter()
|
||||
fmt.dateFormat = "yyyy-MM-dd"
|
||||
|
||||
Reference in New Issue
Block a user