feat: redesign player with Dynamic Island, compact timer, and fix Live Activity timer drift #2

Merged
millianlmx merged 18 commits from revamp-timer-video-layout into main 2026-05-23 12:24:34 +02:00
2 changed files with 730 additions and 0 deletions
Showing only changes of commit 349a96379e - Show all commits

View File

@@ -0,0 +1,727 @@
import Foundation
struct MockPrograms {
static let all: [WorkoutProgram] = _build()
}
extension MockPrograms {
private static func _build() -> [WorkoutProgram] {
let block = TabataBlockBuilder()
return [
// Upper Body Free
_program("681616f7-97b8-4998-8f56-b327e3aa552d",
"Épaules & Bras Doux", "Gentle Shoulders & Arms",
"Programme débutant pour renforcer doucement les épaules et les bras.",
"upper-body", "Beginner", "#4A90D9", 90,
blocks: [
block(1,
ex1("Cercles bras tendus", "Arm circles",
"Gardez les bras à hauteur d'épaules, petits puis grands cercles",
"Keep arms at shoulder height, small then large circles",
"Cercles plus petits", "Smaller circles",
"Cercles plus grands et plus rapides", "Larger and faster circles"),
ex2("Élévations latérales", "Lateral raises",
"Montez lentement les bras sur le côté, paumes vers le bas",
"Raise arms slowly to the sides, palms facing down",
"Sans charge, amplitude réduite", "No weight, reduced range",
"Avec bouteilles d'eau", "With water bottles")),
block(2,
ex1("Flexions au mur", "Wall push-ups",
"Mains écartées largeur épaules, descendez lentement",
"Hands shoulder-width apart, lower slowly",
"Plus près du mur", "Closer to the wall",
"Push-ups au sol sur les genoux", "Knee push-ups on floor"),
ex2("Press épaules sans charge", "Shoulder press no weight",
"Poussez au-dessus de la tête, coudes à 90° au départ",
"Push overhead, elbows at 90° to start",
"Amplitude réduite", "Reduced range",
"Avec légères charges", "With light weights")),
block(3,
ex1("Shrugs épaules", "Shoulder shrugs",
"Montez les épaules vers les oreilles, maintenez 2 secondes",
"Shrug shoulders toward ears, hold 2 seconds",
"Sans maintien", "No hold",
"Avec charge", "With weight"),
ex2("Rotation poignets", "Wrist circles",
"Rotations lentes dans les deux sens pour préparer les avant-bras",
"Slow rotations both directions to prepare forearms",
"Amplitude réduite", "Reduced range",
"Avec poings serrés", "With clenched fists")),
]),
_program("11168ec3-531d-4097-9b90-fb41689a9b63",
"Dos & Biceps Initiation", "Back & Biceps Initiation",
"Initiation au renforcement du dos et des biceps avec des mouvements simples et accessibles.",
"upper-body", "Beginner", "#4A90D9", 85,
blocks: [
block(1,
ex1("Tirage élastique assis", "Seated band row",
"Tirez les coudes en arrière, serrez les omoplates",
"Pull elbows back, squeeze shoulder blades",
"Élastique léger, amplitude réduite", "Light band, reduced range",
"Élastique plus tendu", "Tighter band"),
ex2("Curl biceps debout", "Standing bicep curls",
"Coudes collés au corps, montez et descendez lentement",
"Elbows pinned to body, curl up and down slowly",
"Sans charge, amplitude partielle", "No weight, partial range",
"Avec bouteilles d'eau", "With water bottles")),
block(2,
ex1("Superman au sol", "Superman hold",
"Levez bras et jambes simultanément, maintenez 3 secondes",
"Lift arms and legs together, hold 3 seconds",
"Bras seuls ou jambes seules", "Arms only or legs only",
"Superman alterné", "Alternating superman"),
ex2("Tirage menton imaginaire", "Upright row mime",
"Tirez les coudes vers le haut le long du corps",
"Pull elbows up along the body",
"Sans charge, mouvement lent", "No weight, slow movement",
"Avec légère charge", "With light weight")),
block(3,
ex1("Rétraction omoplates", "Scapular retraction",
"Serrez les omoplates ensemble, maintenez 3 secondes",
"Squeeze shoulder blades together, hold 3 seconds",
"Assis, sans résistance", "Seated, no resistance",
"Avec élastique", "With band"),
ex2("Flexion poignets", "Wrist curls",
"Fléchissez les poignets vers le haut, avant-bras sur les cuisses",
"Flex wrists upward, forearms on thighs",
"Sans charge", "No weight",
"Avec légère charge", "With light weight")),
]),
_program("87d53233-3fa7-4fa7-bba3-e5ab1a5d5931",
"Haut du Corps Tonus", "Upper Body Tone",
"Programme intermédiaire pour tonifier l'ensemble du haut du corps. Alternance push/pull.",
"upper-body", "Intermediate", "#4A90D9", 120,
blocks: [
block(1,
ex1("Push-ups classiques", "Standard push-ups",
"Corps gainé, descendez jusqu'au sol, remontez en poussant fort",
"Plank body, lower to floor, push up strong",
"Sur les genoux", "On knees",
"Pieds surélevés", "Feet elevated"),
ex2("Dips sur chaise", "Chair dips",
"Mains sur le bord d'une chaise, descendez les coudes à 90°",
"Hands on chair edge, lower elbows to 90°",
"Pieds plus près, amplitude réduite", "Feet closer, reduced range",
"Pieds surélevés", "Feet elevated")),
block(2,
ex1("Pompes diamant", "Diamond push-ups",
"Mains rapprochées sous la poitrine, pouces et index forment un diamant",
"Hands close under chest, thumbs and index form a diamond",
"Écartement plus large", "Wider hand position",
"Avec pause en bas", "With bottom pause"),
ex2("Pike push-ups", "Pike push-ups",
"Hanches hautes, descendez le front vers le sol",
"Hips high, lower forehead toward floor",
"Amplitude réduite", "Reduced range",
"Pieds surélevés", "Feet elevated")),
block(3,
ex1("Burpees sans saut", "Burpee no jump",
"Descendez au sol, remontez en position debout, pas de saut",
"Lower to floor, stand back up, no jump",
"Sans push-up au sol", "No push-up on floor",
"Burpees complets avec saut", "Full burpees with jump"),
ex2("Mountain climbers", "Mountain climbers",
"Ramenez alternativement les genoux vers la poitrine en position de planche",
"Alternate driving knees to chest in plank position",
"Plus lent", "Slower",
"Plus rapide", "Faster")),
]),
_program("9fd7f33c-2502-4f8f-be27-c15907daded0",
"Upper Body Burn", "Upper Body Burn",
"Programme avancé haute intensité. Push-ups, dips, et mouvements explosifs.",
"upper-body", "Advanced", "#4A90D9", 160,
blocks: [
block(1,
ex1("Push-ups clap", "Clap push-ups",
"Explosez vers le haut, tapez les mains avant de replonger",
"Explode upward, clap hands before landing",
"Push-ups rapides sans clap", "Fast push-ups no clap",
"Avec poids lesté", "With weighted vest"),
ex2("Explosive dips", "Explosive dips",
"Poussez fort pour décoller les mains de la chaise",
"Push hard to lift hands off chair",
"Dips contrôlés", "Controlled dips",
"Avec poids sur les cuisses", "With weight on lap")),
block(2,
ex1("Archer push-ups", "Archer push-ups",
"Un bras tendu sur le côté, l'autre fléchit pour la pompe",
"One arm extended to side, other bends for push-up",
"Écartement réduit", "Reduced spread",
"Pompe à un bras complète", "Full one-arm push-up"),
ex2("Pike push-ups explosifs", "Explosive pike push-ups",
"Poussez explosivement hors du sol en position pike",
"Push explosively off floor in pike position",
"Pike push-ups contrôlés", "Controlled pike push-ups",
"Handstand push-ups contre mur", "Wall handstand push-ups")),
block(3,
ex1("Burpees complets", "Full burpees",
"Saut explosif en haut, va-et-vient complet au sol",
"Explosive jump at top, full down-and-up",
"Sans saut ni push-up", "No jump or push-up",
"Burpee pull-ups si barre disponible", "Burpee pull-ups if bar available"),
ex2("Spiderman push-ups", "Spiderman push-ups",
"Ramenez le genou vers le coude pendant la descente, alternez",
"Drive knee to elbow on the way down, alternate",
"Push-ups classiques", "Standard push-ups",
"Avec résistance élastique", "With band resistance")),
]),
// Lower Body Free
_program("22d65930-a9ff-49b2-a8f4-8c4c7068a8cf",
"Jambes Légères", "Light Legs",
"Programme débutant pour activer les jambes en douceur.",
"lower-body", "Beginner", "#9B59B6", 95,
blocks: [
block(1,
ex1("Squats au mur", "Wall sit squats",
"Dos contre le mur, descendez à 90°, maintenez",
"Back against wall, lower to 90°, hold",
"Squats libres sans mur", "Free squats without wall",
"Wall sit statique 20s", "Static wall sit 20s"),
ex2("Marche sur place montées genoux", "High knee marches",
"Lever les genoux haut, alternance droite-gauche",
"Lift knees high, alternate right-left",
"Plus lent, genoux moins hauts", "Slower, lower knees",
"Plus rapide avec saut léger", "Faster with light bounce")),
block(2,
ex1("Fentes stationnaires", "Stationary lunges",
"Un pas en avant, descendez le genou arrière, remontez",
"Step forward, lower back knee, stand up",
"Amplitude réduite", "Reduced range",
"Fentes marchées", "Walking lunges"),
ex2("Calf raises", "Calf raises",
"Montez sur la pointe des pieds, redescendez lentement",
"Rise onto toes, lower slowly",
"Les deux pieds, amplitude réduite", "Both feet, reduced range",
"Un pied à la fois", "One foot at a time")),
block(3,
ex1("Glute bridge", "Glute bridges",
"Allongé, pieds au sol, montez les hanches en serrant les fessiers",
"Lying down, feet on floor, raise hips squeezing glutes",
"Amplitude réduite", "Reduced range",
"Single leg bridge", "Bridge sur une jambe"),
ex2("Clamshell", "Clamshells",
"Sur le côté, genoux fléchis, ouvrez le genou du haut",
"On side, knees bent, open top knee",
"Amplitude réduite", "Reduced range",
"Avec élastique", "With band")),
]),
_program("6eb4bfc2-0f6e-4784-a6d1-3a812341c434",
"Fessiers & Cuisses Doux", "Gentle Glutes & Thighs",
"Renforcement doux des fessiers et cuisses.",
"lower-body", "Beginner", "#9B59B6", 90,
blocks: [
block(1,
ex1("Squats sumo", "Sumo squats",
"Pieds écartés, pointes vers l'extérieur, descendez lentement",
"Feet wide, toes out, lower slowly",
"Amplitude réduite", "Reduced range",
"Avec poids au sol entre les pieds", "With weight between feet"),
ex2("Donkey kicks", "Donkey kicks",
"À quatre pattes, poussez un pied vers le plafond",
"On all fours, push one foot toward ceiling",
"Amplitude réduite, plus lent", "Reduced range, slower",
"Avec élastique", "With band")),
block(2,
ex1("Step-ups sur marche", "Step-ups on step",
"Montez sur une marche, jambe tendue en haut, redescendez",
"Step up onto a step, leg straight at top, step down",
"Marche plus basse", "Lower step",
"Marche plus haute", "Higher step"),
ex2("Fire hydrants", "Fire hydrants",
"À quatre pattes, levez le genou sur le côté comme un chien",
"On all fours, lift knee to side like a dog",
"Plus lent", "Slower",
"Avec élastique", "With band")),
block(3,
ex1("Squat plié lent", "Slow plié squats",
"Position ballet, descendez très lentement sur 3 secondes",
"Ballet position, lower very slowly over 3 seconds",
"Pas de pause en bas", "No pause at bottom",
"Avec pulsations en bas", "With pulses at bottom"),
ex2("Leg raises latéral", "Side leg raises",
"Allongé sur le côté, levez la jambe du haut lentement",
"Lying on side, lift top leg slowly",
"Amplitude réduite", "Reduced range",
"Avec élastique cheville", "With ankle band")),
]),
_program("78840358-2118-4e63-942b-f6ffa7799c8d",
"Lower Body Power", "Lower Body Power",
"Programme intermédiaire pour des jambes fortes.",
"lower-body", "Intermediate", "#9B59B6", 130,
blocks: [
block(1,
ex1("Squats sautés", "Jump squats",
"Descendez en squat, explosez vers le haut, atterrissez en douceur",
"Lower into squat, explode upward, land softly",
"Squats rapides sans saut", "Fast squats no jump",
"Squats sautés avec torsion", "Jump squats with twist"),
ex2("Fentes sautées", "Jumping lunges",
"Alternez les jambes en sautant, genou avant à 90°",
"Alternate legs jumping, front knee at 90°",
"Fentes alternées rapides sans saut", "Fast alternating lunges no jump",
"Fentes sautées avec poids", "Jumping lunges with weight")),
block(2,
ex1("Bulgarian split squat", "Bulgarian split squats",
"Pied arrière surélevé, descendez le genou arrière vers le sol",
"Rear foot elevated, lower back knee toward floor",
"Sans élévation", "No elevation",
"Avec poids dans chaque main", "With weights in each hand"),
ex2("Romanian deadlift mime", "Romanian deadlift mime",
"Hanches poussées en arrière, dos droit, descendez jusqu'à tension ischios",
"Hips pushed back, straight back, lower until hamstring tension",
"Amplitude réduite", "Reduced range",
"Avec poids", "With weight")),
block(3,
ex1("Skater jumps", "Skater jumps",
"Saut latéral d'un pied à l'autre, atterrissez sur une jambe",
"Lateral jump foot to foot, land on one leg",
"Pas latéraux sans saut", "Lateral steps no jump",
"Plus amples et plus rapides", "Wider and faster"),
ex2("Squat pulse", "Squat pulses",
"Restez en bas du squat, petites pulsations de haut en bas",
"Stay at bottom of squat, small up-down pulses",
"Demi-amplitude", "Half range",
"Pulsations plus profondes", "Deeper pulses")),
]),
_program("2439ee21-a73e-4f35-ac28-5dfeeb1249ab",
"Leg Destroyer", "Leg Destroyer",
"Programme avancé. Jump squats, pistol squats assistés et plyométrie pure.",
"lower-body", "Advanced", "#9B59B6", 170,
blocks: [
block(1,
ex1("Pistol squat assisté", "Assisted pistol squats",
"Une jambe tendue devant, descendez sur l'autre en tenant un support",
"One leg extended front, lower on other holding support",
"Avec chaise pour soutien", "With chair for support",
"Pistol squat complet", "Full pistol squat"),
ex2("Box jumps", "Box jumps",
"Saut explosif sur une surface surélevée, atterrissez en squat",
"Explosive jump onto elevated surface, land in squat",
"Step-ups rapides", "Fast step-ups",
"Box jumps plus hautes", "Higher box jumps")),
block(2,
ex1("Jump squat deep", "Deep jump squats",
"Squat très profond, saut maximal, atterrissage contrôlé",
"Very deep squat, max jump, controlled landing",
"Squat profond sans saut", "Deep squat no jump",
"Avec lest", "With weight vest"),
ex2("Single leg deadlift", "Single leg deadlifts",
"Équilibre sur une jambe, penchez-vous en avant, jambe arrière tendue",
"Balance on one leg, hinge forward, back leg straight",
"Avec support", "With support",
"Avec poids", "With weight")),
block(3,
ex1("Tuck jumps", "Tuck jumps",
"Saut vertical, ramenez les genoux à la poitrine en l'air",
"Vertical jump, tuck knees to chest in air",
"Squats sautés normaux", "Regular jump squats",
"Tuck jumps consécutifs sans pause", "Continuous tuck jumps"),
ex2("Explosive lunges", "Explosive lunges",
"Fentes avec saut et changement de jambe explosif à chaque rep",
"Lunges with explosive leg switch jump each rep",
"Fentes marchées rapides", "Fast walking lunges",
"Fentes sautées avec haltères", "Jump lunges with dumbbells")),
]),
// Full Body Free
_program("3a62af9d-af30-4afd-9144-295bde20a28d",
"Full Body Éveil", "Full Body Awakening",
"Programme débutant complet pour réveiller tout le corps.",
"full-body", "Beginner", "#00C896", 100,
blocks: [
block(1,
ex1("Jumping jacks doux", "Gentle jumping jacks",
"Bras vers le haut, pieds écartés, mouvement fluide",
"Arms up, feet apart, fluid motion",
"Step touches sans saut", "Step touches no jump",
"Plus rapides", "Faster"),
ex2("Squats légers", "Bodyweight squats",
"Pieds largeur épaules, descendez comme pour s'asseoir",
"Feet shoulder-width, lower as if sitting",
"Demi-squats", "Half squats",
"Squats complets avec pause en bas", "Full squats with bottom pause")),
block(2,
ex1("Marche en montagne lente", "Slow mountain climbers",
"Position planche, ramenez un genou puis l'autre lentement",
"Plank position, bring one knee then other slowly",
"Plus lent", "Slower",
"Plus rapide", "Faster"),
ex2("Push-ups au mur", "Wall push-ups",
"Mains sur le mur, descendez et poussez, corps gainé",
"Hands on wall, lower and push, body tight",
"Plus près du mur", "Closer to wall",
"Push-ups au sol sur genoux", "Floor knee push-ups")),
block(3,
ex1("Glute bridge", "Glute bridges",
"Au sol, pieds plans, montez les hanches en serrant les fessiers",
"On floor, flat feet, raise hips squeezing glutes",
"Amplitude réduite", "Reduced range",
"Single leg bridge", "One-leg bridge"),
ex2("Planche genoux", "Knee plank",
"Avant-bras au sol, genoux au sol, corps aligné",
"Forearms down, knees down, body aligned",
"Sur les mains au lieu des avant-bras", "On hands instead of forearms",
"Planche complète sur pieds", "Full plank on feet")),
]),
_program("76609f2f-ea94-4138-9d43-9b46f3406404",
"Cardio & Renforcement Doux", "Gentle Cardio & Strength",
"Alternance cardio léger et renforcement pour un premier pas accessible.",
"full-body", "Beginner", "#00C896", 95,
blocks: [
block(1,
ex1("Pas chassés latéraux", "Lateral shuffles",
"Déplacez-vous latéralement en restant bas, changez de direction",
"Move laterally staying low, change direction",
"Plus lent", "Slower",
"Plus rapide avec touche au sol", "Faster with floor touch"),
ex2("Curl biceps sans charge", "Bicep curls no weight",
"Coudes collés, montez et descendez les avant-bras",
"Elbows pinned, raise and lower forearms",
"Amplitude partielle", "Partial range",
"Avec bouteilles d'eau", "With water bottles")),
block(2,
ex1("Squat + punch", "Squat punches",
"Descendez en squat, en remontant lancez deux punches alternés",
"Lower into squat, throw two alternate punches on way up",
"Squat sans punch", "Squat no punch",
"Plus rapide avec jump", "Faster with jump"),
ex2("Superman", "Superman",
"Au sol ventre en bas, levez bras et jambes ensemble",
"On floor face down, lift arms and legs together",
"Bras seuls", "Arms only",
"Avec rotation", "With rotation")),
block(3,
ex1("Step-ups alternés", "Alternate step-ups",
"Montez sur une marche en alternant les jambes",
"Step up on a step alternating legs",
"Marche plus basse", "Lower step",
"Marche plus haute", "Higher step"),
ex2("Bird dog", "Bird dogs",
"À quatre pattes, tendez bras opposé et jambe opposée",
"On all fours, extend opposite arm and leg",
"Sans équilibre prolongé", "Without hold",
"Avec pause 3 secondes", "With 3-second hold")),
]),
_program("39e380ea-619f-4695-b00b-4e727f752d2e",
"Full Body HIIT", "Full Body HIIT",
"Programme intermédiaire haute intensité.",
"full-body", "Intermediate", "#00C896", 140,
blocks: [
block(1,
ex1("Burpees sans saut", "Burpee no jump",
"Au sol et debout, pas de saut en haut, rythme soutenu",
"Floor to standing, no top jump, steady pace",
"Sans push-up", "No push-up",
"Burpees complets avec saut", "Full burpees with jump"),
ex2("Mountain climbers rapides", "Fast mountain climbers",
"Planche haute, genoux rapides vers la poitrine",
"High plank, fast knees to chest",
"Plus lent", "Slower",
"Cross-body mountain climbers", "Cross-body climbers")),
block(2,
ex1("Push-ups + row", "Push-up to renegade row",
"Une pompe puis tirez un coude en arrière, alternez",
"One push-up then pull one elbow back, alternate",
"Push-ups + tirage sans poids", "Push-ups + no-weight row",
"Avec haltères", "With dumbbells"),
ex2("Jump squats", "Jump squats",
"Squat profond, saut vertical, atterrissage souple",
"Deep squat, vertical jump, soft landing",
"Squats rapides sans saut", "Fast squats no jump",
"Tuck squats (genoux à la poitrine)", "Tuck squats (knees to chest)")),
block(3,
ex1("Plank jack", "Plank jacks",
"Position planche, sautez pieds écartés puis serrés",
"Plank position, jump feet apart then together",
"Step au lieu de sauter", "Step instead of jump",
"Plus rapide", "Faster"),
ex2("Renegade row mime", "Renegade row mime",
"Position planche haute, tirez un coude en arrière, alternez",
"High plank, pull one elbow back, alternate",
"Sans poids, plus lent", "No weight, slower",
"Avec haltères ou bouteilles", "With dumbbells or bottles")),
]),
_program("c0d7962e-973a-405c-97d5-c77843841beb",
"Total Annihilation", "Total Annihilation",
"Programme avancé. Burpees, plyométrie et mouvements composés.",
"full-body", "Advanced", "#00C896", 180,
blocks: [
block(1,
ex1("Burpees complets", "Full burpees",
"Saut en haut, push-up au sol, va-et-vient explosif complet",
"Top jump, floor push-up, full explosive cycle",
"Burpees sans push-up", "Burpees no push-up",
"Burpee pull-ups", "Burpee pull-ups"),
ex2("Man-makers", "Man-makers",
"Push-up + row each arm + squat + press overhead",
"Push-up + row each arm + squat + press overhead",
"Sans poids, amplitude réduite", "No weight, reduced range",
"Avec haltères", "With dumbbells")),
block(2,
ex1("Pop squats", "Pop squats",
"Saut latéral d'un côté à l'autre en squat à chaque atterrissage",
"Lateral jump side to side in squat on each landing",
"Squats latéraux sans saut", "Lateral squats no jump",
"Plus amples et plus rapides", "Wider and faster"),
ex2("Spider push-ups", "Spiderman push-ups",
"Pompe + ramenez genou au coude du même côté à chaque descente",
"Push-up + drive knee to same-side elbow each descent",
"Push-ups classiques", "Standard push-ups",
"Avec résistance", "With resistance")),
block(3,
ex1("Squat thrust + tuck", "Squat thrust to tuck jump",
"Descendez au sol en squat thrust, remontez en tuck jump",
"Down to squat thrust, up to tuck jump",
"Sans tuck jump", "No tuck jump",
"Avec push-up au sol", "With floor push-up"),
ex2("Ice skater explosif", "Explosive skaters",
"Saut latéral d'un pied à l'autre amplitude maximale",
"Lateral jump foot to foot at max range",
"Skaters modérés", "Moderate skaters",
"Avec pause sur une jambe", "With single-leg hold")),
]),
// Premium
_program("f0ba130e-9a16-469b-a6ab-463ae7c47a10",
"Bras & Épaules Sculpté", "Sculpted Arms & Shoulders",
"Programme intermédiaire ciblé bras et épaules.",
"upper-body", "Intermediate", "#4A90D9", 125, isFree: false,
blocks: [
block(1,
ex1p("Push-ups surélevés", "Decline push-ups",
"Pieds sur chaise, mains au sol, descendez lentement",
"Feet on chair, hands on floor, lower slowly"),
ex2p("Dips profonds", "Deep dips",
"Amplitude maximale, pause en bas",
"Full range, pause at bottom")),
block(2,
ex1p("Curl + press", "Curl to press",
"Curl biceps puis poussez au-dessus de la tête",
"Bicep curl then press overhead"),
ex2p("Push-ups diamant", "Diamond push-ups",
"Mains serrées, triceps isolés",
"Hands close, triceps isolated")),
block(3,
ex1p("L-fly latéral", "Lateral raises",
"Bras tendus sur les côtés, montez à hauteur épaules",
"Straight arms to sides, raise to shoulder height"),
ex2p("Shrugs + rotation", "Shrug rotations",
"Montez épaules puis rotation vers l'avant",
"Shrug up then rotate forward")),
]),
_program("1f31f624-351a-430e-a7d4-45ab3ed44765",
"Cuisses & Mollets Force", "Power Thighs & Calves",
"Programme intermédiaire pour des cuisses puissantes.",
"lower-body", "Intermediate", "#9B59B6", 135, isFree: false,
blocks: [
block(1,
ex1p("Front squats", "Front squats",
"Mains croisées, coudes hauts, descendez profond",
"Arms crossed, elbows high, lower deep"),
ex2p("Calf raises unilatéral", "Single-leg calf raises",
"Sur un pied, montez sur la pointe",
"On one foot, rise onto toes")),
block(2,
ex1p("Walking lunges", "Walking lunges",
"Grands pas en avant, genou arrière frôle le sol",
"Long steps forward, back knee grazes floor"),
ex2p("Wall sit + jump", "Wall sit to jump",
"Wall sit 20s puis saut vertical",
"Wall sit 20s then vertical jump")),
block(3,
ex1p("Reverse lunges", "Reverse lunges",
"Pas en arrière, genou avant reste à 90°",
"Step backward, front knee stays at 90°"),
ex2p("Squat + calf raise", "Squat to calf raise",
"Remontez du squat sur la pointe des pieds",
"Rise from squat onto toes")),
]),
_program("43541fed-0b1a-4d5f-8f65-779ddd82fd18",
"Métabolique Total", "Total Metabolic",
"Programme intermédiaire métabolique. Brûle maximum de calories.",
"full-body", "Intermediate", "#00C896", 150, isFree: false,
blocks: [
block(1,
ex1p("Squat thrust rapide", "Fast squat thrusts",
"Descendez au sol et remontez le plus vite possible",
"Down to floor and back up as fast as possible"),
ex2p("Mountain climbers croisés", "Cross mountain climbers",
"Genou vers coude opposé, alternez vite",
"Knee to opposite elbow, alternate fast")),
block(2,
ex1p("Burpee + tuck", "Burpee to tuck jump",
"Burpee complet puis tuck jump vertical",
"Full burpee then vertical tuck jump"),
ex2p("Plank up-downs", "Plank up-downs",
"Planche haute vers basse et inversement, alternez les bras",
"High to low plank and back, alternate arms")),
block(3,
ex1p("High knees explosifs", "Explosive high knees",
"Montées de genoux rapides et hautes, bras en opposition",
"Fast high knee drives, arms in opposition"),
ex2p("Squat jumps rotations", "Squat jump twists",
"Saut en squat avec rotation 90° à chaque saut",
"Squat jump with 90° twist each jump")),
]),
_program("51d071a7-c371-4fd1-966c-31d360a96421",
"Arms of Steel", "Arms of Steel",
"Programme avancé dédié aux bras.",
"upper-body", "Advanced", "#4A90D9", 165, isFree: false,
blocks: [
block(1,
ex1p("Tricep dips explosifs", "Explosive tricep dips",
"Poussez fort pour décoller, atterrissez et replongez",
"Push hard to lift off, land and dive back"),
ex2p("Close-grip push-ups", "Close-grip push-ups",
"Mains serrées, coudes collés au corps",
"Hands close, elbows pinned to body")),
block(2,
ex1p("Curl 21s style", "21s style curls",
"7 basses + 7 hautes + 7 complètes, sans pause",
"7 bottom + 7 top + 7 full, no rest"),
ex2p("Pike push-ups", "Pike push-ups",
"Épaules au-dessus des mains, descendez le front",
"Shoulders over hands, lower forehead")),
block(3,
ex1p("Commando plank", "Commando plank",
"Montez de planche basse à haute et redescendez, alternez",
"Go from low to high plank and back, alternate"),
ex2p("Push-up clap", "Clap push-ups",
"Explosez pour taper les mains en l'air",
"Explode to clap hands in air")),
]),
_program("3db31a8c-4047-47a1-a163-6ffa8449e25e",
"Plyo Legs Extreme", "Plyo Legs Extreme",
"Plyométrie pure pour les jambes.",
"lower-body", "Advanced", "#9B59B6", 175, isFree: false,
blocks: [
block(1,
ex1p("Box jumps continus", "Continuous box jumps",
"Saut sur box, redescente souple, enchaînez sans pause",
"Jump onto box, soft landing, chain without rest"),
ex2p("Depth jumps", "Depth jumps",
"Descendez de la box, touchez le sol et sautez vertical",
"Step off box, touch floor and jump vertical")),
block(2,
ex1p("Bounds géants", "Bounding leaps",
"Sauts en longueur maximale d'un pied à l'autre",
"Max distance leaps foot to foot"),
ex2p("Single-leg hops", "Single-leg hops",
"Sauts sur place sur un pied, hauteur maximale",
"In-place hops on one foot, max height")),
block(3,
ex1p("Lateral box jumps", "Lateral box jumps",
"Face au côté de la box, saut latéral par-dessus",
"Facing side of box, lateral jump over"),
ex2p("Squat jumps profond", "Deep squat jumps",
"Squat très profond, saut le plus haut possible",
"Very deep squat, highest possible jump")),
]),
_program("565b713a-4a65-4866-8584-044260010514",
"Warrior Workout", "Warrior Workout",
"Le défi ultime. Mouvements composés avancés, zéro repos mental.",
"full-body", "Advanced", "#00C896", 190, isFree: false,
blocks: [
block(1,
ex1p("Burpee pull-up mime", "Burpee to pull-up mime",
"Burpee complet puis saut mains au-dessus comme un pull-up",
"Full burpee then jump hands up like a pull-up"),
ex2p("Turkish get-up mime", "Turkish get-up mime",
"Au sol à debout en passant par chaque étape",
"Floor to standing through each stage")),
block(2,
ex1p("Bear crawl", "Bear crawl",
"Quatre pattes, genoux décollés, avancez en opposition",
"On all fours, knees off ground, move in opposition"),
ex2p("Crab walk", "Crab walk",
"Assis face au plafond, avancez sur mains et pieds",
"Sitting face up, move on hands and feet")),
block(3,
ex1p("Burpee broad jump", "Burpee broad jumps",
"Burpee puis saut en longueur maximum en avant",
"Burpee then max forward broad jump"),
ex2p("Sprint sur place", "Sprint in place",
"Sprint maximal sur place, genoux très hauts",
"Max sprint in place, knees very high")),
]),
]
}
// Helpers
private static func _program(
_ id: String, _ title: String, _ titleEn: String, _ desc: String,
_ zone: String, _ level: String, _ color: String, _ cals: Int,
isFree: Bool = true,
blocks: [TabataBlock]
) -> WorkoutProgram {
let totalRounds = blocks.reduce(0) { $0 + $1.rounds }
let workSeconds = blocks.reduce(0) { $0 + $1.rounds * ($1.workTime + $1.restTime) }
return WorkoutProgram(
id: id,
title: title,
titleEn: titleEn,
description: desc,
descriptionEn: desc,
bodyZone: zone,
level: level,
musicVibe: "electronic",
accentColor: color,
isFree: isFree,
estimatedCalories: cals,
estimatedDuration: workSeconds / 60,
totalRounds: totalRounds,
warmup: WarmupSection(movements: [], totalDuration: 0),
cooldown: CooldownSection(movements: [], totalDuration: 0),
blocks: blocks,
thumbnailUrl: nil
)
}
}
// Block builder (reduces repetition)
private struct TabataBlockBuilder {
func callAsFunction(
_ position: Int,
_ ex1: TabataExercise,
_ ex2: TabataExercise,
rounds: Int = 8, work: Int = 20, rest: Int = 10
) -> TabataBlock {
TabataBlock(
id: UUID().uuidString,
position: position,
exercise1: ex1,
exercise2: ex2,
rounds: rounds,
workTime: work,
restTime: rest
)
}
}
// Exercise builders
private func ex1(_ name: String, _ nameEn: String,
_ tip: String, _ tipEn: String,
_ mod: String, _ modEn: String,
_ prog: String, _ progEn: String) -> TabataExercise {
TabataExercise(name: name, nameEn: nameEn, tip: tip, tipEn: tipEn,
modification: mod, modificationEn: modEn,
progression: prog, progressionEn: progEn)
}
private func ex2(_ name: String, _ nameEn: String,
_ tip: String, _ tipEn: String,
_ mod: String, _ modEn: String,
_ prog: String, _ progEn: String) -> TabataExercise {
TabataExercise(name: name, nameEn: nameEn, tip: tip, tipEn: tipEn,
modification: mod, modificationEn: modEn,
progression: prog, progressionEn: progEn)
}
private func ex1p(_ name: String, _ nameEn: String, _ tip: String, _ tipEn: String) -> TabataExercise {
TabataExercise(name: name, nameEn: nameEn, tip: tip, tipEn: tipEn)
}
private func ex2p(_ name: String, _ nameEn: String, _ tip: String, _ tipEn: String) -> TabataExercise {
TabataExercise(name: name, nameEn: nameEn, tip: tip, tipEn: tipEn)
}

View File

@@ -52,9 +52,12 @@ final class HomeViewModel: ObservableObject {
do {
if let remote = try await SupabaseService.shared.fetchAllPrograms() {
allPrograms = remote
} else {
allPrograms = MockPrograms.all
}
} catch {
self.error = error.localizedDescription
allPrograms = MockPrograms.all
}
}
}