94 lines
6.4 KiB
Markdown
94 lines
6.4 KiB
Markdown
# Спецификация 05: интеграция UI — экран «Тренировка» и «Настройки»
|
||
|
||
Источники: Ф-1.1 (активация кнопкой, экран активной тренировки),
|
||
Ф-1.6 (правка ≤ 2 касаний), Ф-3.1 (статус-строка), решения гейта
|
||
1.3 №1/№2, ui-ux разд. 3 (текст дублирует цвет, нижняя треть,
|
||
≥ 48 dp). Единицы 6–7. Расширение экранов m10.
|
||
|
||
## 1. Экран «Тренировка» — кнопка микрофона и прослушивание
|
||
|
||
- в TopAppBar рядом с Edit — кнопка Mic (`Icons.Filled.Mic` /
|
||
`MicOff`), цель ≥ 48 dp; состояние дублируется текстом в теле
|
||
экрана: «Слушаю…» (индикатор — пульсирующая точка) /
|
||
«Голос выключен» (🛡 цвет → текст);
|
||
- **первое включение** (последовательность, без блокировки
|
||
интерфейса):
|
||
1. разрешение `RECORD_AUDIO` (runtime-запрос): отказ → голос
|
||
выключен, сообщение «Без разрешения микрофона голос
|
||
недоступен» (кнопка остаётся доступной для повторного
|
||
запроса);
|
||
2. модель не загружена (`ModelStore.isDownloaded()=false`) →
|
||
диалог «Модель распознавания не загружена. Скачать сейчас?
|
||
(~45 МБ)» → да → загрузка (прогресс %, ошибки текстом,
|
||
кнопка «Отмена»), по успеху — старт прослушивания; нет →
|
||
голос выключен;
|
||
3. готово → `SttEngine.startListening` (спец 02);
|
||
- повторное нажатие — выключение (`stopListening`); выход с экрана
|
||
тренировки — остановка прослушивания (`DisposableEffect`);
|
||
прослушивание работает только при активной тренировке (Ф-1.1) —
|
||
заглушка «Нет активной тренировки» кнопки не активирует;
|
||
|
||
## 2. Обратная связь на экране
|
||
|
||
- строка последней команды (текст, не только цвет 🛡): «Принято:
|
||
подход 60 на 10» / «Принято: вес 62,5» / «Принято: отдых 90» /
|
||
«Принято: РПЭ 7» / «Не распознано» / «Число вне диапазона» /
|
||
«Сначала выберите упражнение» (эффекты Message исполнителя);
|
||
- строка появляется при первой команде, остаётся до следующей.
|
||
|
||
## 3. Текущее упражнение (решение гейта 1.3 №2)
|
||
|
||
- строки блока «План сессии» — clickable: тап выбирает «текущее
|
||
упражнение» (подсветка + подпись «текущее»);
|
||
- умолчание — первый пункт плана сессии дня; план пуст —
|
||
используется последний выбранный в форме подхода (selected
|
||
exercise m10 сохраняется); совсем нет — ничего не выбрано,
|
||
голосовые Approach/Weight отклоняются (no_exercise, спец 03 §5);
|
||
- голос пишет подходы в текущее упражнение (`logSet(source=
|
||
"voice")`); ручная форма m10 (Edit) остаётся без изменений
|
||
(правка ≤ 2 касаний, Ф-1.6);
|
||
- эффект `WorkingWeight(w)` — обновляет вес формы m10 и показ
|
||
плана (следующие «Подход» озвучивают уже новый вес, если
|
||
атлет говорит «подход на R» без веса — НЕ входит в грамматику
|
||
v1: вес в команде обязателен, Ф-1.2).
|
||
|
||
## 4. Таймер отдыха
|
||
|
||
- эффект `RestStarted(s)` → `restLeft = s` (переиспользование
|
||
RestCard/RestTimer m10; фазы цвет+текст без изменений);
|
||
- ручной старт кнопкой «Отдых» остаётся (умолчание
|
||
`Rest.DefaultSec`).
|
||
|
||
## 5. «Настройки» — блок «Распознавание речи» (расширение m10)
|
||
|
||
- `Voice.ModelUrl` — текстовое поле, умолчание
|
||
`https://alphacephei.com/vosk/models/vosk-model-small-ru-0.22.zip`;
|
||
валидация — абсолютный https:// URL (кнопка «Сохранить»
|
||
неактивна при ошибке — паттерн BaseUrl m10);
|
||
- статус модели: «Не загружена» / «Загружена (N МБ)»;
|
||
- кнопка «Загрузить» → `ModelStore.download` с прогрессом
|
||
(повтор при ошибке; замена каталога при смене URL);
|
||
- кнопка «Проверить TTS» → «Русский голос доступен» /
|
||
«TTS недоступен — только сигналы и текст» (`ttsAvailable()`,
|
||
спец 04);
|
||
- AppSettings m09/m10 расширяется полем `voiceModelUrl` (errata
|
||
m10 по образцу `hrMaxBpm`; SettingsRepository — DataStore).
|
||
|
||
## 6. Разрешения и манифест
|
||
|
||
- `AndroidManifest.xml`: `<uses-permission
|
||
android:name="android.permission.RECORD_AUDIO"/>` — runtime
|
||
(dangerous), запрос только из кнопки микрофона (не при старте
|
||
приложения);
|
||
- интернет для загрузки модели — существующее разрешение m09
|
||
(SyncWorker); распознавание сеть не использует (🛡 офлайн).
|
||
|
||
## 7. Тесты
|
||
|
||
- unit (pure JVM): ViewModel-логика эффектов (WorkingWeight →
|
||
состояние веса, RestStarted → секунды, Message → строка
|
||
статуса) — где выделено в чистые функции; валидация
|
||
`Voice.ModelUrl` (паттерн SettingsValidator m10);
|
||
- ручной смок — критерии 2/3 module_reqs (полный голосовой
|
||
сценарий + синхронизация command_log).
|