# Спецификация 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`: `` — runtime (dangerous), запрос только из кнопки микрофона (не при старте приложения); - интернет для загрузки модели — существующее разрешение m09 (SyncWorker); распознавание сеть не использует (🛡 офлайн). ## 7. Тесты - unit (pure JVM): ViewModel-логика эффектов (WorkingWeight → состояние веса, RestStarted → секунды, Message → строка статуса) — где выделено в чистые функции; валидация `Voice.ModelUrl` (паттерн SettingsValidator m10); - ручной смок — критерии 2/3 module_reqs (полный голосовой сценарий + синхронизация command_log).