From cfa6a8bb527774adaddfef03be5f45c7ba618dd2 Mon Sep 17 00:00:00 2001 From: Sylvain Bettinelli Date: Fri, 8 May 2026 09:40:34 +0000 Subject: [PATCH] =?UTF-8?q?fix=20CoachWorkoutKit=20Swift=20:=20API=20Worko?= =?UTF-8?q?utKit=20corrig=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compile errors : - WorkoutAlertEnumeration n'existe pas → c'est WorkoutAlert (et il faut passer l'alert via WorkoutStep.alert, pas en param d'IntervalStep) - IntervalStep init est .init(_ purpose:, step: WorkoutStep) — pas de goal ni alert direct, faut wrapper dans WorkoutStep d'abord - WorkoutScheduler.shared.preview(plan) ajouté en iOS 17.4+ → wrap dans if #available(17.4) avec fallback schedule() pour 17.0-17.3 Ajouts : - requestAuthorization() avant preview/schedule (idempotent si déjà accordée) - HeartRateZoneAlert appliqué sur work + rest steps via .alert (style mutable) --- ios/App/App/CoachWorkoutKit.swift | 67 ++++++++++++++++++------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/ios/App/App/CoachWorkoutKit.swift b/ios/App/App/CoachWorkoutKit.swift index 7a8571c..550daf9 100644 --- a/ios/App/App/CoachWorkoutKit.swift +++ b/ios/App/App/CoachWorkoutKit.swift @@ -14,12 +14,12 @@ // repeats: 6, // cooldownMin: 10, // }) -// → { sent: true } si l'user a tapé "Ajouter aux workouts" dans la sheet +// → { sent: true } si la sheet a été présentée et user a tapé Ajouter // → reject avec error string sinon // -// L'app présente une sheet système iOS qui demande à l'user de confirmer -// l'ajout du workout au Watch. Le workout devient alors disponible dans -// Apple Watch → Exercice → Workouts personnalisés → [displayName]. +// Sur iOS 17.4+ : utilise WorkoutScheduler.shared.preview(plan) qui ouvre +// la sheet système iOS 'Ajouter aux workouts'. +// Sur iOS 17.0-17.3 (rare) : fallback schedule() qui ajoute direct. import Foundation import Capacitor @@ -103,50 +103,59 @@ public class CoachWorkoutKitPlugin: CAPPlugin { repeats: Int, cooldownMin: Double ) async throws { - // 1. Warmup step (1 fois) + + // 1. Warmup — un WorkoutStep avec un goal time let warmupStep = WorkoutStep(goal: .time(warmupMin * 60, .seconds)) - // 2. Work + Rest interval block (répété N fois) - var workAlerts: [any WorkoutAlertEnumeration] = [] + // 2. Work step — wrapped dans un IntervalStep avec purpose .work + var workWorkoutStep = WorkoutStep(goal: .time(workMin * 60, .seconds)) if let zone = workHrZone { - workAlerts.append(HeartRateZoneAlert(zone: zone)) + workWorkoutStep.alert = HeartRateZoneAlert(zone: zone) } - let workStep = IntervalStep( - .work, - goal: .time(workMin * 60, .seconds), - alert: workAlerts.first as? (any WorkoutAlertEnumeration) - ) + let workInterval = IntervalStep(.work, step: workWorkoutStep) - var restAlerts: [any WorkoutAlertEnumeration] = [] + // 3. Rest step — IntervalStep purpose .recovery + var restWorkoutStep = WorkoutStep(goal: .time(restMin * 60, .seconds)) if let zone = restHrZone { - restAlerts.append(HeartRateZoneAlert(zone: zone)) + restWorkoutStep.alert = HeartRateZoneAlert(zone: zone) } - let restStep = IntervalStep( - .recovery, - goal: .time(restMin * 60, .seconds), - alert: restAlerts.first as? (any WorkoutAlertEnumeration) - ) + let restInterval = IntervalStep(.recovery, step: restWorkoutStep) - let intervalBlock = IntervalBlock( - steps: [workStep, restStep], - iterations: repeats - ) + // 4. Block répété N fois + let block = IntervalBlock(steps: [workInterval, restInterval], iterations: repeats) - // 3. Cooldown step + // 5. Cooldown let cooldownStep = WorkoutStep(goal: .time(cooldownMin * 60, .seconds)) - // 4. Custom workout + // 6. CustomWorkout let custom = CustomWorkout( activity: activity, location: .outdoor, displayName: displayName, warmup: warmupStep, - blocks: [intervalBlock], + blocks: [block], cooldown: cooldownStep ) - // 5. Plan + preview (présente la sheet système "Ajouter à mes workouts") + // 7. Plan let plan = WorkoutPlan(.custom(custom)) - try await WorkoutScheduler.shared.preview(plan) + + // 8. Request authorization si pas déjà accordée + let authState = await WorkoutScheduler.shared.authorizationState + if authState != .authorized { + _ = try await WorkoutScheduler.shared.requestAuthorization() + } + + // 9. Présenter la sheet système (iOS 17.4+) ou scheduler direct (17.0-17.3) + if #available(iOS 17.4, *) { + try await WorkoutScheduler.shared.preview(plan) + } else { + // Fallback : schedule "now" pour rendre dispo sur Watch + let now = Calendar.current.dateComponents( + [.year, .month, .day, .hour, .minute], + from: Date() + ) + _ = try await WorkoutScheduler.shared.schedule(plan, at: now) + } } }