diff --git a/Apps/LekaActivityUIExplorer/Resources/GEKNewSystem/activities/activity-touchToSelect-one_right_answer-colors-shuffle_sequences.yml b/Apps/LekaActivityUIExplorer/Resources/GEKNewSystem/activities/activity-touchToSelect-one_right_answer-colors-shuffle_sequences.yml index f1a06dcc8d..49e1fb7a92 100644 --- a/Apps/LekaActivityUIExplorer/Resources/GEKNewSystem/activities/activity-touchToSelect-one_right_answer-colors-shuffle_sequences.yml +++ b/Apps/LekaActivityUIExplorer/Resources/GEKNewSystem/activities/activity-touchToSelect-one_right_answer-colors-shuffle_sequences.yml @@ -6,7 +6,7 @@ id: a3542226982342c5805931f9e86a69a8 name: Touch To Select - One Right Answer - Colors - Shuffle sequences description: L'objectif est de trouver la bonne couleur ou des les rassembler par famille image: activity_color_recognition_1 -shuffle_sequences: true +shuffle_groups: true sequence: - exercises: - instructions: Touche le rouge diff --git a/Modules/ContentKit/Examples/ContentKitExample/Resources/activity.yml b/Modules/ContentKit/Examples/ContentKitExample/Resources/activity.yml index 922325b976..2de4d34478 100644 --- a/Modules/ContentKit/Examples/ContentKitExample/Resources/activity.yml +++ b/Modules/ContentKit/Examples/ContentKitExample/Resources/activity.yml @@ -84,9 +84,9 @@ l10n: gameengine: shuffle_exercises: true - shuffle_sequences: true + shuffle_groups: true -exercises: +exercise_groups: - group: - instructions: - locale: fr_FR diff --git a/Modules/ContentKit/Resources/Content/activities/examples/sample_1-5A670B59EB214A6AA11AB39D64D63990.activity.yml b/Modules/ContentKit/Resources/Content/activities/examples/sample_1-5A670B59EB214A6AA11AB39D64D63990.activity.yml index 4aee3d6f42..c4ba52ca09 100644 --- a/Modules/ContentKit/Resources/Content/activities/examples/sample_1-5A670B59EB214A6AA11AB39D64D63990.activity.yml +++ b/Modules/ContentKit/Resources/Content/activities/examples/sample_1-5A670B59EB214A6AA11AB39D64D63990.activity.yml @@ -38,7 +38,7 @@ l10n: details: icon: sample_1 - title: Activité d'exemple + title: Activité d'exemple 1 subtitle: pour le développement description: | @@ -61,7 +61,7 @@ l10n: details: icon: sample_1 - title: Sample activity + title: Sample activity 1 subtitle: for development description: | @@ -80,133 +80,185 @@ l10n: - Repulsa impediunt munera teneri fallebat - Bracchia frustra telo Iovis faucibus casus -gameengine: - shuffle_exercises: true - shuffle_sequences: true - -exercises: - - group: - - instructions: - - locale: fr_FR - value: Touch le rond jaune - - locale: en_US - value: Touch the yellow circle - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: yellow - type: color - isRightAnswer: true - - value: red - type: color - - value: green - type: color - - value: blue - type: color - - - instructions: - - locale: fr_FR - value: Touch la pastèque - - locale: en_US - value: Touch the watermelon - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: 🍉 - type: emoji - isRightAnswer: true - - value: 🍌 - type: emoji - - value: 🍒 - type: emoji - - value: 🥝 - type: emoji - - - instructions: - - locale: fr_FR - value: Touch le carré - - locale: en_US - value: Touch the square - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: circle - type: sfsymbol - - value: square - type: sfsymbol - isRightAnswer: true - - value: triangle - type: sfsymbol - - value: rhombus - type: sfsymbol - - - group: - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - group: - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorHeptatonic - - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorPentatonic - - - group: - - instructions: - interface: danceFreeze - payload: - songs: - - earlyBird - - emptyPage - - gigglySquirrel - - handsOn - - happyDays - - inTheGame - - littleByLittle - - - instructions: - interface: hideAndSeek - - - instructions: - - locale: fr_FR - value: Joue les notes de la même couleur que Leka - - locale: en_US - value: Play the notes of the same color as Leka - interface: melody - payload: - instrument: xylophone - songs: - - underTheMoonlight - - aGreenMouse - - twinkleTwinkleLittleStar - - londonBridgeIsFallingDown - - ohTheCrocodiles - - happyBirthday +exercises_payload: + options: + shuffle_exercises: false + shuffle_groups: false + + exercise_groups: + - group: + - instructions: + - locale: fr_FR + value: Touch le rond jaune + - locale: en_US + value: Touch the yellow circle + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + isRightAnswer: true + - value: red + type: color + - value: green + type: color + - value: blue + type: color + + - instructions: + - locale: fr_FR + value: Touch les ronds verts et bleus + - locale: en_US + value: Touch the green and blue circles + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + - value: red + type: color + - value: green + type: color + isRightAnswer: true + - value: blue + type: color + isRightAnswer: true + + - group: + - instructions: + - locale: fr_FR + value: Touch la pastèque + - locale: en_US + value: Touch the watermelon + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🍉 + type: emoji + isRightAnswer: true + - value: 🍌 + type: emoji + - value: 🍒 + type: emoji + - value: 🥝 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le chat et le chien + - locale: en_US + value: Touch the cat and the dog + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🐱 + type: emoji + isRightAnswer: true + - value: 🐶 + type: emoji + isRightAnswer: true + - value: 🐷 + type: emoji + - value: 🐹 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le marteau et la scie + - locale: en_US + value: Touch the hammer and the saw + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🔨 + type: emoji + isRightAnswer: true + - value: 🪚 + type: emoji + isRightAnswer: true + - value: 🪛 + type: emoji + - value: 🪜 + type: emoji + + - group: + - instructions: + - locale: fr_FR + value: Touch le carré + - locale: en_US + value: Touch the square + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: circle + type: sfsymbol + - value: square + type: sfsymbol + isRightAnswer: true + - value: triangle + type: sfsymbol + - value: rhombus + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch la personne jouant au tennis + - locale: en_US + value: Touch the person playing tennis + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: figure.climbing + type: sfsymbol + - value: figure.tennis + type: sfsymbol + isRightAnswer: true + - value: figure.pool.swim + type: sfsymbol + - value: figure.soccer + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch l'orage + - locale: en_US + value: Touch the storm + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: sun.max + type: sfsymbol + - value: cloud.sun + type: sfsymbol + - value: cloud.bolt.rain.fill + type: sfsymbol + isRightAnswer: true + - value: cloud.rain + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch le vélo + - locale: en_US + value: Touch the bike + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: bicycle + type: sfsymbol + isRightAnswer: true + - value: car + type: sfsymbol + - value: airplane + type: sfsymbol + - value: boat + type: sfsymbol diff --git a/Modules/ContentKit/Resources/Content/activities/examples/sample_2-6102794F02D3423482E243BCBC7F8CA8.activity.yml b/Modules/ContentKit/Resources/Content/activities/examples/sample_2-6102794F02D3423482E243BCBC7F8CA8.activity.yml index 3948b7e8ff..d4c2ca2ee3 100644 --- a/Modules/ContentKit/Resources/Content/activities/examples/sample_2-6102794F02D3423482E243BCBC7F8CA8.activity.yml +++ b/Modules/ContentKit/Resources/Content/activities/examples/sample_2-6102794F02D3423482E243BCBC7F8CA8.activity.yml @@ -38,7 +38,7 @@ l10n: details: icon: sample_2 - title: Activité d'exemple + title: Activité d'exemple 2 subtitle: pour le développement description: | @@ -61,7 +61,7 @@ l10n: details: icon: sample_2 - title: Sample activity + title: Sample activity 2 subtitle: for development description: | @@ -80,133 +80,185 @@ l10n: - Repulsa impediunt munera teneri fallebat - Bracchia frustra telo Iovis faucibus casus -gameengine: - shuffle_exercises: true - shuffle_sequences: true - -exercises: - - group: - - instructions: - - locale: fr_FR - value: Touch le rond jaune - - locale: en_US - value: Touch the yellow circle - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: yellow - type: color - isRightAnswer: true - - value: red - type: color - - value: green - type: color - - value: blue - type: color - - - instructions: - - locale: fr_FR - value: Touch la pastèque - - locale: en_US - value: Touch the watermelon - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: 🍉 - type: emoji - isRightAnswer: true - - value: 🍌 - type: emoji - - value: 🍒 - type: emoji - - value: 🥝 - type: emoji - - - instructions: - - locale: fr_FR - value: Touch le carré - - locale: en_US - value: Touch the square - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: circle - type: sfsymbol - - value: square - type: sfsymbol - isRightAnswer: true - - value: triangle - type: sfsymbol - - value: rhombus - type: sfsymbol - - - group: - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - group: - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorHeptatonic - - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorPentatonic - - - group: - - instructions: - interface: danceFreeze - payload: - songs: - - earlyBird - - emptyPage - - gigglySquirrel - - handsOn - - happyDays - - inTheGame - - littleByLittle - - - instructions: - interface: hideAndSeek - - - instructions: - - locale: fr_FR - value: Joue les notes de la même couleur que Leka - - locale: en_US - value: Play the notes of the same color as Leka - interface: melody - payload: - instrument: xylophone - songs: - - underTheMoonlight - - aGreenMouse - - twinkleTwinkleLittleStar - - londonBridgeIsFallingDown - - ohTheCrocodiles - - happyBirthday +exercises_payload: + options: + shuffle_exercises: true + shuffle_groups: false + + exercise_groups: + - group: + - instructions: + - locale: fr_FR + value: Touch le rond jaune + - locale: en_US + value: Touch the yellow circle + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + isRightAnswer: true + - value: red + type: color + - value: green + type: color + - value: blue + type: color + + - instructions: + - locale: fr_FR + value: Touch les ronds verts et bleus + - locale: en_US + value: Touch the green and blue circles + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + - value: red + type: color + - value: green + type: color + isRightAnswer: true + - value: blue + type: color + isRightAnswer: true + + - group: + - instructions: + - locale: fr_FR + value: Touch la pastèque + - locale: en_US + value: Touch the watermelon + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🍉 + type: emoji + isRightAnswer: true + - value: 🍌 + type: emoji + - value: 🍒 + type: emoji + - value: 🥝 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le chat et le chien + - locale: en_US + value: Touch the cat and the dog + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🐱 + type: emoji + isRightAnswer: true + - value: 🐶 + type: emoji + isRightAnswer: true + - value: 🐷 + type: emoji + - value: 🐹 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le marteau et la scie + - locale: en_US + value: Touch the hammer and the saw + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🔨 + type: emoji + isRightAnswer: true + - value: 🪚 + type: emoji + isRightAnswer: true + - value: 🪛 + type: emoji + - value: 🪜 + type: emoji + + - group: + - instructions: + - locale: fr_FR + value: Touch le carré + - locale: en_US + value: Touch the square + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: circle + type: sfsymbol + - value: square + type: sfsymbol + isRightAnswer: true + - value: triangle + type: sfsymbol + - value: rhombus + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch la personne jouant au tennis + - locale: en_US + value: Touch the person playing tennis + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: figure.climbing + type: sfsymbol + - value: figure.tennis + type: sfsymbol + isRightAnswer: true + - value: figure.pool.swim + type: sfsymbol + - value: figure.soccer + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch l'orage + - locale: en_US + value: Touch the storm + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: sun.max + type: sfsymbol + - value: cloud.sun + type: sfsymbol + - value: cloud.bolt.rain.fill + type: sfsymbol + isRightAnswer: true + - value: cloud.rain + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch le vélo + - locale: en_US + value: Touch the bike + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: bicycle + type: sfsymbol + isRightAnswer: true + - value: car + type: sfsymbol + - value: airplane + type: sfsymbol + - value: boat + type: sfsymbol diff --git a/Modules/ContentKit/Resources/Content/activities/examples/sample_3-E7EE9CA4B13B49AF96CD77A9DF90833B.activity.yml b/Modules/ContentKit/Resources/Content/activities/examples/sample_3-E7EE9CA4B13B49AF96CD77A9DF90833B.activity.yml index 1893a7a3e8..2a006e57a0 100644 --- a/Modules/ContentKit/Resources/Content/activities/examples/sample_3-E7EE9CA4B13B49AF96CD77A9DF90833B.activity.yml +++ b/Modules/ContentKit/Resources/Content/activities/examples/sample_3-E7EE9CA4B13B49AF96CD77A9DF90833B.activity.yml @@ -38,7 +38,7 @@ l10n: details: icon: sample_3 - title: Activité d'exemple + title: Activité d'exemple 3 subtitle: pour le développement description: | @@ -61,7 +61,7 @@ l10n: details: icon: sample_3 - title: Sample activity + title: Sample activity 3 subtitle: for development description: | @@ -80,133 +80,185 @@ l10n: - Repulsa impediunt munera teneri fallebat - Bracchia frustra telo Iovis faucibus casus -gameengine: - shuffle_exercises: true - shuffle_sequences: true - -exercises: - - group: - - instructions: - - locale: fr_FR - value: Touch le rond jaune - - locale: en_US - value: Touch the yellow circle - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: yellow - type: color - isRightAnswer: true - - value: red - type: color - - value: green - type: color - - value: blue - type: color - - - instructions: - - locale: fr_FR - value: Touch la pastèque - - locale: en_US - value: Touch the watermelon - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: 🍉 - type: emoji - isRightAnswer: true - - value: 🍌 - type: emoji - - value: 🍒 - type: emoji - - value: 🥝 - type: emoji - - - instructions: - - locale: fr_FR - value: Touch le carré - - locale: en_US - value: Touch the square - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: circle - type: sfsymbol - - value: square - type: sfsymbol - isRightAnswer: true - - value: triangle - type: sfsymbol - - value: rhombus - type: sfsymbol - - - group: - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - group: - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorHeptatonic - - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorPentatonic - - - group: - - instructions: - interface: danceFreeze - payload: - songs: - - earlyBird - - emptyPage - - gigglySquirrel - - handsOn - - happyDays - - inTheGame - - littleByLittle - - - instructions: - interface: hideAndSeek - - - instructions: - - locale: fr_FR - value: Joue les notes de la même couleur que Leka - - locale: en_US - value: Play the notes of the same color as Leka - interface: melody - payload: - instrument: xylophone - songs: - - underTheMoonlight - - aGreenMouse - - twinkleTwinkleLittleStar - - londonBridgeIsFallingDown - - ohTheCrocodiles - - happyBirthday +exercises_payload: + options: + shuffle_exercises: false + shuffle_groups: true + + exercise_groups: + - group: + - instructions: + - locale: fr_FR + value: Touch le rond jaune + - locale: en_US + value: Touch the yellow circle + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + isRightAnswer: true + - value: red + type: color + - value: green + type: color + - value: blue + type: color + + - instructions: + - locale: fr_FR + value: Touch les ronds verts et bleus + - locale: en_US + value: Touch the green and blue circles + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + - value: red + type: color + - value: green + type: color + isRightAnswer: true + - value: blue + type: color + isRightAnswer: true + + - group: + - instructions: + - locale: fr_FR + value: Touch la pastèque + - locale: en_US + value: Touch the watermelon + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🍉 + type: emoji + isRightAnswer: true + - value: 🍌 + type: emoji + - value: 🍒 + type: emoji + - value: 🥝 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le chat et le chien + - locale: en_US + value: Touch the cat and the dog + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🐱 + type: emoji + isRightAnswer: true + - value: 🐶 + type: emoji + isRightAnswer: true + - value: 🐷 + type: emoji + - value: 🐹 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le marteau et la scie + - locale: en_US + value: Touch the hammer and the saw + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🔨 + type: emoji + isRightAnswer: true + - value: 🪚 + type: emoji + isRightAnswer: true + - value: 🪛 + type: emoji + - value: 🪜 + type: emoji + + - group: + - instructions: + - locale: fr_FR + value: Touch le carré + - locale: en_US + value: Touch the square + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: circle + type: sfsymbol + - value: square + type: sfsymbol + isRightAnswer: true + - value: triangle + type: sfsymbol + - value: rhombus + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch la personne jouant au tennis + - locale: en_US + value: Touch the person playing tennis + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: figure.climbing + type: sfsymbol + - value: figure.tennis + type: sfsymbol + isRightAnswer: true + - value: figure.pool.swim + type: sfsymbol + - value: figure.soccer + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch l'orage + - locale: en_US + value: Touch the storm + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: sun.max + type: sfsymbol + - value: cloud.sun + type: sfsymbol + - value: cloud.bolt.rain.fill + type: sfsymbol + isRightAnswer: true + - value: cloud.rain + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch le vélo + - locale: en_US + value: Touch the bike + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: bicycle + type: sfsymbol + isRightAnswer: true + - value: car + type: sfsymbol + - value: airplane + type: sfsymbol + - value: boat + type: sfsymbol diff --git a/Modules/ContentKit/Resources/Content/activities/examples/sample_4-81F6617499FE42ADB5B03B409462923E.activity.yml b/Modules/ContentKit/Resources/Content/activities/examples/sample_4-81F6617499FE42ADB5B03B409462923E.activity.yml index c020d53693..7aacbeb5f6 100644 --- a/Modules/ContentKit/Resources/Content/activities/examples/sample_4-81F6617499FE42ADB5B03B409462923E.activity.yml +++ b/Modules/ContentKit/Resources/Content/activities/examples/sample_4-81F6617499FE42ADB5B03B409462923E.activity.yml @@ -38,7 +38,7 @@ l10n: details: icon: sample_4 - title: Activité d'exemple + title: Activité d'exemple 4 subtitle: pour le développement description: | @@ -61,7 +61,7 @@ l10n: details: icon: sample_4 - title: Sample activity + title: Sample activity 4 subtitle: for development description: | @@ -80,133 +80,185 @@ l10n: - Repulsa impediunt munera teneri fallebat - Bracchia frustra telo Iovis faucibus casus -gameengine: - shuffle_exercises: true - shuffle_sequences: true - -exercises: - - group: - - instructions: - - locale: fr_FR - value: Touch le rond jaune - - locale: en_US - value: Touch the yellow circle - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: yellow - type: color - isRightAnswer: true - - value: red - type: color - - value: green - type: color - - value: blue - type: color - - - instructions: - - locale: fr_FR - value: Touch la pastèque - - locale: en_US - value: Touch the watermelon - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: 🍉 - type: emoji - isRightAnswer: true - - value: 🍌 - type: emoji - - value: 🍒 - type: emoji - - value: 🥝 - type: emoji - - - instructions: - - locale: fr_FR - value: Touch le carré - - locale: en_US - value: Touch the square - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: circle - type: sfsymbol - - value: square - type: sfsymbol - isRightAnswer: true - - value: triangle - type: sfsymbol - - value: rhombus - type: sfsymbol - - - group: - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - group: - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorHeptatonic - - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorPentatonic - - - group: - - instructions: - interface: danceFreeze - payload: - songs: - - earlyBird - - emptyPage - - gigglySquirrel - - handsOn - - happyDays - - inTheGame - - littleByLittle - - - instructions: - interface: hideAndSeek - - - instructions: - - locale: fr_FR - value: Joue les notes de la même couleur que Leka - - locale: en_US - value: Play the notes of the same color as Leka - interface: melody - payload: - instrument: xylophone - songs: - - underTheMoonlight - - aGreenMouse - - twinkleTwinkleLittleStar - - londonBridgeIsFallingDown - - ohTheCrocodiles - - happyBirthday +exercises_payload: + options: + shuffle_exercises: true + shuffle_groups: true + + exercise_groups: + - group: + - instructions: + - locale: fr_FR + value: Touch le rond jaune + - locale: en_US + value: Touch the yellow circle + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + isRightAnswer: true + - value: red + type: color + - value: green + type: color + - value: blue + type: color + + - instructions: + - locale: fr_FR + value: Touch les ronds verts et bleus + - locale: en_US + value: Touch the green and blue circles + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + - value: red + type: color + - value: green + type: color + isRightAnswer: true + - value: blue + type: color + isRightAnswer: true + + - group: + - instructions: + - locale: fr_FR + value: Touch la pastèque + - locale: en_US + value: Touch the watermelon + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🍉 + type: emoji + isRightAnswer: true + - value: 🍌 + type: emoji + - value: 🍒 + type: emoji + - value: 🥝 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le chat et le chien + - locale: en_US + value: Touch the cat and the dog + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🐱 + type: emoji + isRightAnswer: true + - value: 🐶 + type: emoji + isRightAnswer: true + - value: 🐷 + type: emoji + - value: 🐹 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le marteau et la scie + - locale: en_US + value: Touch the hammer and the saw + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🔨 + type: emoji + isRightAnswer: true + - value: 🪚 + type: emoji + isRightAnswer: true + - value: 🪛 + type: emoji + - value: 🪜 + type: emoji + + - group: + - instructions: + - locale: fr_FR + value: Touch le carré + - locale: en_US + value: Touch the square + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: circle + type: sfsymbol + - value: square + type: sfsymbol + isRightAnswer: true + - value: triangle + type: sfsymbol + - value: rhombus + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch la personne jouant au tennis + - locale: en_US + value: Touch the person playing tennis + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: figure.climbing + type: sfsymbol + - value: figure.tennis + type: sfsymbol + isRightAnswer: true + - value: figure.pool.swim + type: sfsymbol + - value: figure.soccer + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch l'orage + - locale: en_US + value: Touch the storm + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: sun.max + type: sfsymbol + - value: cloud.sun + type: sfsymbol + - value: cloud.bolt.rain.fill + type: sfsymbol + isRightAnswer: true + - value: cloud.rain + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch le vélo + - locale: en_US + value: Touch the bike + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: bicycle + type: sfsymbol + isRightAnswer: true + - value: car + type: sfsymbol + - value: airplane + type: sfsymbol + - value: boat + type: sfsymbol diff --git a/Modules/ContentKit/Resources/Content/activities/examples/sample_5-725853C4DC7B4D84A45AA20385F389F1.activity.yml b/Modules/ContentKit/Resources/Content/activities/examples/sample_5-725853C4DC7B4D84A45AA20385F389F1.activity.yml index ac27041c11..0d76a17f37 100644 --- a/Modules/ContentKit/Resources/Content/activities/examples/sample_5-725853C4DC7B4D84A45AA20385F389F1.activity.yml +++ b/Modules/ContentKit/Resources/Content/activities/examples/sample_5-725853C4DC7B4D84A45AA20385F389F1.activity.yml @@ -38,7 +38,7 @@ l10n: details: icon: sample_5 - title: Activité d'exemple + title: Activité d'exemple 5 subtitle: pour le développement description: | @@ -61,7 +61,7 @@ l10n: details: icon: sample_5 - title: Sample activity + title: Sample activity 5 subtitle: for development description: | @@ -80,133 +80,185 @@ l10n: - Repulsa impediunt munera teneri fallebat - Bracchia frustra telo Iovis faucibus casus -gameengine: - shuffle_exercises: true - shuffle_sequences: true - -exercises: - - group: - - instructions: - - locale: fr_FR - value: Touch le rond jaune - - locale: en_US - value: Touch the yellow circle - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: yellow - type: color - isRightAnswer: true - - value: red - type: color - - value: green - type: color - - value: blue - type: color - - - instructions: - - locale: fr_FR - value: Touch la pastèque - - locale: en_US - value: Touch the watermelon - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: 🍉 - type: emoji - isRightAnswer: true - - value: 🍌 - type: emoji - - value: 🍒 - type: emoji - - value: 🥝 - type: emoji - - - instructions: - - locale: fr_FR - value: Touch le carré - - locale: en_US - value: Touch the square - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: circle - type: sfsymbol - - value: square - type: sfsymbol - isRightAnswer: true - - value: triangle - type: sfsymbol - - value: rhombus - type: sfsymbol - - - group: - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - group: - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorHeptatonic - - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorPentatonic - - - group: - - instructions: - interface: danceFreeze - payload: - songs: - - earlyBird - - emptyPage - - gigglySquirrel - - handsOn - - happyDays - - inTheGame - - littleByLittle - - - instructions: - interface: hideAndSeek - - - instructions: - - locale: fr_FR - value: Joue les notes de la même couleur que Leka - - locale: en_US - value: Play the notes of the same color as Leka - interface: melody - payload: - instrument: xylophone - songs: - - underTheMoonlight - - aGreenMouse - - twinkleTwinkleLittleStar - - londonBridgeIsFallingDown - - ohTheCrocodiles - - happyBirthday +exercises_payload: + options: + shuffle_exercises: false + shuffle_groups: false + + exercise_groups: + - group: + - instructions: + - locale: fr_FR + value: Touch le rond jaune + - locale: en_US + value: Touch the yellow circle + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + isRightAnswer: true + - value: red + type: color + - value: green + type: color + - value: blue + type: color + + - instructions: + - locale: fr_FR + value: Touch les ronds verts et bleus + - locale: en_US + value: Touch the green and blue circles + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + - value: red + type: color + - value: green + type: color + isRightAnswer: true + - value: blue + type: color + isRightAnswer: true + + - group: + - instructions: + - locale: fr_FR + value: Touch la pastèque + - locale: en_US + value: Touch the watermelon + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🍉 + type: emoji + isRightAnswer: true + - value: 🍌 + type: emoji + - value: 🍒 + type: emoji + - value: 🥝 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le chat et le chien + - locale: en_US + value: Touch the cat and the dog + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🐱 + type: emoji + isRightAnswer: true + - value: 🐶 + type: emoji + isRightAnswer: true + - value: 🐷 + type: emoji + - value: 🐹 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le marteau et la scie + - locale: en_US + value: Touch the hammer and the saw + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🔨 + type: emoji + isRightAnswer: true + - value: 🪚 + type: emoji + isRightAnswer: true + - value: 🪛 + type: emoji + - value: 🪜 + type: emoji + + - group: + - instructions: + - locale: fr_FR + value: Touch le carré + - locale: en_US + value: Touch the square + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: circle + type: sfsymbol + - value: square + type: sfsymbol + isRightAnswer: true + - value: triangle + type: sfsymbol + - value: rhombus + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch la personne jouant au tennis + - locale: en_US + value: Touch the person playing tennis + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: figure.climbing + type: sfsymbol + - value: figure.tennis + type: sfsymbol + isRightAnswer: true + - value: figure.pool.swim + type: sfsymbol + - value: figure.soccer + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch l'orage + - locale: en_US + value: Touch the storm + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: sun.max + type: sfsymbol + - value: cloud.sun + type: sfsymbol + - value: cloud.bolt.rain.fill + type: sfsymbol + isRightAnswer: true + - value: cloud.rain + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch le vélo + - locale: en_US + value: Touch the bike + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: bicycle + type: sfsymbol + isRightAnswer: true + - value: car + type: sfsymbol + - value: airplane + type: sfsymbol + - value: boat + type: sfsymbol diff --git a/Modules/ContentKit/Resources/Content/activities/examples/sample_6-2FE0B8BDD1B0497F87B32A390119DB98.activity.yml b/Modules/ContentKit/Resources/Content/activities/examples/sample_6-2FE0B8BDD1B0497F87B32A390119DB98.activity.yml index 06f02802a7..cec017e054 100644 --- a/Modules/ContentKit/Resources/Content/activities/examples/sample_6-2FE0B8BDD1B0497F87B32A390119DB98.activity.yml +++ b/Modules/ContentKit/Resources/Content/activities/examples/sample_6-2FE0B8BDD1B0497F87B32A390119DB98.activity.yml @@ -38,7 +38,7 @@ l10n: details: icon: sample_6 - title: Activité d'exemple + title: Activité d'exemple 6 subtitle: pour le développement description: | @@ -61,7 +61,7 @@ l10n: details: icon: sample_6 - title: Sample activity + title: Sample activity 6 subtitle: for development description: | @@ -80,133 +80,185 @@ l10n: - Repulsa impediunt munera teneri fallebat - Bracchia frustra telo Iovis faucibus casus -gameengine: - shuffle_exercises: true - shuffle_sequences: true - -exercises: - - group: - - instructions: - - locale: fr_FR - value: Touch le rond jaune - - locale: en_US - value: Touch the yellow circle - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: yellow - type: color - isRightAnswer: true - - value: red - type: color - - value: green - type: color - - value: blue - type: color - - - instructions: - - locale: fr_FR - value: Touch la pastèque - - locale: en_US - value: Touch the watermelon - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: 🍉 - type: emoji - isRightAnswer: true - - value: 🍌 - type: emoji - - value: 🍒 - type: emoji - - value: 🥝 - type: emoji - - - instructions: - - locale: fr_FR - value: Touch le carré - - locale: en_US - value: Touch the square - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: circle - type: sfsymbol - - value: square - type: sfsymbol - isRightAnswer: true - - value: triangle - type: sfsymbol - - value: rhombus - type: sfsymbol - - - group: - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - instructions: - - locale: fr_FR - value: Contrôle Leka avec la télécommande et fais le changer de couleur - - locale: en_US - value: Control Leka with the remote and make it change color - interface: remoteArrow - - - group: - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorHeptatonic - - - instructions: - - locale: fr_FR - value: Joue du xylophone avec Leka - - locale: en_US - value: Play the xylophone with Leka - interface: musicalInstruments - payload: - instrument: xylophone - scale: majorPentatonic - - - group: - - instructions: null - interface: danceFreeze - payload: - songs: - - earlyBird - - emptyPage - - gigglySquirrel - - handsOn - - happyDays - - inTheGame - - littleByLittle - - - instructions: null - interface: hideAndSeek - - - instructions: - - locale: fr_FR - value: Joue les notes de la même couleur que Leka - - locale: en_US - value: Play the notes of the same color as Leka - interface: melody - payload: - instrument: xylophone - songs: - - underTheMoonlight - - aGreenMouse - - twinkleTwinkleLittleStar - - londonBridgeIsFallingDown - - ohTheCrocodiles - - happyBirthday +exercises_payload: + options: + shuffle_exercises: false + shuffle_groups: false + + exercise_groups: + - group: + - instructions: + - locale: fr_FR + value: Touch le rond jaune + - locale: en_US + value: Touch the yellow circle + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + isRightAnswer: true + - value: red + type: color + - value: green + type: color + - value: blue + type: color + + - instructions: + - locale: fr_FR + value: Touch les ronds verts et bleus + - locale: en_US + value: Touch the green and blue circles + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + - value: red + type: color + - value: green + type: color + isRightAnswer: true + - value: blue + type: color + isRightAnswer: true + + - group: + - instructions: + - locale: fr_FR + value: Touch la pastèque + - locale: en_US + value: Touch the watermelon + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🍉 + type: emoji + isRightAnswer: true + - value: 🍌 + type: emoji + - value: 🍒 + type: emoji + - value: 🥝 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le chat et le chien + - locale: en_US + value: Touch the cat and the dog + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🐱 + type: emoji + isRightAnswer: true + - value: 🐶 + type: emoji + isRightAnswer: true + - value: 🐷 + type: emoji + - value: 🐹 + type: emoji + + - instructions: + - locale: fr_FR + value: Touch le marteau et la scie + - locale: en_US + value: Touch the hammer and the saw + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: 🔨 + type: emoji + isRightAnswer: true + - value: 🪚 + type: emoji + isRightAnswer: true + - value: 🪛 + type: emoji + - value: 🪜 + type: emoji + + - group: + - instructions: + - locale: fr_FR + value: Touch le carré + - locale: en_US + value: Touch the square + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: circle + type: sfsymbol + - value: square + type: sfsymbol + isRightAnswer: true + - value: triangle + type: sfsymbol + - value: rhombus + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch la personne jouant au tennis + - locale: en_US + value: Touch the person playing tennis + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: figure.climbing + type: sfsymbol + - value: figure.tennis + type: sfsymbol + isRightAnswer: true + - value: figure.pool.swim + type: sfsymbol + - value: figure.soccer + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch l'orage + - locale: en_US + value: Touch the storm + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: sun.max + type: sfsymbol + - value: cloud.sun + type: sfsymbol + - value: cloud.bolt.rain.fill + type: sfsymbol + isRightAnswer: true + - value: cloud.rain + type: sfsymbol + + - instructions: + - locale: fr_FR + value: Touch le vélo + - locale: en_US + value: Touch the bike + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: bicycle + type: sfsymbol + isRightAnswer: true + - value: car + type: sfsymbol + - value: airplane + type: sfsymbol + - value: boat + type: sfsymbol diff --git a/Modules/ContentKit/Sources/Activity/Activity+DEPRECATED.swift b/Modules/ContentKit/Sources/Activity/Activity+DEPRECATED.swift deleted file mode 100644 index ad6ae65670..0000000000 --- a/Modules/ContentKit/Sources/Activity/Activity+DEPRECATED.swift +++ /dev/null @@ -1,45 +0,0 @@ -// Leka - iOS Monorepo -// Copyright APF France handicap -// SPDX-License-Identifier: Apache-2.0 - -import Foundation -import Yams - -public struct ActivityDeprecated: Codable, Identifiable { - // MARK: Lifecycle - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.id = try container.decode(String.self, forKey: .id) - self.name = try container.decode(String.self, forKey: .name) - self.description = try container.decode(String.self, forKey: .description) - self.image = try container.decode(String.self, forKey: .image) - self.sequence = try container.decode([Exercise.Sequence].self, forKey: .sequence) - - self.shuffleExercises = try container.decodeIfPresent(Bool.self, forKey: .shuffleExercises) ?? false - self.shuffleSequences = try container.decodeIfPresent(Bool.self, forKey: .shuffleSequences) ?? false - } - - // MARK: Public - - public let id: String - public let name: String - public let description: String - public let image: String - public let shuffleExercises: Bool - public let shuffleSequences: Bool - public var sequence: [Exercise.Sequence] - - // MARK: Private - - private enum CodingKeys: String, CodingKey { - case id - case name - case description - case image - case sequence - case shuffleExercises = "shuffle_exercises" - case shuffleSequences = "shuffle_sequences" - } -} diff --git a/Modules/ContentKit/Sources/Activity/Activity.swift b/Modules/ContentKit/Sources/Activity/Activity.swift index 462cdc9d19..ec8700b61a 100644 --- a/Modules/ContentKit/Sources/Activity/Activity.swift +++ b/Modules/ContentKit/Sources/Activity/Activity.swift @@ -11,34 +11,32 @@ import Yams // swiftlint:disable nesting -public struct Activity: Codable, Identifiable { +public struct Activity: Decodable, Identifiable { // MARK: Lifecycle public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - // Allow synthesized Codable conformance to decode the rest self.uuid = try container.decode(String.self, forKey: .uuid) self.name = try container.decode(String.self, forKey: .name) + self.status = try container.decode(Status.self, forKey: .status) + self.authors = try container.decode([String].self, forKey: .authors) self.skills = try container.decode([String].self, forKey: .skills) self.hmi = try container.decode([String].self, forKey: .hmi) self.tags = try container.decode([String].self, forKey: .tags) - self.status = try container.decode(Status.self, forKey: .status) - self.gameengine = try container.decode(GameEngine.self, forKey: .gameengine) - - self.l10n = try container.decode([Localization].self, forKey: .l10n) -// exercises = try container.decode([ExerciseGroup].self, forKey: .exercises) let localeStrings = try container.decode([String].self, forKey: .locales) self.locales = localeStrings.compactMap { Locale(identifier: $0) } + self.l10n = try container.decode([LocalizedDetails].self, forKey: .l10n) + + self.exercisePayload = try container.decode(ExercisesPayload.self, forKey: .exercicesPayload) } // MARK: Public public let uuid: String public let name: String - public let status: Status public let authors: [String] // TODO: (@ladislas) - implement authors @@ -47,11 +45,9 @@ public struct Activity: Codable, Identifiable { public let tags: [String] // TODO: (@ladislas) - implement tags public let locales: [Locale] - public let l10n: [Localization] + public let l10n: [LocalizedDetails] - public let gameengine: GameEngine - - // public let exercises: [ExerciseGroup] + public var exercisePayload: ExercisesPayload public var id: String { self.uuid } public var languages: [Locale.LanguageCode] { self.locales.compactMap(\.language.languageCode) } @@ -81,24 +77,23 @@ public struct Activity: Codable, Identifiable { case status case locales case l10n - case gameengine -// case exercises + case exercicesPayload = "exercises_payload" } } // MARK: Activity.Status public extension Activity { - enum Status: String, Codable { + enum Status: String, Decodable { case draft case published } } -// MARK: Activity.Localization +// MARK: Activity.LocalizedDetails public extension Activity { - struct Localization: Codable { + struct LocalizedDetails: Decodable { // MARK: Lifecycle public init(from decoder: Decoder) throws { @@ -129,7 +124,7 @@ public extension Activity { // MARK: Activity.Details public extension Activity { - struct Details: Codable { + struct Details: Decodable { public let icon: String public let title: String public let subtitle: String @@ -143,26 +138,56 @@ public extension Activity { } } -// MARK: - GameEngine +// MARK: Activity.ExercisesPayload -public struct GameEngine: Codable { - // MARK: Internal +public extension Activity { + struct ExercisesPayload: Decodable { + // MARK: Internal - let shuffleExercises: Bool - let shuffleSequences: Bool + let options: Options + var exerciseGroups: [ExerciseGroup] - // MARK: Private + // MARK: Private - private enum CodingKeys: String, CodingKey { - case shuffleExercises = "shuffle_exercises" - case shuffleSequences = "shuffle_sequences" + private enum CodingKeys: String, CodingKey { + case options + case exerciseGroups = "exercise_groups" + } } } -// MARK: - ExerciseGroup +public extension Activity.ExercisesPayload { + struct Options: Decodable { + // MARK: Public + + public let shuffleExercises: Bool + public let shuffleGroups: Bool + + // MARK: Private + + private enum CodingKeys: String, CodingKey { + case shuffleExercises = "shuffle_exercises" + case shuffleGroups = "shuffle_groups" + } + } + + struct ExerciseGroup: Decodable { + // MARK: Lifecycle + + public init(exercises: [Exercise]) { + self.exercises = exercises + } -struct ExerciseGroup: Codable { - let group: [Exercise] + // MARK: Public + + public let exercises: [Exercise] + + // MARK: Private + + private enum CodingKeys: String, CodingKey { + case exercises = "group" + } + } } // swiftlint:enable nesting diff --git a/Modules/ContentKit/Sources/Activity/ActivityExerciseManager.swift b/Modules/ContentKit/Sources/Activity/ActivityExerciseManager.swift new file mode 100644 index 0000000000..274e36c3e7 --- /dev/null +++ b/Modules/ContentKit/Sources/Activity/ActivityExerciseManager.swift @@ -0,0 +1,71 @@ +// Leka - iOS Monorepo +// Copyright APF France handicap +// SPDX-License-Identifier: Apache-2.0 + +public class ActivityExerciseManager { + // MARK: Lifecycle + + public init(activity: Activity) { + var copyOfActivity = activity + + if copyOfActivity.exercisePayload.options.shuffleExercises { + copyOfActivity.exercisePayload.exerciseGroups = copyOfActivity.exercisePayload.exerciseGroups.map { + Activity.ExercisesPayload.ExerciseGroup(exercises: $0.exercises.shuffled()) + } + } + + if copyOfActivity.exercisePayload.options.shuffleGroups { + copyOfActivity.exercisePayload.exerciseGroups.shuffle() + } + + self.activity = copyOfActivity + } + + // MARK: Public + + public var currentGroupIndex: Int = 0 + public var currentExerciseIndexInCurrentGroup: Int = 0 + + public var totalGroups: Int { + self.activity.exercisePayload.exerciseGroups.count + } + + public var totalExercisesInCurrentGroup: Int { + self.activity.exercisePayload.exerciseGroups[self.currentGroupIndex].exercises.count + } + + public var currentExercise: Exercise { + self.activity.exercisePayload.exerciseGroups[self.currentGroupIndex].exercises[self.currentExerciseIndexInCurrentGroup] + } + + public var isFirstExercise: Bool { + self.currentExerciseIndexInCurrentGroup == 0 && self.currentGroupIndex == 0 + } + + public var isLastExercise: Bool { + self.currentExerciseIndexInCurrentGroup == self.activity.exercisePayload.exerciseGroups[self.currentGroupIndex].exercises.count - 1 + && self.currentGroupIndex == self.activity.exercisePayload.exerciseGroups.count - 1 + } + + public func moveToNextExercise() { + if self.currentExerciseIndexInCurrentGroup < self.activity.exercisePayload.exerciseGroups[self.currentGroupIndex].exercises.count - 1 { + self.currentExerciseIndexInCurrentGroup += 1 + } else if self.currentGroupIndex < self.activity.exercisePayload.exerciseGroups.count - 1 { + self.currentGroupIndex += 1 + self.currentExerciseIndexInCurrentGroup = 0 + } + } + + public func moveToPreviousExercise() { + if self.currentExerciseIndexInCurrentGroup > 0 { + self.currentExerciseIndexInCurrentGroup -= 1 + } else if self.currentGroupIndex > 0 { + self.currentGroupIndex -= 1 + self.currentExerciseIndexInCurrentGroup = self.activity.exercisePayload.exerciseGroups[self.currentGroupIndex].exercises.count - 1 + } + } + + // MARK: Private + + private let activity: Activity +} diff --git a/Modules/ContentKit/Sources/Activity/ActivitySequenceManager.swift b/Modules/ContentKit/Sources/Activity/ActivitySequenceManager.swift deleted file mode 100644 index 684223d3e2..0000000000 --- a/Modules/ContentKit/Sources/Activity/ActivitySequenceManager.swift +++ /dev/null @@ -1,71 +0,0 @@ -// Leka - iOS Monorepo -// Copyright APF France handicap -// SPDX-License-Identifier: Apache-2.0 - -public class ActivitySequenceManager { - // MARK: Lifecycle - - public init(activity: ActivityDeprecated) { - var localActivity = activity - - if localActivity.shuffleExercises { - localActivity.sequence = localActivity.sequence.map { sequence in - Exercise.Sequence(exercises: sequence.exercises.shuffled()) - } - } - - if localActivity.shuffleSequences { - localActivity.sequence.shuffle() - } - - self.activity = localActivity - } - - // MARK: Public - - public var currentSequenceIndex: Int = 0 - public var currentExerciseIndexInSequence: Int = 0 - - public var totalSequences: Int { - self.activity.sequence.count - } - - public var totalExercisesInCurrentSequence: Int { - self.activity.sequence[self.currentSequenceIndex].exercises.count - } - - public var currentExercise: Exercise { - self.activity.sequence[self.currentSequenceIndex].exercises[self.currentExerciseIndexInSequence] - } - - public var isFirstExercise: Bool { - self.currentExerciseIndexInSequence == 0 && self.currentSequenceIndex == 0 - } - - public var isLastExercise: Bool { - self.currentExerciseIndexInSequence == self.activity.sequence[self.currentSequenceIndex].exercises.count - 1 - && self.currentSequenceIndex == self.activity.sequence.count - 1 - } - - public func moveToNextExercise() { - if self.currentExerciseIndexInSequence < self.activity.sequence[self.currentSequenceIndex].exercises.count - 1 { - self.currentExerciseIndexInSequence += 1 - } else if self.currentSequenceIndex < self.activity.sequence.count - 1 { - self.currentSequenceIndex += 1 - self.currentExerciseIndexInSequence = 0 - } - } - - public func moveToPreviousExercise() { - if self.currentExerciseIndexInSequence > 0 { - self.currentExerciseIndexInSequence -= 1 - } else if self.currentSequenceIndex > 0 { - self.currentSequenceIndex -= 1 - self.currentExerciseIndexInSequence = self.activity.sequence[self.currentSequenceIndex].exercises.count - 1 - } - } - - // MARK: Private - - private let activity: ActivityDeprecated -} diff --git a/Modules/ContentKit/Sources/ContentKit+Decode+DEPRECATED.swift b/Modules/ContentKit/Sources/ContentKit+Decode+DEPRECATED.swift deleted file mode 100644 index b2b125bf21..0000000000 --- a/Modules/ContentKit/Sources/ContentKit+Decode+DEPRECATED.swift +++ /dev/null @@ -1,44 +0,0 @@ -// Leka - iOS Monorepo -// Copyright APF France handicap -// SPDX-License-Identifier: Apache-2.0 - -import Foundation -import Yams - -public extension ContentKit { - // TODO(@ladislas): maybe return optional activity instead of fatalError - static func decodeActivityDeprecated(_ filename: String) -> ActivityDeprecated { - do { - guard let file = Bundle.main.path(forResource: filename, ofType: "yml") else { - log.error("File not found: \(filename)") - fatalError("💥 File not found: \(filename)") - } - - let data = try String(contentsOfFile: file, encoding: .utf8) - let activity = try YAMLDecoder().decode(ActivityDeprecated.self, from: data) - - return activity - } catch { - log.error("Error decoding \(filename): \(error)") - fatalError("💥 Error decoding \(filename): \(error)") - } - } - - // TODO(@ladislas): maybe return optional activity instead of fatalError - static func decodeActivityFromModuleDeprecated(_ filename: String) -> ActivityDeprecated { - do { - guard let file = Bundle.module.path(forResource: filename, ofType: "yml") else { - log.error("File not found: \(filename)") - fatalError("💥 File not found: \(filename)") - } - - let data = try String(contentsOfFile: file, encoding: .utf8) - let activity = try YAMLDecoder().decode(ActivityDeprecated.self, from: data) - - return activity - } catch { - log.error("Error decoding \(filename): \(error)") - fatalError("💥 Error decoding \(filename): \(error)") - } - } -} diff --git a/Modules/ContentKit/Sources/Exercise/Exercise+Sequence.swift b/Modules/ContentKit/Sources/Exercise/Exercise+Sequence.swift deleted file mode 100644 index 585a5b5893..0000000000 --- a/Modules/ContentKit/Sources/Exercise/Exercise+Sequence.swift +++ /dev/null @@ -1,11 +0,0 @@ -// Leka - iOS Monorepo -// Copyright APF France handicap -// SPDX-License-Identifier: Apache-2.0 - -import Foundation - -public extension Exercise { - struct Sequence: Codable { - public let exercises: [Exercise] - } -} diff --git a/Modules/ContentKit/Sources/Exercise/Exercise.swift b/Modules/ContentKit/Sources/Exercise/Exercise.swift index 8941352fb0..af31f35524 100644 --- a/Modules/ContentKit/Sources/Exercise/Exercise.swift +++ b/Modules/ContentKit/Sources/Exercise/Exercise.swift @@ -3,17 +3,42 @@ // SPDX-License-Identifier: Apache-2.0 import Foundation +import LocalizationKit +import LogKit -public struct Exercise: Codable { +// MARK: - Exercise + +public struct Exercise: Decodable { // MARK: Lifecycle public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - self.instructions = try container.decode(String.self, forKey: .instructions) self.interface = try container.decode(Interface.self, forKey: .interface) self.gameplay = try container.decodeIfPresent(Gameplay.self, forKey: .gameplay) self.action = try container.decodeIfPresent(Action.self, forKey: .action) + self.localizedInstructions = try? container.decode([LocalizedInstructions].self, forKey: .localizedInstructions) + + log.debug("localizedInstructions: \(self.localizedInstructions)") + + if let localizedInstructions = self.localizedInstructions { + let availableLocales = localizedInstructions.map(\.locale) + log.debug("\(availableLocales)") + + let currentLocale = availableLocales.first(where: { + $0.language.languageCode == LocalizationKit.l10n.language + }) ?? Locale(identifier: "en_US") + + log.debug("Current Language: \(LocalizationKit.l10n.language)") + log.debug("currentLocale: \(currentLocale)") + + self.instructions = self.localizedInstructions?.first(where: { $0.locale == currentLocale })?.value + // log.debug("instructions: \(self.instructions)") + log.debug("Selected Instructions: \(String(describing: self.instructions))") + } else { + self.instructions = nil + } + switch (self.interface, self.gameplay) { case (.touchToSelect, .findTheRightAnswers), (.listenThenTouchToSelect, .findTheRightAnswers), @@ -51,23 +76,42 @@ public struct Exercise: Codable { // MARK: Public - public let instructions: String + public let instructions: String? public let interface: Interface public let gameplay: Gameplay? public let action: Action? public let payload: ExercisePayloadProtocol? - public func encode(to _: Encoder) throws { - fatalError("💥 Not implemented yet") - } - // MARK: Internal enum CodingKeys: String, CodingKey { - case instructions + case localizedInstructions = "instructions" case interface case gameplay case action case payload } + + // MARK: Private + + private let localizedInstructions: [LocalizedInstructions]? +} + +// MARK: Exercise.LocalizedInstructions + +public extension Exercise { + struct LocalizedInstructions: Codable { + // MARK: Lifecycle + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.locale = try Locale(identifier: container.decode(String.self, forKey: .locale)) + self.value = try container.decode(String.self, forKey: .value) + } + + // MARK: Internal + + let locale: Locale + let value: String + } } diff --git a/Modules/ContentKit/Sources/Mocks/Activity+Mock.swift b/Modules/ContentKit/Sources/Mocks/Activity+Mock.swift index 2dece2979c..ae676be759 100644 --- a/Modules/ContentKit/Sources/Mocks/Activity+Mock.swift +++ b/Modules/ContentKit/Sources/Mocks/Activity+Mock.swift @@ -13,108 +13,109 @@ public extension Activity { // swiftformat:disable all private static let mockActivityYaml = """ - version: 1.0.0 - - uuid: E7EE9CA4B13B49AF96CD77A9DF90833B - name: mock_activity - - status: published - - authors: - - leka - - aurore_kiesler - - julie_tuil - - skills: - - spatial_understanding - - recognition/animals - - communication/non_verbal_communication/gestures - - tags: - - tag_one - - tag_two - - tag_three - - hmi: - - robot - - magic_cards - - tablet_robot - - locales: - - en_US - - fr_FR - - l10n: - - locale: fr_FR - details: - icon: name_of_the_activity-icon-fr_FR.svg - - title: Activité d'exemple - subtitle: pour le développement - - description: | - Activité d'exemple utilisée pour le développement de l'application - - instructions: | - ## Longues instructions en markdown plus complexe si on veut - - Lorem markdownum recepta avidum, missa de quam patientia, antris: cum defuit, - Titan repetemus nomine, ignare. Quod ad aura, et non quod vidisse utque ulla: - - - Pro inposuit tibi orsa tum artes ferox - - Acmon plausu qua agrestum situs virgo in - - Vacuus a pendens rostro non si pharetrae - - Haeremusque quos auxiliaris coniunx - - Repulsa impediunt munera teneri fallebat - - Bracchia frustra telo Iovis faucibus casus - - - locale: en_US - details: - icon: name_of_the_activity-icon-en_US.svg - - title: Sample activity - subtitle: for development - - description: | - Sample activity used for the development of the application - - instructions: | - ## Long instructions in markdown more complex if we want - - Lorem markdownum recepta avidum, missa de quam patientia, antris: cum defuit, - Titan repetemus nomine, ignare. Quod ad aura, et non quod vidisse utque ulla: - - - Pro inposuit tibi orsa tum artes ferox - - Acmon plausu qua agrestum situs virgo in - - Vacuus a pendens rostro non si pharetrae - - Haeremusque quos auxiliaris coniunx - - Repulsa impediunt munera teneri fallebat - - Bracchia frustra telo Iovis faucibus casus - - gameengine: - shuffle_exercises: true - shuffle_sequences: true - - exercises: - - group: - - instructions: - - locale: fr_FR - value: Touch le rond jaune - - locale: en_US - value: Touch the yellow circle - interface: touchToSelect - gameplay: findTheRightAnswers - payload: - choices: - - value: yellow - type: color - isRightAnswer: true - - value: red - type: color - - value: green - type: color - - value: blue - type: color - """ + version: 1.0.0 + + uuid: E7EE9CA4B13B49AF96CD77A9DF90833B + name: mock_activity + + status: published + + authors: + - leka + - aurore_kiesler + - julie_tuil + + skills: + - spatial_understanding + - recognition/animals + - communication/non_verbal_communication/gestures + + tags: + - tag_one + - tag_two + - tag_three + + hmi: + - robot + - magic_cards + - tablet_robot + + locales: + - en_US + - fr_FR + + l10n: + - locale: fr_FR + details: + icon: name_of_the_activity-icon-fr_FR.svg + + title: Activité d'exemple + subtitle: pour le développement + + description: | + Activité d'exemple utilisée pour le développement de l'application + + instructions: | + ## Longues instructions en markdown plus complexe si on veut + + Lorem markdownum recepta avidum, missa de quam patientia, antris: cum defuit, + Titan repetemus nomine, ignare. Quod ad aura, et non quod vidisse utque ulla: + + - Pro inposuit tibi orsa tum artes ferox + - Acmon plausu qua agrestum situs virgo in + - Vacuus a pendens rostro non si pharetrae + - Haeremusque quos auxiliaris coniunx + - Repulsa impediunt munera teneri fallebat + - Bracchia frustra telo Iovis faucibus casus + + - locale: en_US + details: + icon: name_of_the_activity-icon-en_US.svg + + title: Sample activity + subtitle: for development + + description: | + Sample activity used for the development of the application + + instructions: | + ## Long instructions in markdown more complex if we want + + Lorem markdownum recepta avidum, missa de quam patientia, antris: cum defuit, + Titan repetemus nomine, ignare. Quod ad aura, et non quod vidisse utque ulla: + + - Pro inposuit tibi orsa tum artes ferox + - Acmon plausu qua agrestum situs virgo in + - Vacuus a pendens rostro non si pharetrae + - Haeremusque quos auxiliaris coniunx + - Repulsa impediunt munera teneri fallebat + - Bracchia frustra telo Iovis faucibus casus + + exercises_payload: + options: + shuffle_exercises: true + shuffle_groups: true + + exercise_groups: + - group: + - instructions: + - locale: fr_FR + value: Touch le rond jaune + - locale: en_US + value: Touch the yellow circle + interface: touchToSelect + gameplay: findTheRightAnswers + payload: + choices: + - value: yellow + type: color + isRightAnswer: true + - value: red + type: color + - value: green + type: color + - value: blue + type: color + """ // swiftformat:enable all } diff --git a/Modules/GameEngineKit/Sources/_NewSystem/Views/Activity/ActivityViewViewModel.swift b/Modules/GameEngineKit/Sources/_NewSystem/Views/Activity/ActivityViewViewModel.swift index d54166ba3b..e1ca3c6e3d 100644 --- a/Modules/GameEngineKit/Sources/_NewSystem/Views/Activity/ActivityViewViewModel.swift +++ b/Modules/GameEngineKit/Sources/_NewSystem/Views/Activity/ActivityViewViewModel.swift @@ -10,7 +10,7 @@ public class ActivityViewViewModel: ObservableObject { // MARK: Lifecycle public init(activity: ActivityDeprecated) { - self.sequenceManager = ActivitySequenceManager(activity: activity) + self.sequenceManager = ActivityExerciseManager(activity: activity) self.currentActivity = activity @@ -116,7 +116,7 @@ public class ActivityViewViewModel: ObservableObject { // MARK: Private - private let sequenceManager: ActivitySequenceManager + private let sequenceManager: ActivityExerciseManager private var cancellables: Set = [] diff --git a/Specs/jtd/activity.jtd.json b/Specs/jtd/activity.jtd.json index b9323af99e..a1a6ba96e5 100644 --- a/Specs/jtd/activity.jtd.json +++ b/Specs/jtd/activity.jtd.json @@ -42,20 +42,24 @@ "ref": "$l10n" } }, - "gameengine": { + "exercises_payload": { "properties": { - "shuffle_exercises": { - "type": "boolean" + "options": { + "properties": { + "shuffle_exercises": { + "type": "boolean" + }, + "shuffle_groups": { + "type": "boolean" + } + } }, - "shuffle_sequences": { - "type": "boolean" + "exercise_groups": { + "elements": { + "ref": "$group" + } } } - }, - "exercises": { - "elements": { - "ref": "$group" - } } }, "definitions": {