fix CoachWorkoutKit Swift : API WorkoutKit corrigée

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)
This commit is contained in:
Sylvain Bettinelli
2026-05-08 09:40:34 +00:00
parent 2d3e149c0a
commit cfa6a8bb52

View File

@@ -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)
}
}
}