diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 3c38b2960..eb50872c9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -39,7 +39,7 @@ jobs:
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - run: npm install --no-save @microbit-foundation/ml-trainer-microbit@0.2.0-dev.75 @microbit-foundation/website-deploy-aws@0.6 @microbit-foundation/website-deploy-aws-config@0.10
+ - run: npm install --no-save @microbit-foundation/ml-trainer-microbit@0.2.0-dev.78 @microbit-foundation/website-deploy-aws@0.6 @microbit-foundation/website-deploy-aws-config@0.10
if: github.repository_owner == 'microbit-foundation'
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/lang/ui.ca.json b/lang/ui.ca.json
index 63b02c458..5cc9b2123 100644
--- a/lang/ui.ca.json
+++ b/lang/ui.ca.json
@@ -55,6 +55,14 @@
"defaultMessage": "Afegir una acció",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "Temporitzador d'activitat d'IA",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "Cable micro USB",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "Connecta una micro:bit de recollida de dades o importa mostres de dades",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "Copia el patró",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "Més edició a les opcions de MakeCode",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "Anomena una acció que vulguis que reconegui la micro:bit",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "Següent",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "No hi ha mostres de dades",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "Aquest projecte no contenia cap mostra de dades, de manera que només s'ha obert el programa. Has d'entrenar un model abans de poder utilitzar el programa.",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "Prem per gravar una mostra de dades o prem el botó B de la teva micro:bit de recollida de dades.",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "Enregistra {numSamples} mostres",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "Entrenant un model",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "Entrenant un model",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "desconnecta i torna a connectar el cable USB",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.en.json b/lang/ui.en.json
index aed989dd0..3e48560fe 100644
--- a/lang/ui.en.json
+++ b/lang/ui.en.json
@@ -55,6 +55,14 @@
"defaultMessage": "Add action",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "AI activity timer",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "Micro USB cable",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "Connect a data collection micro:bit or import data samples",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "Copy pattern",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,8 +1183,12 @@
"defaultMessage": "More edit in MakeCode options",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
- "defaultMessage": "Name an action you want the micro:bit to recognise",
+ "defaultMessage": "Name an action you want CreateAI to recognise, like ‘waving’ or ‘jumping’",
"description": "Hint shown when you have an unnamed action"
},
"name-project": {
@@ -1251,10 +1259,6 @@
"defaultMessage": "Next",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "No data samples",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "This project did not contain any data samples, so only the code has been opened. You need to train a model before you can use the code.",
"description": "Content of import non-CreateAI hex dialog"
@@ -1392,13 +1396,21 @@
"description": "Aria label for record button"
},
"record-hint": {
- "defaultMessage": "Press to record a data sample.",
+ "defaultMessage": "Press record to collect a movement data sample.",
"description": "Hint when you have named the first action but not recorded any data samples"
},
"record-hint-button-b": {
- "defaultMessage": "Press to record a data sample or press button B on your data collection micro:bit.",
+ "defaultMessage": "Press record or button B on the micro:bit to collect a movement data sample.",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "Record {numSamples} samples",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "Training a model",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "Train model",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "unplug and replug the USB cable",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.es-es.json b/lang/ui.es-es.json
index e9d4c5c9d..26f2b2867 100644
--- a/lang/ui.es-es.json
+++ b/lang/ui.es-es.json
@@ -55,6 +55,14 @@
"defaultMessage": "Añadir acción",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "Temporizador de actividad de IA",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "Cable micro USB",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "Conecta una colección de datos de micro:bit o importa muestras de datos",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "Copiar patrón",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "Más edición en opciones de MakeCode",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "Nombra una acción que quieras que reconozca el micro:bit",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "Siguiente",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "No hay muestras de datos",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "Este proyecto no contenía ninguna muestra de datos, por lo que sólo se ha abierto el código. Necesitas entrenar un modelo antes de poder utilizar el código.",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "Pulsa para grabar una muestra de datos o pulsa el botón B de tu micro:bit de recogida de datos.",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "Grabar {numSamples} muestras",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "Entrenar un modelo",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "Entrenar modelo",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "desenchufa y vuelve a enchufar el cable USB",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.fr.json b/lang/ui.fr.json
index a157e961c..e4ab42c75 100644
--- a/lang/ui.fr.json
+++ b/lang/ui.fr.json
@@ -55,6 +55,14 @@
"defaultMessage": "Ajouter une action",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "Minuteur d'activité IA",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "Câble Micro USB",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "Connecter un micro:bit de collecte de données ou importer des échantillons de données",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "Copier le motif",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "Plus de modifications dans les options MakeCode",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "Nommez une action que vous voulez que le micro:bit reconnaisse",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "Suivant",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "Aucun échantillon de données",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "Ce projet ne contenait pas d'échantillons de données, donc seul le code a été ouvert. Vous devez entraîner un modèle avant de pouvoir utiliser le code.",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "Appuyez pour enregistrer un échantillon de données ou appuyez sur le bouton B de votre micro:bit de collecte de données.",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "Enregistrer {numSamples} échantillons ",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "Entraînement d'un modèle",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "Entraîner le modèle",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "débrancher et rebrancher le câble USB",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.ja.json b/lang/ui.ja.json
index 96aa34ece..67e680411 100644
--- a/lang/ui.ja.json
+++ b/lang/ui.ja.json
@@ -55,6 +55,14 @@
"defaultMessage": "アクションを追加",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "AI活動タイマー",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "マイクロUSBケーブル",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "データ収集用micro:bitを接続 または データサンプルのインポート",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "パターンをコピー",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "MakeCodeのオプションをさらに編集する",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "micro:bitに認識させたいアクションに名前を付けてください",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "次",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "データサンプルがありません",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "このプロジェクトにはデータサンプルが含まれていないため、プログラムだけが開かれています。 プログラムを使う前に、モデルを訓練する必要があります。",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "データサンプルを記録するには、データ収集用micro:bitのボタンBを押します。",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "{numSamples} サンプルを記録",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "モデルのトレーニング",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "モデルのトレーニング",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "USBケーブルを抜いて再接続",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.ko.json b/lang/ui.ko.json
index 4e83005e2..b053d1589 100644
--- a/lang/ui.ko.json
+++ b/lang/ui.ko.json
@@ -55,6 +55,14 @@
"defaultMessage": "행동 추가",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "AI 활동 타이머",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "마이크로 USB 케이블",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "데이터 수집 micro:bit에 연결하기 또는 데이터 샘플 가져오기를 하세요.",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "패턴 복사",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "MakeCode 옵션에서 추가 편집",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "micro:bit가 인식할 행동의 이름 지정하기",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "다음",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "데이터 샘플 없음",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "이 프로젝트에는 데이터 샘플이 없어 코드만 공개되었습니다. 코드를 사용하기 전에 모델을 훈련해야 합니다.",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "눌러서 데이터 샘플을 기록하거나 데이터 수집 micro:bit의 B 버튼을 누르세요.",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "샘플 {numSamples}개 기록",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "모델 훈련 중",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "모델 훈련",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "USB 케이블을 분리했다가 다시 연결하세요.",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.lol.json b/lang/ui.lol.json
index 7a853407d..120af14fe 100644
--- a/lang/ui.lol.json
+++ b/lang/ui.lol.json
@@ -55,6 +55,14 @@
"defaultMessage": "crwdns362672:0crwdne362672:0",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "crwdns362674:0crwdne362674:0",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "crwdns362770:0crwdne362770:0",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "crwdns362772:0crwdne362772:0",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "crwdns362774:0crwdne362774:0",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "crwdns363178:0crwdne363178:0",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "crwdns363180:0crwdne363180:0",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "crwdns363214:0crwdne363214:0",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "crwdns363216:0crwdne363216:0",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "crwdns363218:0crwdne363218:0",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "crwdns363274:0crwdne363274:0",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "crwdns363276:0{numSamples}crwdne363276:0",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "crwdns363434:0crwdne363434:0",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "crwdns363436:0crwdne363436:0",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "crwdns363476:0crwdne363476:0",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.nl.json b/lang/ui.nl.json
index 77d7b1140..7e4f1f1a0 100644
--- a/lang/ui.nl.json
+++ b/lang/ui.nl.json
@@ -55,6 +55,14 @@
"defaultMessage": "Voeg actie toe",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "AI activiteiten timer",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "Micro USB-kabel",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "Verbind een micro:bit die gegevens verzamelt of importeer data samples",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "Kopieer patroon",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "Meer opties voor bewerken in MakeCode",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "Geef een naam aan een actie die je wilt dat de micro:bit herkent",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "Volgende",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "Geen data samples",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "Dit project bevatte geen data samples, dus alleen de code is geopend. Je moet een model trainen voordat je de code kunt gebruiken.",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "Klik om een data sample op te nemen of druk op knop B op jouw data collectie micro:bit.",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "Neem {numSamples} samples op",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "Model trainen",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "Train model",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "de USB-kabel ontkoppelen en opnieuw aansluiten",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.pl.json b/lang/ui.pl.json
index c8167b527..b3473dc3b 100644
--- a/lang/ui.pl.json
+++ b/lang/ui.pl.json
@@ -55,6 +55,14 @@
"defaultMessage": "Dodaj działanie",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "Licznik aktywności AI",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "Kabel Micro USB",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "Podłącz micro:bit zbierający dane lub importuj próbki danych",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "Kopiuj wzór",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "Więcej edycji w opcjach MakeCode",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "Nazwij akcję którą chcesz, aby micro:bit rozpoznał",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "Dalej",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "Brak próbek danych",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "Ten projekt nie zawierał żadnych próbek danych, tylko kod został otwarty. Musisz wytrenować model, zanim będziesz mógł użyć kodu.",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "Naciśnij, aby nagrać próbkę danych lub naciśnij przycisk B na micro:bicie do zbierana danych.",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "Zapisz próbki {numSamples}",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "Trenowanie modelu",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "Trenuj model",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "odłącz i podłącz kabel USB",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.pt-br.json b/lang/ui.pt-br.json
index ba2526cae..00e65ab2d 100644
--- a/lang/ui.pt-br.json
+++ b/lang/ui.pt-br.json
@@ -55,6 +55,14 @@
"defaultMessage": "Adicionar ação",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "Cronômetro de atividades de IA",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "Cabo Micro USB",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "Conecte um micro:bit de coleta de dados ou importe as amostras de dados",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "Copiar padrão",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "Mais opções de edição no MakeCode.",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "Nomeie uma ação que você deseja que o micro:bit reconheça.",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "Próximo",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "Nenhuma amostra de dados",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "Este projeto não contém amostras de dados, portanto, apenas o código foi aberto. Você precisa treinar um modelo antes de poder usar o código.",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "Pressione para gravar uma amostra de dados ou pressione o botão B no seu micro:bit de coleta de dados.",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "Gravar {numSamples} amostras",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "Treinando um modelo.",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "Treinar modelo.",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "Desconecte e reconecte o cabo USB.",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/lang/ui.zh-tw.json b/lang/ui.zh-tw.json
index 81b58739b..0c870a737 100644
--- a/lang/ui.zh-tw.json
+++ b/lang/ui.zh-tw.json
@@ -55,6 +55,14 @@
"defaultMessage": "新增動作",
"description": "Button to add an action (movement related, e.g. clapping)"
},
+ "add-action-hint": {
+ "defaultMessage": "Finished recording for {actionName}?Add another action",
+ "description": "Hint when you have recorded enough data samples for one action"
+ },
+ "add-action-hint-label": {
+ "defaultMessage": "Finished recording for {actionName}? Press ‘Add action’ button to add another action",
+ "description": "Hint when you have recorded enough data samples for one action aria label"
+ },
"ai-activity-timer-resource-title": {
"defaultMessage": "AI 活動計時器",
"description": "Home page resource card title"
@@ -259,10 +267,6 @@
"defaultMessage": "微型 USB 纜線",
"description": "Label for cable icon in list of requirements"
},
- "connect-or-import": {
- "defaultMessage": "連線數據收集用的 micro:bit 或匯入數據樣本",
- "description": "Empty data samples page text"
- },
"connect-pattern-heading": {
"defaultMessage": "複製圖案",
"description": "Heading for Bluetooth pattern connection dialog"
@@ -1179,6 +1183,10 @@
"defaultMessage": "在 MakeCode 選項中進行更多編輯",
"description": "Aria label for the additional actions menu to the right of the Edit in MakeCode button"
},
+ "move-hint": {
+ "defaultMessage": "Move the micro:bit to explore how different actions change the graph",
+ "description": "Hint when you have just connected a micro:bit"
+ },
"name-action-hint": {
"defaultMessage": "命名您希望 micro:bit 辨識的動作",
"description": "Hint shown when you have an unnamed action"
@@ -1251,10 +1259,6 @@
"defaultMessage": "下一個",
"description": "Next button text for dialogs and similar"
},
- "no-data-samples": {
- "defaultMessage": "沒有數據樣本",
- "description": "Empty data samples page status text"
- },
"not-create-ai-hex-import-dialog-content": {
"defaultMessage": "這項專案不包含任何數據樣本,因此僅開啟程式碼。您需要先訓練模型,然後才能使用程式碼。",
"description": "Content of import non-CreateAI hex dialog"
@@ -1399,6 +1403,14 @@
"defaultMessage": "按下以記錄數據樣本或是按下您的數據收集用的 micro:bit 上的按鍵 B。",
"description": "Hint when you have named the first action but not recorded any data samples and have a micro:bit connected"
},
+ "record-more-hint": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}}",
+ "description": "Hint when you have not recorded enough data samples. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
+ "record-more-hint-label": {
+ "defaultMessage": "Record at least {numSamples, plural, one {{numSamples} more data sample} other {{numSamples} more data samples}} for {actionName}",
+ "description": "Hint when you have not recorded enough data samples aria label. Uses ICU syntax for pluralisation: https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format."
+ },
"record-samples": {
"defaultMessage": "記錄 {numSamples} 個樣本",
"description": "Additional recording action text"
@@ -1723,6 +1735,14 @@
"defaultMessage": "訓練模型",
"description": "Training dialog"
},
+ "train-hint": {
+ "defaultMessage": "Finished recording?Train the model",
+ "description": "Hint when you have recorded enough data samples to train a model"
+ },
+ "train-hint-label": {
+ "defaultMessage": "Finished recording? Press ‘Train the model’ button to train the model",
+ "description": "Hint when you have recorded enough data samples to train a model aria label"
+ },
"train-model": {
"defaultMessage": "訓練模型",
"description": "Action to train a model"
@@ -1806,5 +1826,9 @@
"webusb-retry-replug4": {
"defaultMessage": "拔下並重新插入 USB 纜線",
"description": "WebUSB error dialog"
+ },
+ "welcome-title": {
+ "defaultMessage": "Welcome to micro:bit CreateAI",
+ "description": "Welcome dialog"
}
}
\ No newline at end of file
diff --git a/src/buffered-data-hooks.tsx b/src/buffered-data-hooks.tsx
index 3f5fa45c9..8237e4e7d 100644
--- a/src/buffered-data-hooks.tsx
+++ b/src/buffered-data-hooks.tsx
@@ -4,7 +4,10 @@
*
* SPDX-License-Identifier: MIT
*/
-import { AccelerometerDataEvent } from "@microbit/microbit-connection";
+import {
+ AccelerometerData,
+ AccelerometerDataEvent,
+} from "@microbit/microbit-connection";
import {
ReactNode,
createContext,
@@ -73,3 +76,60 @@ const useBufferedDataInternal = (): BufferedData => {
}, [connection, connectStatus, getBuffer]);
return getBuffer();
};
+
+export const useHasMoved = (): boolean => {
+ const hasMoved = useStore((s) => s.hasMoved);
+ const setHasMoved = useStore((s) => s.setHasMoved);
+ const [connectStatus] = useConnectStatus();
+ const connection = useConnectActions();
+ useEffect(() => {
+ if (connectStatus !== ConnectionStatus.Connected) {
+ setHasMoved(false);
+ }
+ let ignore = false;
+ const delta: AccelerometerData = { x: 0, y: 0, z: 0 };
+ let lastSample: AccelerometerData | undefined;
+ const threshold = 40_000;
+ const minDelta = 100;
+ const skipSamples = 10;
+ let skipped = 0;
+ const listener = (e: AccelerometerDataEvent) => {
+ if (skipped < skipSamples) {
+ skipped++;
+ } else if (lastSample) {
+ const deltaX = Math.abs(lastSample.x - e.data.x);
+ if (deltaX > minDelta) {
+ delta.x += deltaX;
+ }
+ const deltaY = Math.abs(lastSample.y - e.data.y);
+ if (deltaY > minDelta) {
+ delta.y += deltaY;
+ }
+ const deltaZ = Math.abs(lastSample.z - e.data.z);
+ if (deltaZ > minDelta) {
+ delta.z += deltaZ;
+ }
+ }
+ lastSample = e.data;
+ if (
+ (delta.x > threshold ? 1 : 0) +
+ (delta.y > threshold ? 1 : 0) +
+ (delta.z > threshold ? 1 : 0) >
+ 1
+ ) {
+ connection.removeAccelerometerListener(listener);
+ if (!ignore) {
+ setHasMoved(true);
+ }
+ }
+ };
+ if (!hasMoved) {
+ connection.addAccelerometerListener(listener);
+ }
+ return () => {
+ ignore = true;
+ connection.removeAccelerometerListener(listener);
+ };
+ }, [connection, connectStatus, hasMoved, setHasMoved]);
+ return hasMoved;
+};
diff --git a/src/components/ActionNameCard.tsx b/src/components/ActionNameCard.tsx
index 196df69af..6d0eb0d9a 100644
--- a/src/components/ActionNameCard.tsx
+++ b/src/components/ActionNameCard.tsx
@@ -55,6 +55,7 @@ const ActionNameCard = ({
const toastId = "name-too-long-toast";
const setActionName = useStore((s) => s.setActionName);
const setActionIcon = useStore((s) => s.setActionIcon);
+ const setHint = useStore((s) => s.setHint);
const { icon, ID: id } = value;
const [localName, setLocalName] = useState(value.name);
const predictionResult = useStore((s) => s.predictionResult);
@@ -70,11 +71,22 @@ const ActionNameCard = ({
setActionName(id, name);
},
400,
+ // Allowing the first 'Record' button to appear immediately so that
+ // users can keyboard navigate to the button immediately after naming
+ // their first action.
{ leading: true }
),
[setActionName]
);
+ const debouncedSetHint = useMemo(
+ () =>
+ // Set hint on the trailing end of inputting action name to avoid
+ // aria-live for hint from being interrupted by inputting of action name.
+ debounce(() => setHint(false), 400, { leading: false, trailing: true }),
+ [setHint]
+ );
+
const onChange: React.ChangeEventHandler = useCallback(
(e) => {
const name = e.target.value;
@@ -95,8 +107,9 @@ const ActionNameCard = ({
}
setLocalName(name);
debouncedSetActionName(id, name);
+ debouncedSetHint();
},
- [debouncedSetActionName, id, intl, toast]
+ [debouncedSetActionName, debouncedSetHint, id, intl, toast]
);
const handleIconSelected = useCallback(
diff --git a/src/components/ConnectFirstDialog.tsx b/src/components/ConnectFirstDialog.tsx
index 5235f0129..ffbf40228 100644
--- a/src/components/ConnectFirstDialog.tsx
+++ b/src/components/ConnectFirstDialog.tsx
@@ -35,107 +35,127 @@ const ConnectFirstDialog = ({
isOpen,
...rest
}: ConnectFirstDialogProps) => {
+ const { handleClose, isConnecting, handleConnect } = useConnectFirst({
+ isOpen,
+ onClose,
+ onConnect: onChooseConnect,
+ connectOptions: options,
+ });
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export const useConnectFirst = ({
+ isOpen,
+ onClose,
+ onConnect,
+ connectOptions,
+}: {
+ isOpen: boolean;
+ onClose: () => void;
+ onConnect?: () => void;
+ connectOptions?: ConnectOptions;
+}) => {
const {
actions,
status: connStatus,
isDialogOpen: isConnectionDialogOpen,
} = useConnectionStage();
- const [isWaiting, setIsWaiting] = useState(false);
+ const [isConnecting, setIsConnecting] = useState(false);
- const handleOnClose = useCallback(() => {
- setIsWaiting(false);
+ const handleClose = useCallback(() => {
+ setIsConnecting(false);
onClose();
}, [onClose]);
const handleConnect = useCallback(async () => {
- onChooseConnect?.();
+ onConnect?.();
switch (connStatus) {
case ConnectionStatus.FailedToConnect:
case ConnectionStatus.FailedToReconnectTwice:
case ConnectionStatus.FailedToSelectBluetoothDevice:
case ConnectionStatus.NotConnected: {
// Start connection flow.
- actions.startConnect(options);
- return handleOnClose();
+ actions.startConnect(connectOptions);
+ return handleClose();
}
case ConnectionStatus.ConnectionLost:
case ConnectionStatus.FailedToReconnect:
case ConnectionStatus.Disconnected: {
// Reconnect.
await actions.reconnect();
- return handleOnClose();
+ return handleClose();
}
case ConnectionStatus.ReconnectingAutomatically: {
// Wait for reconnection to happen.
- setIsWaiting(true);
+ setIsConnecting(true);
return;
}
case ConnectionStatus.Connected: {
// Connected whilst dialog is up.
- return handleOnClose();
+ return handleClose();
}
case ConnectionStatus.ReconnectingExplicitly:
case ConnectionStatus.Connecting: {
// Impossible cases.
- return handleOnClose();
+ return handleClose();
}
}
- }, [onChooseConnect, connStatus, actions, options, handleOnClose]);
+ }, [onConnect, connStatus, actions, connectOptions, handleClose]);
useEffect(() => {
if (
isOpen &&
(isConnectionDialogOpen ||
- (isWaiting && connStatus === ConnectionStatus.Connected))
+ (isConnecting && connStatus === ConnectionStatus.Connected))
) {
// Close dialog if connection dialog is opened, or
// once connected after waiting.
- handleOnClose();
+ handleClose();
return;
}
}, [
connStatus,
- handleOnClose,
+ handleClose,
isConnectionDialogOpen,
isOpen,
- isWaiting,
+ isConnecting,
onClose,
]);
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return { handleConnect, isConnecting, handleClose };
};
export default ConnectFirstDialog;
diff --git a/src/components/DataSamplesTable.tsx b/src/components/DataSamplesTable.tsx
index 1f6d7ffcf..b781388b6 100644
--- a/src/components/DataSamplesTable.tsx
+++ b/src/components/DataSamplesTable.tsx
@@ -4,42 +4,27 @@
*
* SPDX-License-Identifier: MIT
*/
-import {
- Button,
- Grid,
- GridProps,
- HStack,
- Text,
- VStack,
-} from "@chakra-ui/react";
+import { Grid, GridProps, HStack, Text } from "@chakra-ui/react";
import { ButtonEvent } from "@microbit/microbit-connection";
-import {
- ReactNode,
- useCallback,
- useEffect,
- useMemo,
- useRef,
- useState,
-} from "react";
+import { useCallback, useEffect, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { useConnectActions } from "../connect-actions-hooks";
import { useConnectionStage } from "../connection-stage-hooks";
-import { ActionData } from "../model";
+import { keyboardShortcuts, useShortcut } from "../keyboard-shortcut-hooks";
+import { ActionData, DataSamplesPageHint } from "../model";
import { useStore } from "../store";
+import { recordButtonId } from "./ActionDataSamplesCard";
+import { actionNameInputId } from "./ActionNameCard";
+import { ConfirmDialog } from "./ConfirmDialog";
import ConnectFirstDialog from "./ConnectFirstDialog";
import DataSamplesMenu from "./DataSamplesMenu";
import DataSamplesTableRow from "./DataSamplesTableRow";
import HeadingGrid, { GridColumnHeadingItemProps } from "./HeadingGrid";
-import LoadProjectInput, { LoadProjectInputRef } from "./LoadProjectInput";
import RecordingDialog, {
RecordingCompleteDetail,
RecordingOptions,
} from "./RecordingDialog";
import ShowGraphsCheckbox from "./ShowGraphsCheckbox";
-import { ConfirmDialog } from "./ConfirmDialog";
-import { actionNameInputId } from "./ActionNameCard";
-import { recordButtonId } from "./ActionDataSamplesCard";
-import { keyboardShortcuts, useShortcut } from "../keyboard-shortcut-hooks";
const gridCommonProps: Partial = {
gridTemplateColumns: "290px 1fr",
@@ -68,22 +53,18 @@ const headings: GridColumnHeadingItemProps[] = [
interface DataSamplesTableProps {
selectedActionIdx: number;
setSelectedActionIdx: (idx: number) => void;
+ hint: DataSamplesPageHint;
}
const DataSamplesTable = ({
selectedActionIdx: selectedActionIdx,
setSelectedActionIdx: setSelectedActionIdx,
+ hint,
}: DataSamplesTableProps) => {
const actions = useStore((s) => s.actions);
// Default to first action being selected if last action is deleted.
const selectedAction: ActionData = actions[selectedActionIdx] ?? actions[0];
- const showHints = useMemo(
- () =>
- actions.length === 0 ||
- (actions.length === 1 && actions[0].recordings.length === 0),
- [actions]
- );
const intl = useIntl();
const isDeleteActionConfirmOpen = useStore((s) => s.isDeleteActionDialogOpen);
const deleteActionConfirmOnOpen = useStore((s) => s.deleteActionDialogOnOpen);
@@ -99,19 +80,13 @@ const DataSamplesTable = ({
const closeDialog = useStore((s) => s.closeDialog);
const connection = useConnectActions();
- const { actions: connActions } = useConnectionStage();
const { isConnected } = useConnectionStage();
- const loadProjectInputRef = useRef(null);
// For adding flashing animation for new recording.
const [newRecordingId, setNewRecordingId] = useState(
undefined
);
- const handleConnect = useCallback(() => {
- connActions.startConnect();
- }, [connActions]);
-
useEffect(() => {
const listener = (e: ButtonEvent) => {
if (!isRecordingDialogOpen && e.state) {
@@ -227,73 +202,31 @@ const DataSamplesTable = ({
{...gridCommonProps}
headings={headings}
/>
- {actions.length === 0 ? (
-
-
-
-
-
- {!isConnected && (
-
- (
-
- ),
- link2: (chunks: ReactNode) => (
-
- ),
- }}
- />
-
- )}
-
- ) : (
-
- {actions.map((action, idx) => (
- setNewRecordingId(undefined)}
- selected={selectedAction.ID === action.ID}
- onSelectRow={() => setSelectedActionIdx(idx)}
- onRecord={handleRecord}
- showHints={showHints}
- onDeleteAction={deleteActionConfirmOnOpen}
- renameShortcutScopeRef={renameActionShortcutScopeRef}
- />
- ))}
-
- )}
+
+ {actions.map((action, idx) => (
+ setNewRecordingId(undefined)}
+ selected={selectedAction.ID === action.ID}
+ onSelectRow={() => setSelectedActionIdx(idx)}
+ onRecord={handleRecord}
+ // Only show hint for the last row.
+ hint={idx === actions.length - 1 ? hint : null}
+ onDeleteAction={deleteActionConfirmOnOpen}
+ renameShortcutScopeRef={renameActionShortcutScopeRef}
+ />
+ ))}
+
>
);
};
diff --git a/src/components/DataSamplesTableHints.tsx b/src/components/DataSamplesTableHints.tsx
index b95951387..f154fecd3 100644
--- a/src/components/DataSamplesTableHints.tsx
+++ b/src/components/DataSamplesTableHints.tsx
@@ -3,70 +3,322 @@
*
* SPDX-License-Identifier: MIT
*/
-import { GridItem, HStack, Text, VStack } from "@chakra-ui/react";
+import {
+ AspectRatio,
+ Box,
+ HStack,
+ Image,
+ Stack,
+ Text,
+ usePrefersReducedMotion,
+ VisuallyHidden,
+ VStack,
+} from "@chakra-ui/react";
import { FormattedMessage } from "react-intl";
import { useConnectionStage } from "../connection-stage-hooks";
-import { ActionData } from "../model";
-import ActionDataSamplesCard from "./ActionDataSamplesCard";
-import GreetingEmojiWithArrow from "./GreetingEmojiWithArrow";
-import { RecordingOptions } from "./RecordingDialog";
+import microbitButtonB from "../images/microbit-button-b.svg";
+import moveMicrobitImage from "../images/move-microbit.svg";
+import { Action } from "../model";
+import Emoji, { animations, EmojiAi } from "./Emoji";
+import EmojiArrow from "./EmojiArrow";
import UpCurveArrow from "./UpCurveArrow";
-interface DataSamplesTableHintsProps {
- action: ActionData;
- onRecord?: (recordingOptions: RecordingOptions) => void;
-}
+export const NameFirstActionHint = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
-const DataSamplesTableHints = ({
- action,
- onRecord,
-}: DataSamplesTableHintsProps) => {
- const { isConnected } = useConnectionStage();
+export const NameActionHint = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export const NameActionWithSamplesHint = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const RecordHintWithButtonB = () => {
return (
<>
- {action.name.length === 0 ? (
-
-
-
-
-
-
-
-
+
+ {chunks} }}
+ />
+
+
+ >
+ );
+};
+
+export const RecordFirstActionHint = () => {
+ const { isConnected } = useConnectionStage();
+ return (
+
+
+ {isConnected ? (
+
) : (
- <>
-
-
-
- {/* Empty grid item to fill first column of grid */}
-
-
-
-
- {isConnected ? (
-
-
-
- ) : (
-
-
-
- )}
-
-
- >
+
+
+
)}
- >
+
);
};
-export default DataSamplesTableHints;
+export const RecordHint = () => {
+ const { isConnected } = useConnectionStage();
+ return (
+
+
+
+
+
+ {isConnected ? (
+
+ ) : (
+
+
+
+ )}
+
+
+ );
+};
+
+export const RecordMoreHint = ({
+ recorded,
+ actionName,
+}: {
+ recorded: number;
+ actionName: string;
+}) => {
+ const numSamples = recorded === 1 ? 2 : 1;
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export const AddActionHint = ({ action }: { action: Action }) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (
+ <>
+
+ {chunks}
+ >
+ ),
+ }}
+ />
+
+
+ );
+};
+
+export const MoveMicrobitHint = () => {
+ const prefersReducedMotion = usePrefersReducedMotion();
+ return (
+
+
+
+
+ {/* Ratio hides excess whitespace */}
+
+
+
+
+
+
+
+
+ );
+};
+
+export const TrainHint = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+ (
+ <>
+
+ {chunks}
+ >
+ ),
+ }}
+ />
+
+
+
+
+ );
+};
diff --git a/src/components/DataSamplesTableRow.tsx b/src/components/DataSamplesTableRow.tsx
index dee9446a5..be470bb36 100644
--- a/src/components/DataSamplesTableRow.tsx
+++ b/src/components/DataSamplesTableRow.tsx
@@ -5,13 +5,20 @@
* SPDX-License-Identifier: MIT
*/
import { Box, GridItem } from "@chakra-ui/react";
+import { RefType } from "react-hotkeys-hook/dist/types";
import { useIntl } from "react-intl";
-import { ActionData } from "../model";
+import { ActionData, DataSamplesPageHint } from "../model";
import ActionDataSamplesCard from "./ActionDataSamplesCard";
import ActionNameCard, { ActionCardNameViewMode } from "./ActionNameCard";
-import DataSamplesTableHints from "./DataSamplesTableHints";
+import {
+ NameActionHint,
+ NameActionWithSamplesHint,
+ NameFirstActionHint,
+ RecordFirstActionHint,
+ RecordHint,
+ RecordMoreHint,
+} from "./DataSamplesTableHints";
import { RecordingOptions } from "./RecordingDialog";
-import { RefType } from "react-hotkeys-hook/dist/types";
interface DataSamplesTableRowProps {
preview?: boolean;
@@ -19,7 +26,7 @@ interface DataSamplesTableRowProps {
selected: boolean;
onSelectRow?: () => void;
onRecord?: (recordingOptions: RecordingOptions) => void;
- showHints: boolean;
+ hint: DataSamplesPageHint;
newRecordingId?: number;
clearNewRecordingId?: () => void;
onDeleteAction?: () => void;
@@ -32,14 +39,13 @@ const DataSamplesTableRow = ({
onSelectRow,
onRecord,
preview,
- showHints,
+ hint,
newRecordingId,
clearNewRecordingId,
onDeleteAction,
renameShortcutScopeRef,
}: DataSamplesTableRowProps) => {
const intl = useIntl();
-
return (
<>
- {showHints ? (
-
- ) : (
-
- {(action.name.length > 0 || action.recordings.length > 0) && (
-
- )}
+ {(hint === "name-first-action" || hint === "name-action") && (
+
+ {hint === "name-first-action" && }
+ {hint === "name-action" && }
)}
+
+ {(action.name.length > 0 || action.recordings.length > 0) && (
+
+ )}
+ {hint === "record-action" && }
+ {hint === "record-more-action" && (
+
+ )}
+
+ {hint === "name-action-with-samples" && (
+
+
+
+ )}
+ {hint === "record-first-action" && (
+ <>
+ {/* Skip first column to correctly place hint. */}
+
+
+ {hint === "record-first-action" && }
+
+ >
+ )}
>
);
diff --git a/src/components/Emoji.tsx b/src/components/Emoji.tsx
new file mode 100644
index 000000000..6318a50af
--- /dev/null
+++ b/src/components/Emoji.tsx
@@ -0,0 +1,189 @@
+import {
+ Icon,
+ IconProps,
+ keyframes,
+ usePrefersReducedMotion,
+} from "@chakra-ui/react";
+
+export const animations = {
+ wobble: `${keyframes({
+ "0%": {
+ transform: "rotate(15deg)",
+ },
+ "25%": {
+ transform: "rotate(-15deg)",
+ },
+ "50%": {
+ transform: "rotate(15deg)",
+ },
+ "75%": {
+ transform: "rotate(-15deg)",
+ },
+ })} 2s`,
+ tada: `${keyframes({
+ "0%": {
+ transform: "scale(1) rotate(0deg)",
+ },
+ "10%, 20%": {
+ transform: "scale(0.95) rotate(-3deg)",
+ },
+ "30%, 50%, 70%, 90%": {
+ transform: "scale(1.1) rotate(3deg)",
+ },
+ "40%, 60%, 80%": {
+ transform: "scale(1.1) rotate(-3deg)",
+ },
+ "100%": {
+ transform: "scale(1) rotate(0deg)",
+ },
+ })} 1s ease-in-out`,
+ spin: `${keyframes({
+ "0%": {
+ transform: "rotate3d(0, 1, 0, 0deg)",
+ },
+ "100%": {
+ transform: "rotate3d(0, 1, 0, 360deg)",
+ },
+ })} 2s`,
+};
+
+type Eye = "round" | "tick" | "heart";
+
+type Side = "left" | "right";
+
+interface EmojiProps extends IconProps {
+ leftEye?: Eye;
+ rightEye?: Eye;
+}
+
+const Emoji = ({
+ leftEye = "round",
+ rightEye = "round",
+ boxSize = 16,
+ color = "brand.500",
+ animation,
+ ...props
+}: EmojiProps) => {
+ const prefersReducedMotion = usePrefersReducedMotion();
+ return (
+
+ {/* Outline */}
+
+
+
+ {/* Smile */}
+
+
+ );
+};
+
+const Eye = ({ type, side }: { type: Eye; side: Side }) => {
+ switch (type) {
+ case "round":
+ return ;
+ case "tick":
+ return ;
+ case "heart":
+ return ;
+ }
+};
+
+const RoundEye = ({ side }: { side: Side }) => {
+ return (
+
+ );
+};
+
+const TickEye = ({ position }: { position: Side }) => {
+ return (
+
+
+
+
+ );
+};
+
+const HeartEye = ({ side }: { side: Side }) => {
+ return (
+
+ );
+};
+
+export const EmojiAi = ({
+ boxSize = 16,
+ color = "brand.500",
+ animation,
+ ...props
+}: EmojiProps) => {
+ const prefersReducedMotion = usePrefersReducedMotion();
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Emoji;
diff --git a/src/components/EmojiArrow.tsx b/src/components/EmojiArrow.tsx
new file mode 100644
index 000000000..d3b532486
--- /dev/null
+++ b/src/components/EmojiArrow.tsx
@@ -0,0 +1,14 @@
+import { Icon, IconProps } from "@chakra-ui/react";
+
+const EmojiArrow = (props: IconProps) => {
+ return (
+
+
+
+ );
+};
+
+export default EmojiArrow;
diff --git a/src/components/GreetingEmojiWithArrow.tsx b/src/components/GreetingEmojiWithArrow.tsx
deleted file mode 100644
index 71c2921ee..000000000
--- a/src/components/GreetingEmojiWithArrow.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * (c) 2024, Micro:bit Educational Foundation and contributors
- *
- * SPDX-License-Identifier: MIT
- */
-import { Icon } from "@chakra-ui/react";
-
-interface GreetingEmojiWithArrowProps {
- w: string;
- h: string;
- color?: string;
-}
-
-const GreetingEmojiWithArrow = ({
- w,
- h,
- color,
-}: GreetingEmojiWithArrowProps) => {
- return (
-
-
-
-
- );
-};
-
-export default GreetingEmojiWithArrow;
diff --git a/src/components/LiveGraphPanel.tsx b/src/components/LiveGraphPanel.tsx
index 502a1b36f..aee586d09 100644
--- a/src/components/LiveGraphPanel.tsx
+++ b/src/components/LiveGraphPanel.tsx
@@ -29,6 +29,7 @@ import PredictedAction from "./PredictedAction";
interface LiveGraphPanelProps {
showPredictedAction?: boolean;
+ showDisconnectedOverlay?: boolean;
disconnectedTextId: string;
}
@@ -37,6 +38,7 @@ export const predictedActionDisplayWidth = 180;
const LiveGraphPanel = ({
showPredictedAction,
disconnectedTextId,
+ showDisconnectedOverlay = true,
}: LiveGraphPanelProps) => {
const { actions, status, isConnected } = useConnectionStage();
const parentPortalRef = useRef(null);
@@ -87,7 +89,7 @@ const LiveGraphPanel = ({
bgColor="white"
className={tourElClassname.liveGraph}
>
- {isDisconnected && (
+ {isDisconnected && showDisconnectedOverlay && (
{
return (
-
+
, "children">;
+
+const WelcomeDialog = ({ onClose, isOpen, ...rest }: WelcomeDialogProps) => {
+ const { handleClose, isConnecting, handleConnect } = useConnectFirst({
+ isOpen,
+ onClose,
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default WelcomeDialog;
diff --git a/src/deployment/default/images/homepage-short-clip.mp4 b/src/deployment/default/images/homepage-short-clip.mp4
new file mode 100644
index 000000000..24d9d5121
Binary files /dev/null and b/src/deployment/default/images/homepage-short-clip.mp4 differ
diff --git a/src/e2e/app/data-samples.ts b/src/e2e/app/data-samples.ts
index 0ac48c3db..15c61f847 100644
--- a/src/e2e/app/data-samples.ts
+++ b/src/e2e/app/data-samples.ts
@@ -13,6 +13,7 @@ export class DataSamplesPage {
private url: string;
private heading: Locator;
private connectBtn: Locator;
+ public welcomeDialog: WelcomeDialog;
constructor(public readonly page: Page) {
this.url = `http://localhost:5173${
@@ -20,6 +21,7 @@ export class DataSamplesPage {
}data-samples`;
this.navbar = new Navbar(page);
this.heading = this.page.getByRole("heading", { name: "Data samples" });
+ this.welcomeDialog = new WelcomeDialog(page);
this.connectBtn = this.page.getByLabel("Connect to micro:bit");
}
@@ -41,7 +43,7 @@ export class DataSamplesPage {
}
async connect() {
- await this.connectBtn.click();
+ await this.welcomeDialog.connect();
const connectionDialogs = new ConnectionDialogs(this.page);
return connectionDialogs;
}
@@ -54,15 +56,11 @@ export class DataSamplesPage {
}
async expectOnPage() {
+ await this.welcomeDialog.close();
await expect(this.heading).toBeVisible();
this.expectUrl();
}
- async expectCorrectInitialState() {
- this.expectUrl();
- await expect(this.heading).toBeVisible({ timeout: 10000 });
- }
-
async expectActions(expectedActions: string[]) {
const actionInputs = this.page.getByRole("textbox", {
name: "Name of action",
@@ -81,3 +79,24 @@ export class DataSamplesPage {
return new TrainModelDialog(this.page);
}
}
+
+class WelcomeDialog {
+ private heading: Locator;
+
+ constructor(public readonly page: Page) {
+ this.page = page;
+ this.heading = this.page.getByText("Welcome to micro:bit CreateAI");
+ }
+
+ async expectOpen() {
+ await expect(this.heading).toBeVisible();
+ }
+
+ async close() {
+ await this.page.getByRole("button", { name: "Close" }).click();
+ }
+
+ async connect() {
+ await this.page.getByRole("button", { name: "Connect" }).click();
+ }
+}
diff --git a/src/e2e/new-page.spec.ts b/src/e2e/new-page.spec.ts
index 99744b6b3..e12e5747a 100644
--- a/src/e2e/new-page.spec.ts
+++ b/src/e2e/new-page.spec.ts
@@ -26,6 +26,7 @@ test.describe("new page", () => {
test("resume session", async ({ newPage, homePage, dataSamplesPage }) => {
await newPage.startNewSession();
+ await dataSamplesPage.welcomeDialog.close();
await dataSamplesPage.navbar.home();
await homePage.getStarted();
await newPage.expectResumeButtonToShowProjectName("Untitled");
diff --git a/src/e2e/test-model-page.spec.ts b/src/e2e/test-model-page.spec.ts
index a9d0eb231..8e127d744 100644
--- a/src/e2e/test-model-page.spec.ts
+++ b/src/e2e/test-model-page.spec.ts
@@ -1,11 +1,12 @@
import { test } from "./fixtures";
test.describe("test model page", () => {
- test.beforeEach(async ({ homePage, newPage }) => {
+ test.beforeEach(async ({ homePage, newPage, dataSamplesPage }) => {
await homePage.setupContext();
await homePage.goto();
await homePage.getStarted();
await newPage.continueSavedSession("test-data/dataset.json");
+ await dataSamplesPage.welcomeDialog.close();
});
test("initial state", async ({ dataSamplesPage, testModelPage }) => {
diff --git a/src/images/createai-animation.mp4 b/src/images/createai-animation.mp4
new file mode 100644
index 000000000..5b068cdba
Binary files /dev/null and b/src/images/createai-animation.mp4 differ
diff --git a/src/images/microbit-button-b.svg b/src/images/microbit-button-b.svg
new file mode 100644
index 000000000..256c66c2d
--- /dev/null
+++ b/src/images/microbit-button-b.svg
@@ -0,0 +1,48 @@
+
diff --git a/src/images/move-microbit.svg b/src/images/move-microbit.svg
new file mode 100644
index 000000000..8db1c179b
--- /dev/null
+++ b/src/images/move-microbit.svg
@@ -0,0 +1,190 @@
+
+
diff --git a/src/images/pre-connect-video.mp4 b/src/images/pre-connect-video.mp4
new file mode 100644
index 000000000..8fbeb1e5b
Binary files /dev/null and b/src/images/pre-connect-video.mp4 differ
diff --git a/src/images/step-by-step.svg b/src/images/step-by-step.svg
new file mode 100644
index 000000000..d4bbc450e
--- /dev/null
+++ b/src/images/step-by-step.svg
@@ -0,0 +1,236 @@
+
diff --git a/src/live-region-hook.ts b/src/live-region-hook.ts
new file mode 100644
index 000000000..d42372799
--- /dev/null
+++ b/src/live-region-hook.ts
@@ -0,0 +1,19 @@
+import { useEffect, useState } from "react";
+import { LiveRegion, LiveRegionOptions } from "./live-region";
+
+export const useLiveRegion = (
+ parentNode: HTMLElement | null,
+ options: Partial = {}
+) => {
+ const [liveRegion] = useState(() => new LiveRegion(options));
+
+ useEffect(() => {
+ if (parentNode) {
+ liveRegion.setupLiveRegion(parentNode);
+ }
+
+ return () => liveRegion.destroy();
+ }, [liveRegion, parentNode]);
+
+ return liveRegion;
+};
diff --git a/src/live-region.ts b/src/live-region.ts
new file mode 100644
index 000000000..4e74de4b3
--- /dev/null
+++ b/src/live-region.ts
@@ -0,0 +1,70 @@
+export interface LiveRegionOptions {
+ id: string;
+ "aria-live": "polite" | "assertive";
+ role: "status" | "alert" | "log";
+ "aria-atomic": React.AriaAttributes["aria-atomic"];
+}
+
+const defaultOptions: LiveRegionOptions = {
+ id: "live-region",
+ "aria-live": "polite",
+ role: "status",
+ "aria-atomic": true,
+};
+
+export class LiveRegion {
+ region: HTMLElement | null;
+ options: Required;
+
+ constructor(options: Partial = {}) {
+ this.options = { ...defaultOptions, ...options };
+ this.region = null;
+ }
+
+ setupLiveRegion(parentNode: HTMLElement) {
+ if (this.region) {
+ // Region already setup.
+ return;
+ }
+ this.region = document.createElement("div");
+ setup(this.region, this.options);
+ parentNode.appendChild(this.region);
+ }
+
+ speak(message: string) {
+ this.clear();
+ if (this.region) {
+ this.region.innerText = message;
+ }
+ }
+
+ destroy() {
+ if (this.region) {
+ this.region.parentNode?.removeChild(this.region);
+ }
+ }
+
+ clear() {
+ if (this.region) {
+ this.region.innerText = "";
+ }
+ }
+}
+
+const setup = (region: HTMLElement, options: LiveRegionOptions) => {
+ region.id = options.id;
+ region.setAttribute("aria-live", options["aria-live"]);
+ region.setAttribute("role", options.role);
+ region.setAttribute("aria-atomic", String(options["aria-atomic"]));
+ Object.assign(region.style, {
+ border: "0px",
+ clip: "rect(0px, 0px, 0px, 0px)",
+ height: "1px",
+ width: "1px",
+ margin: "-1px",
+ padding: "0px",
+ overflow: "hidden",
+ whiteSpace: "nowrap",
+ position: "absolute",
+ });
+};
diff --git a/src/messages/ui.ca.json b/src/messages/ui.ca.json
index 5713979a5..704a738b4 100644
--- a/src/messages/ui.ca.json
+++ b/src/messages/ui.ca.json
@@ -117,6 +117,44 @@
"value": "Afegir una acció"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -439,32 +477,6 @@
"value": "Cable micro USB"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "Connecta una micro:bit de recollida de dades"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " o "
- },
- {
- "children": [
- {
- "type": 0,
- "value": "importa mostres de dades"
- }
- ],
- "type": 8,
- "value": "link2"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -1985,6 +1997,12 @@
"value": "Més edició a les opcions de MakeCode"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2135,12 +2153,6 @@
"value": "Següent"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "No hi ha mostres de dades"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2391,6 +2403,90 @@
"value": "Prem per gravar una mostra de dades o prem el botó B de la teva micro:bit de recollida de dades."
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 0,
@@ -3015,6 +3111,28 @@
"value": "Entrenant un model"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3182,5 +3300,11 @@
"type": 0,
"value": "desconnecta i torna a connectar el cable USB"
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.en.json b/src/messages/ui.en.json
index fcd46eeeb..8b65eaf52 100644
--- a/src/messages/ui.en.json
+++ b/src/messages/ui.en.json
@@ -117,6 +117,44 @@
"value": "Add action"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -439,32 +477,6 @@
"value": "Micro USB cable"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "Connect a data collection micro:bit"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " or "
- },
- {
- "children": [
- {
- "type": 0,
- "value": "import data samples"
- }
- ],
- "type": 8,
- "value": "link2"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -1999,10 +2011,16 @@
"value": "More edit in MakeCode options"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
- "value": "Name an action you want the micro:bit to recognise"
+ "value": "Name an action you want CreateAI to recognise, like ‘waving’ or ‘jumping’"
}
],
"name-project": [
@@ -2149,12 +2167,6 @@
"value": "Next"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "No data samples"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2396,13 +2408,111 @@
"record-hint": [
{
"type": 0,
- "value": "Press to record a data sample."
+ "value": "Press record to collect a movement data sample."
}
],
"record-hint-button-b": [
{
"type": 0,
- "value": "Press to record a data sample or press button B on your data collection micro:bit."
+ "value": "Press record "
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "or"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ },
+ {
+ "type": 0,
+ "value": " button B on the micro:bit to collect a movement data sample."
+ }
+ ],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
}
],
"record-samples": [
@@ -3043,6 +3153,28 @@
"value": "Training a model"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3210,5 +3342,11 @@
"type": 0,
"value": "unplug and replug the USB cable"
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.es-es.json b/src/messages/ui.es-es.json
index bce2abee6..9ba144979 100644
--- a/src/messages/ui.es-es.json
+++ b/src/messages/ui.es-es.json
@@ -117,6 +117,44 @@
"value": "Añadir acción"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -439,32 +477,6 @@
"value": "Cable micro USB"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "Conecta una colección de datos de micro:bit"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " o "
- },
- {
- "children": [
- {
- "type": 0,
- "value": "importa muestras de datos"
- }
- ],
- "type": 8,
- "value": "link2"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -1999,6 +2011,12 @@
"value": "Más edición en opciones de MakeCode"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2149,12 +2167,6 @@
"value": "Siguiente"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "No hay muestras de datos"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2405,6 +2417,90 @@
"value": "Pulsa para grabar una muestra de datos o pulsa el botón B de tu micro:bit de recogida de datos."
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 0,
@@ -3029,6 +3125,28 @@
"value": "Entrenar un modelo"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3196,5 +3314,11 @@
"type": 0,
"value": "desenchufa y vuelve a enchufar el cable USB"
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.fr.json b/src/messages/ui.fr.json
index 4770d3cd7..2dc8b329b 100644
--- a/src/messages/ui.fr.json
+++ b/src/messages/ui.fr.json
@@ -117,6 +117,44 @@
"value": "Ajouter une action"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -439,32 +477,6 @@
"value": "Câble Micro USB"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "Connecter un micro:bit de collecte de données"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " ou "
- },
- {
- "children": [
- {
- "type": 0,
- "value": "importer des échantillons de données"
- }
- ],
- "type": 8,
- "value": "link2"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -2003,6 +2015,12 @@
"value": "Plus de modifications dans les options MakeCode"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2153,12 +2171,6 @@
"value": "Suivant"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "Aucun échantillon de données"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2409,6 +2421,90 @@
"value": "Appuyez pour enregistrer un échantillon de données ou appuyez sur le bouton B de votre micro:bit de collecte de données."
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 0,
@@ -3047,6 +3143,28 @@
"value": "Entraînement d'un modèle"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3214,5 +3332,11 @@
"type": 0,
"value": "débrancher et rebrancher le câble USB"
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.ja.json b/src/messages/ui.ja.json
index cc8fa68e8..982b8d3bf 100644
--- a/src/messages/ui.ja.json
+++ b/src/messages/ui.ja.json
@@ -113,6 +113,44 @@
"value": "アクションを追加"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -431,32 +469,6 @@
"value": "マイクロUSBケーブル"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "データ収集用micro:bitを接続"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " または "
- },
- {
- "children": [
- {
- "type": 0,
- "value": "データサンプルのインポート"
- }
- ],
- "type": 8,
- "value": "link2"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -1979,6 +1991,12 @@
"value": "MakeCodeのオプションをさらに編集する"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2129,12 +2147,6 @@
"value": "次"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "データサンプルがありません"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2385,6 +2397,90 @@
"value": "データサンプルを記録するには、データ収集用micro:bitのボタンBを押します。"
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 1,
@@ -2993,6 +3089,28 @@
"value": "モデルのトレーニング"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3160,5 +3278,11 @@
"type": 0,
"value": "USBケーブルを抜いて再接続"
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.ko.json b/src/messages/ui.ko.json
index c20240790..ba2c4a208 100644
--- a/src/messages/ui.ko.json
+++ b/src/messages/ui.ko.json
@@ -113,6 +113,44 @@
"value": "행동 추가"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -431,36 +469,6 @@
"value": "마이크로 USB 케이블"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "데이터 수집 micro:bit에 연결하기"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " 또는 "
- },
- {
- "children": [
- {
- "type": 0,
- "value": "데이터 샘플 가져오기"
- }
- ],
- "type": 8,
- "value": "link2"
- },
- {
- "type": 0,
- "value": "를 하세요."
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -1987,6 +1995,12 @@
"value": "MakeCode 옵션에서 추가 편집"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2137,12 +2151,6 @@
"value": "다음"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "데이터 샘플 없음"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2393,6 +2401,90 @@
"value": "눌러서 데이터 샘플을 기록하거나 데이터 수집 micro:bit의 B 버튼을 누르세요."
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 0,
@@ -3001,6 +3093,28 @@
"value": "모델 훈련 중"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3168,5 +3282,11 @@
"type": 0,
"value": "USB 케이블을 분리했다가 다시 연결하세요."
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.lol.json b/src/messages/ui.lol.json
index a4f219e4a..75679fd06 100644
--- a/src/messages/ui.lol.json
+++ b/src/messages/ui.lol.json
@@ -107,6 +107,44 @@
"value": "crwdns362672:0crwdne362672:0"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -429,12 +467,6 @@
"value": "crwdns362770:0crwdne362770:0"
}
],
- "connect-or-import": [
- {
- "type": 0,
- "value": "crwdns362772:0crwdne362772:0"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -1897,6 +1929,12 @@
"value": "crwdns363178:0crwdne363178:0"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2021,12 +2059,6 @@
"value": "crwdns363214:0crwdne363214:0"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "crwdns363216:0crwdne363216:0"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2281,6 +2313,90 @@
"value": "crwdns363274:0crwdne363274:0"
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 0,
@@ -2871,6 +2987,28 @@
"value": "crwdns363434:0crwdne363434:0"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -2996,5 +3134,11 @@
"type": 0,
"value": "crwdns363476:0crwdne363476:0"
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.nl.json b/src/messages/ui.nl.json
index 84d6457ea..0619157ea 100644
--- a/src/messages/ui.nl.json
+++ b/src/messages/ui.nl.json
@@ -117,6 +117,44 @@
"value": "Voeg actie toe"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -439,32 +477,6 @@
"value": "Micro USB-kabel"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "Verbind een micro:bit die gegevens verzamelt"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " of "
- },
- {
- "children": [
- {
- "type": 0,
- "value": "importeer data samples"
- }
- ],
- "type": 8,
- "value": "link2"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -1999,6 +2011,12 @@
"value": "Meer opties voor bewerken in MakeCode"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2149,12 +2167,6 @@
"value": "Volgende"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "Geen data samples"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2405,6 +2417,90 @@
"value": "Klik om een data sample op te nemen of druk op knop B op jouw data collectie micro:bit."
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 0,
@@ -3029,6 +3125,28 @@
"value": "Model trainen"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3196,5 +3314,11 @@
"type": 0,
"value": "de USB-kabel ontkoppelen en opnieuw aansluiten"
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.pl.json b/src/messages/ui.pl.json
index 599e433a9..fb179a658 100644
--- a/src/messages/ui.pl.json
+++ b/src/messages/ui.pl.json
@@ -117,6 +117,44 @@
"value": "Dodaj działanie"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -439,32 +477,6 @@
"value": "Kabel Micro USB"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "Podłącz micro:bit zbierający dane"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " lub "
- },
- {
- "children": [
- {
- "type": 0,
- "value": "importuj próbki danych"
- }
- ],
- "type": 8,
- "value": "link2"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -2003,6 +2015,12 @@
"value": "Więcej edycji w opcjach MakeCode"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2153,12 +2171,6 @@
"value": "Dalej"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "Brak próbek danych"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2409,6 +2421,90 @@
"value": "Naciśnij, aby nagrać próbkę danych lub naciśnij przycisk B na micro:bicie do zbierana danych."
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 0,
@@ -3025,6 +3121,28 @@
"value": "Trenowanie modelu"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3192,5 +3310,11 @@
"type": 0,
"value": "odłącz i podłącz kabel USB"
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.pt-br.json b/src/messages/ui.pt-br.json
index 16a454864..7c925a890 100644
--- a/src/messages/ui.pt-br.json
+++ b/src/messages/ui.pt-br.json
@@ -117,6 +117,44 @@
"value": "Adicionar ação"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -439,32 +477,6 @@
"value": "Cabo Micro USB"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "Conecte um micro:bit de coleta de dados"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " ou "
- },
- {
- "children": [
- {
- "type": 0,
- "value": "importe as amostras de dados"
- }
- ],
- "type": 8,
- "value": "link2"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -1999,6 +2011,12 @@
"value": "Mais opções de edição no MakeCode."
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2129,12 +2147,6 @@
"value": "Próximo"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "Nenhuma amostra de dados"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2389,6 +2401,90 @@
"value": "Pressione para gravar uma amostra de dados ou pressione o botão B no seu micro:bit de coleta de dados."
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 0,
@@ -3009,6 +3105,28 @@
"value": "Treinando um modelo."
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3162,5 +3280,11 @@
"type": 0,
"value": "Desconecte e reconecte o cabo USB."
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/messages/ui.zh-tw.json b/src/messages/ui.zh-tw.json
index 5a3710b42..12ce58558 100644
--- a/src/messages/ui.zh-tw.json
+++ b/src/messages/ui.zh-tw.json
@@ -121,6 +121,44 @@
"value": "新增動作"
}
],
+ "add-action-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Add another action"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "add-action-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ },
+ {
+ "type": 0,
+ "value": "? Press ‘Add action’ button to add another action"
+ }
+ ],
"ai-activity-timer-resource-title": [
{
"type": 0,
@@ -439,32 +477,6 @@
"value": "微型 USB 纜線"
}
],
- "connect-or-import": [
- {
- "children": [
- {
- "type": 0,
- "value": "連線數據收集用的 micro:bit"
- }
- ],
- "type": 8,
- "value": "link1"
- },
- {
- "type": 0,
- "value": " 或"
- },
- {
- "children": [
- {
- "type": 0,
- "value": "匯入數據樣本"
- }
- ],
- "type": 8,
- "value": "link2"
- }
- ],
"connect-pattern-heading": [
{
"type": 0,
@@ -1995,6 +2007,12 @@
"value": "在 MakeCode 選項中進行更多編輯"
}
],
+ "move-hint": [
+ {
+ "type": 0,
+ "value": "Move the micro:bit to explore how different actions change the graph"
+ }
+ ],
"name-action-hint": [
{
"type": 0,
@@ -2145,12 +2163,6 @@
"value": "下一個"
}
],
- "no-data-samples": [
- {
- "type": 0,
- "value": "沒有數據樣本"
- }
- ],
"not-create-ai-hex-import-dialog-content": [
{
"type": 0,
@@ -2401,6 +2413,90 @@
"value": "按下以記錄數據樣本或是按下您的數據收集用的 micro:bit 上的按鍵 B。"
}
],
+ "record-more-hint": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ }
+ ],
+ "record-more-hint-label": [
+ {
+ "type": 0,
+ "value": "Record at least "
+ },
+ {
+ "offset": 0,
+ "options": {
+ "one": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data sample"
+ }
+ ]
+ },
+ "other": {
+ "value": [
+ {
+ "type": 1,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " more data samples"
+ }
+ ]
+ }
+ },
+ "pluralType": "cardinal",
+ "type": 6,
+ "value": "numSamples"
+ },
+ {
+ "type": 0,
+ "value": " for "
+ },
+ {
+ "type": 1,
+ "value": "actionName"
+ }
+ ],
"record-samples": [
{
"type": 0,
@@ -3021,6 +3117,28 @@
"value": "訓練模型"
}
],
+ "train-hint": [
+ {
+ "type": 0,
+ "value": "Finished recording?"
+ },
+ {
+ "children": [
+ {
+ "type": 0,
+ "value": "Train the model"
+ }
+ ],
+ "type": 8,
+ "value": "mark"
+ }
+ ],
+ "train-hint-label": [
+ {
+ "type": 0,
+ "value": "Finished recording? Press ‘Train the model’ button to train the model"
+ }
+ ],
"train-model": [
{
"type": 0,
@@ -3188,5 +3306,11 @@
"type": 0,
"value": "拔下並重新插入 USB 纜線"
}
+ ],
+ "welcome-title": [
+ {
+ "type": 0,
+ "value": "Welcome to micro:bit CreateAI"
+ }
]
}
\ No newline at end of file
diff --git a/src/model.ts b/src/model.ts
index 3e05c4828..c39d5e255 100644
--- a/src/model.ts
+++ b/src/model.ts
@@ -223,6 +223,18 @@ export enum DataSamplesView {
GraphAndDataFeatures = "graph and data features",
}
+export type DataSamplesPageHint =
+ | null
+ | "move-microbit"
+ | "name-first-action"
+ | "record-first-action"
+ | "record-more-action"
+ | "add-action"
+ | "name-action"
+ | "record-action"
+ | "train"
+ | "name-action-with-samples";
+
export enum PostImportDialogState {
None = "none",
Error = "error",
diff --git a/src/pages/DataSamplesPage.tsx b/src/pages/DataSamplesPage.tsx
index 584aa3221..d4ac00208 100644
--- a/src/pages/DataSamplesPage.tsx
+++ b/src/pages/DataSamplesPage.tsx
@@ -4,23 +4,45 @@
*
* SPDX-License-Identifier: MIT
*/
-import { Button, Flex, HStack, VStack } from "@chakra-ui/react";
-import { useCallback, useEffect, useRef, useState } from "react";
+import {
+ Button,
+ Flex,
+ HStack,
+ useDisclosure,
+ usePrefersReducedMotion,
+ VStack,
+} from "@chakra-ui/react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { RiAddLine, RiArrowRightLine } from "react-icons/ri";
-import { FormattedMessage, useIntl } from "react-intl";
+import { FormattedMessage, IntlFormatters, useIntl } from "react-intl";
import { useNavigate } from "react-router";
+import { useHasMoved } from "../buffered-data-hooks";
import DataSamplesTable from "../components/DataSamplesTable";
+import {
+ AddActionHint,
+ MoveMicrobitHint,
+ TrainHint,
+} from "../components/DataSamplesTableHints";
import DefaultPageLayout, {
ProjectMenuItems,
ProjectToolbarItems,
} from "../components/DefaultPageLayout";
import LiveGraphPanel from "../components/LiveGraphPanel";
import TrainModelDialogs from "../components/TrainModelFlowDialogs";
+import WelcomeDialog from "../components/WelcomeDialog";
import { useConnectionStage } from "../connection-stage-hooks";
import { keyboardShortcuts, useShortcut } from "../keyboard-shortcut-hooks";
+import {
+ ActionData,
+ DataSamplesPageHint,
+ PostImportDialogState,
+} from "../model";
import { useHasSufficientDataForTraining, useStore } from "../store";
import { tourElClassname } from "../tours";
import { createTestingModelPageUrl } from "../urls";
+import { animations } from "../components/Emoji";
+import { useLiveRegion } from "../live-region-hook";
+import debounce from "lodash.debounce";
const DataSamplesPage = () => {
const actions = useStore((s) => s.actions);
@@ -32,7 +54,8 @@ const DataSamplesPage = () => {
const trainModelFlowStart = useStore((s) => s.trainModelFlowStart);
const tourStart = useStore((s) => s.tourStart);
- const { isConnected } = useConnectionStage();
+ const { isConnected, isDialogOpen: isConnectionDialogOpen } =
+ useConnectionStage();
useEffect(() => {
// If a user first connects on "Testing model" this can result in the tour when they return to the "Data samples" page.
if (isConnected) {
@@ -56,8 +79,72 @@ const DataSamplesPage = () => {
enabled: !isAddNewActionDisabled,
});
const intl = useIntl();
+ const prefersReducedMotion = usePrefersReducedMotion();
+ const welcomeDialogDisclosure = useDisclosure({
+ defaultIsOpen: !isConnected && !model,
+ });
+ const hasMoved = useHasMoved();
+ const tourInProgress = useStore((s) => !!s.tourState);
+ const isRecordingDialogOpen = useStore((s) => !!s.isRecordingDialogOpen);
+ const isPostImportDialogOpen = useStore(
+ (s) => s.postImportDialogState !== PostImportDialogState.None
+ );
+ const isDialogOpen =
+ welcomeDialogDisclosure.isOpen ||
+ isConnectionDialogOpen ||
+ tourInProgress ||
+ isRecordingDialogOpen ||
+ isPostImportDialogOpen;
+ const hint = useStore((s) => s.hint);
+ const setHint = useStore((s) => s.setHint);
+ useEffect(() => {
+ // Initialise hint on first load.
+ setHint(true);
+ }, [setHint]);
+ const dataSamplesHint: DataSamplesPageHint = isDialogOpen
+ ? null
+ : isConnected && !hasMoved
+ ? "move-microbit"
+ : hint;
+
+ const pageRef = useRef(null);
+ const region = useLiveRegion(pageRef.current);
+
+ // To avoid aria-live interruptions, particularly when inputting action name.
+ const debouncedSpeakHint = useMemo(
+ () =>
+ debounce(
+ (hintText: string) => {
+ region.speak(hintText);
+ },
+ 1000,
+ { leading: false, trailing: true }
+ ),
+ [region]
+ );
+
+ useEffect(() => {
+ if (!dataSamplesHint) {
+ return;
+ }
+ const actionWithHint = actions[actions.length - 1];
+ const hintText = getHintText(
+ intl,
+ dataSamplesHint,
+ isConnected,
+ actionWithHint
+ );
+ debouncedSpeakHint(hintText);
+ }, [actions, dataSamplesHint, debouncedSpeakHint, intl, isConnected, region]);
+
return (
<>
+ {welcomeDialogDisclosure.isOpen && !isPostImportDialogOpen && (
+
+ )}
{
menuItems={}
toolbarItemsRight={}
>
-
+
@@ -85,6 +173,7 @@ const DataSamplesPage = () => {
borderTopWidth={3}
borderColor="gray.200"
alignItems="center"
+ position="relative"
>
+ {dataSamplesHint === "add-action" && (
+
+ )}
{model ? (
)}
+ {dataSamplesHint === "train" && }
+ {dataSamplesHint === "move-microbit" && }
-
+
+
>
);
};
+const getHintText = (
+ intl: IntlFormatters,
+ hint: DataSamplesPageHint,
+ isConnected: boolean,
+ action: ActionData
+): string => {
+ if (!hint) {
+ return "";
+ }
+ switch (hint) {
+ case "add-action": {
+ return intl.formatMessage(
+ { id: "add-action-hint-label" },
+ { actionName: action.name }
+ );
+ }
+ case "move-microbit": {
+ return intl.formatMessage({ id: "move-hint" });
+ }
+ case "record-first-action":
+ case "record-action": {
+ return isConnected
+ ? intl
+ .formatMessage(
+ { id: "record-hint-button-b" },
+ { mark: (chunks: string[]) => chunks }
+ )
+ .toString()
+ : intl.formatMessage({ id: "record-hint" });
+ }
+ case "name-first-action":
+ case "name-action-with-samples":
+ case "name-action": {
+ return intl.formatMessage({ id: "name-action-hint" });
+ }
+ case "record-more-action": {
+ return intl.formatMessage(
+ { id: "record-more-hint-label" },
+ {
+ numSamples: action.recordings.length === 1 ? 2 : 1,
+ actionName: action.name,
+ }
+ );
+ }
+ case "train": {
+ return intl.formatMessage({ id: "train-hint-label" });
+ }
+ }
+};
+
export default DataSamplesPage;
diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx
index c1f878514..784a2cad0 100644
--- a/src/pages/HomePage.tsx
+++ b/src/pages/HomePage.tsx
@@ -31,7 +31,7 @@ import projectImage2 from "theme-package/images/simple-ai-exercise-timer.png";
import projectImage1 from "theme-package/images/ai-storytelling-friend.png";
import homepageVideo from "theme-package/images/homepage-short-clip.mp4";
import HomepageBannerVideo from "../components/HomepageBannerVideo";
-import StepByStepIllustration from "../components/StepByStepIllustration";
+import stepByStep from "../images/step-by-step.svg";
import {
landingPageUrl,
projectUrl,
@@ -133,6 +133,19 @@ const HomePage = () => {
)}
+
+
+
+
+
+
+
+
@@ -163,18 +176,6 @@ const HomePage = () => {
)}
-
-
-
-
-
-
-
-
{flags.websiteContent && (
diff --git a/src/pages/OpenSharedProjectPage.tsx b/src/pages/OpenSharedProjectPage.tsx
index 33195128c..eadcd6a1c 100644
--- a/src/pages/OpenSharedProjectPage.tsx
+++ b/src/pages/OpenSharedProjectPage.tsx
@@ -296,7 +296,7 @@ const PreviewData = ({ dataset }: PreviewDataProps) => {
key={action.ID}
action={action}
selected={false}
- showHints={false}
+ hint={null}
/>
))}
diff --git a/src/store.ts b/src/store.ts
index 6120e675a..35df3ee31 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -35,6 +35,7 @@ import {
EditorStartUp,
TourTriggerName,
tourSequence,
+ DataSamplesPageHint,
} from "./model";
import { defaultSettings, Settings } from "./settings";
import { getTotalNumSamples } from "./utils/actions";
@@ -149,6 +150,15 @@ export interface State {
timestamp: number | undefined;
+ /**
+ * Hint to trigger depending on actions.
+ */
+ hint: DataSamplesPageHint;
+ /**
+ * Set to true if user has moved the micro:bit.
+ * This is used to decide whether to show the move hint.
+ */
+ hasMoved: boolean;
isRecording: boolean;
project: MakeCodeProject;
@@ -238,6 +248,8 @@ export interface Actions {
loadDataset(actions: ActionData[]): void;
loadProject(project: MakeCodeProject, name: string): void;
setEditorOpen(open: boolean): void;
+ setHint(suppressTrainAndAddActionHint?: boolean): void;
+ setHasMoved(hasMoved: boolean): void;
recordingStarted(): void;
recordingStopped(): void;
newSession(projectName?: string): void;
@@ -315,8 +327,10 @@ const createMlStore = (logging: Logging) => {
persist(
(set, get) => ({
timestamp: undefined,
- actions: [],
+ actions: [createFirstAction()],
dataWindow: currentDataWindow,
+ hint: null,
+ hasMoved: false,
isRecording: false,
project: createUntitledProject(),
projectLoadTimestamp: 0,
@@ -405,9 +419,10 @@ const createMlStore = (logging: Logging) => {
newSession(projectName?: string) {
const untitledProject = createUntitledProject();
+ const actions = [createFirstAction()];
set(
{
- actions: [],
+ actions,
dataWindow: currentDataWindow,
model: undefined,
project: projectName
@@ -416,6 +431,7 @@ const createMlStore = (logging: Logging) => {
projectEdited: false,
appEditNeedsFlushToEditor: true,
timestamp: Date.now(),
+ hint: getHint(actions, false),
},
false,
"newSession"
@@ -436,6 +452,21 @@ const createMlStore = (logging: Logging) => {
);
},
+ setHint(suppressTrainAndAddActionHint = false) {
+ set(
+ ({ actions }) => {
+ const hint = getHint(actions, suppressTrainAndAddActionHint);
+ return { hint };
+ },
+ false,
+ "setHint"
+ );
+ },
+
+ setHasMoved(hasMoved) {
+ set({ hasMoved }, false, "setHasMoved");
+ },
+
recordingStarted() {
set({ isRecording: true }, false, "recordingStarted");
},
@@ -459,6 +490,7 @@ const createMlStore = (logging: Logging) => {
];
return {
actions: newActions,
+ hint: getHint(newActions, false),
model: undefined,
...updateProject(
project,
@@ -484,6 +516,7 @@ const createMlStore = (logging: Logging) => {
});
return {
actions: updatedActions,
+ hint: getHint(updatedActions, false),
model: undefined,
};
});
@@ -491,12 +524,16 @@ const createMlStore = (logging: Logging) => {
deleteAction(id: ActionData["ID"]) {
return set(({ project, projectEdited, actions, dataWindow }) => {
- const newActions = actions.filter((a) => a.ID !== id);
+ const remainingActions = actions.filter((a) => a.ID !== id);
+ const newActions =
+ remainingActions.length === 0
+ ? [createFirstAction()]
+ : remainingActions;
const newDataWindow =
newActions.length === 0 ? currentDataWindow : dataWindow;
return {
- actions:
- newActions.length === 0 ? [createFirstAction()] : newActions,
+ actions: newActions,
+ hint: getHint(newActions, false),
dataWindow: newDataWindow,
model: undefined,
...updateProject(
@@ -512,12 +549,24 @@ const createMlStore = (logging: Logging) => {
setActionName(id: ActionData["ID"], name: string) {
return set(
- ({ project, projectEdited, actions, model, dataWindow }) => {
+ ({
+ project,
+ projectEdited,
+ actions,
+ model,
+ dataWindow,
+ hint,
+ }) => {
const newActions = actions.map((action) =>
id !== action.ID ? action : { ...action, name }
);
+ const newHint = getHint(newActions, false);
return {
actions: newActions,
+ // Hint is set separately in DataSamplesPage.tsx and debounced
+ // to avoid aria-live interruptions. Hint is set to null when
+ // the hint will change to avoid showing incorrect hint.
+ ...(hint === newHint ? {} : { hint: null }),
...updateProject(
project,
projectEdited,
@@ -601,6 +650,7 @@ const createMlStore = (logging: Logging) => {
numRecordings === 0 ? currentDataWindow : dataWindow;
return {
actions: newActions,
+ hint: getHint(newActions, false),
dataWindow: newDataWindow,
model: undefined,
...updateProject(
@@ -615,18 +665,22 @@ const createMlStore = (logging: Logging) => {
},
deleteAllActions() {
- return set(({ project, projectEdited }) => ({
- actions: [createFirstAction()],
- dataWindow: currentDataWindow,
- model: undefined,
- ...updateProject(
- project,
- projectEdited,
- [],
- undefined,
- currentDataWindow
- ),
- }));
+ return set(({ project, projectEdited }) => {
+ const actions = [createFirstAction()];
+ return {
+ actions,
+ hint: getHint(actions, false),
+ dataWindow: currentDataWindow,
+ model: undefined,
+ ...updateProject(
+ project,
+ projectEdited,
+ [],
+ undefined,
+ currentDataWindow
+ ),
+ };
+ });
},
downloadDataset() {
@@ -645,8 +699,12 @@ const createMlStore = (logging: Logging) => {
a.click();
},
- loadDataset(newActions: ActionData[]) {
+ loadDataset(datasetActions: ActionData[]) {
set(({ project, projectEdited, settings }) => {
+ const newActions =
+ datasetActions.length > 0
+ ? datasetActions
+ : [createFirstAction()];
const dataWindow = getDataWindowFromActions(newActions);
return {
settings: {
@@ -670,6 +728,7 @@ const createMlStore = (logging: Logging) => {
dataWindow,
model: undefined,
timestamp: Date.now(),
+ hint: getHint(newActions, true),
...updateProject(
project,
projectEdited,
@@ -686,7 +745,11 @@ const createMlStore = (logging: Logging) => {
* from microbit.org we have the JSON already and use this route.
*/
loadProject(project: MakeCodeProject, name: string) {
- const newActions = getActionsFromProject(project);
+ const projectActions = getActionsFromProject(project);
+ const newActions =
+ projectActions.length > 0
+ ? projectActions
+ : [createFirstAction()];
set(({ settings, project: prevProject }) => {
project = renameProject(project, name);
project = {
@@ -707,6 +770,7 @@ const createMlStore = (logging: Logging) => {
},
actions: newActions,
dataWindow: getDataWindowFromActions(newActions),
+ hint: getHint(newActions, true),
model: undefined,
project,
projectEdited: true,
@@ -924,7 +988,11 @@ const createMlStore = (logging: Logging) => {
`[MakeCode] Updating state from MakeCode header change. ID change: ${prevProject.header?.id} -> ${newProject.header?.id}`
);
const timestamp = Date.now();
- const newActions = getActionsFromProject(newProject);
+ const projectActions = getActionsFromProject(newProject);
+ const newActions =
+ projectActions.length > 0
+ ? projectActions
+ : [createFirstAction()];
return {
settings: {
...settings,
@@ -942,6 +1010,7 @@ const createMlStore = (logging: Logging) => {
projectEdited: true,
actions: newActions,
dataWindow: getDataWindowFromActions(newActions),
+ hint: getHint(newActions, true),
model: undefined,
isEditorOpen: false,
isEditorLoadingFile: false,
@@ -1458,3 +1527,43 @@ const renameProject = (
},
};
};
+
+const getHint = (
+ actions: ActionData[],
+ suppressTrainAndAddActionHint: boolean
+): DataSamplesPageHint => {
+ const sufficientDataForTraining = hasSufficientDataForTraining(actions);
+
+ // We don't let you have zero. If you have > 2 you've seen it all before.
+ if (actions.length === 0 || actions.length > 2) {
+ if (sufficientDataForTraining && !suppressTrainAndAddActionHint) {
+ return "train";
+ }
+ return null;
+ }
+ const lastActionIdx = actions.length - 1;
+ const action = actions[lastActionIdx];
+ const isFirstAction = lastActionIdx === 0;
+
+ if (action.name.length === 0) {
+ if (action.recordings.length === 0) {
+ return isFirstAction ? "name-first-action" : "name-action";
+ } else {
+ return "name-action-with-samples";
+ }
+ }
+
+ if (action.recordings.length === 0) {
+ return isFirstAction ? "record-first-action" : "record-action";
+ }
+ if (action.recordings.length < 3) {
+ return "record-more-action";
+ }
+ if (isFirstAction && !suppressTrainAndAddActionHint) {
+ return "add-action";
+ }
+ if (sufficientDataForTraining && !suppressTrainAndAddActionHint) {
+ return "train";
+ }
+ return null;
+};