VEU.WathBody/1-docs/4-modules/m10-phone-ui/module_reqs.md

149 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Требования к модулю: m10-phone-ui
> Модуль — **TrainingUi** телефона `Phone.WatchBody` (архитектура
> разд. 1.2): Jetpack Compose + Material 3 поверх ядра m09
> (`WorkoutCore`, `LocalDb`, `SyncQueue`, `ApiClient`,
> `SettingsRepository`). Голосовой ввод — m11 (кнопка микрофона —
> заглушка ручного ввода), канал часов — m12 (пульс/связь — прочерки).
> Самодостаточная копия требований (d-dev-6). Источники: Ф-3, Ф-4,
> Ф-5, Ф-6, Ф-10 (просмотр), Ф-11.1–11.3, Ф-13.1–13.2/13.5, Ф-14.2
> (manual), tech-req 4.1/6, ui-ux-recommendations разд. 3/5.
## 1. Назначение и границы
**В границах модуля:**
- Compose-каркас: `MainActivity`, тёмная тема Material 3, нижняя
навигация 5 вкладок — **Сегодня / Тренировка / История / Программы /
Профиль**; экраны «Библиотека» и «Настройки» — переходами из
«Сегодня»/«Профиля» (иконки в appbar);
- **экран «Сегодня»** (Ф-13.1): ввод дневника за 2–3 касания — АД
(сист./диаст.), вес, пульс покоя, самочувствие 1–5 (сегмент);
показ записи дня; кнопка «Начать тренировку» → поток допуска;
счётчик очереди sync;
- **поток «Допуск»** (Ф-13.2, модальный экран перед стартом силовой):
подтягивает АД из сегодняшнего дневника, ввод пульса сидя вручную;
`AdmissionChecker` (m09) → исходы: ALLOW («Начать»), CARDIO_ONLY
(силовые заблокированы — сообщение, прогулка), CANCEL (предложение
прогулки, кнопка «Отменить» 🛡 логируется), POSTPONE (перенос;
старт — явное «Всё равно начать» → `startAnyway` 🛡 лог);
выбор `session_kind` при старте (сегмент: обычная/возврат/делоад/
тест, умолчание normal — Ф-14.5);
- **экран «Тренировка»** (Ф-3): статус-строка (связь с часами — серый
прочерк до m12; сеть онлайн/офлайн), пульс «—» (канал — m12), блок
упражнения (текущее из плана сессии дня + рабочий вес), форма
подхода: пикер веса с шагом 2,5 кг (умолчание — последний вес
упражнения), пикер повторов, RPE 1–10 сегмент (Ф-13.3), боль
в колене 0–10 сегмент — только для группы «ноги» (Ф-13.3),
метка «по плану/отклонение» (считает WorkoutCore); таймер отдыха
(обратный отсчёт `Rest.DefaultSec`, фон красный/жёлтый (последние
10 с)/зелёный + текстовая подпись состояния); кнопки: «Отдых»
(старт таймера), микрофон (заглушка — ручной ввод подхода, m11
заменит), «Закончить», «Сбросить» (отмена с подтверждением —
статус `cancelled`, Ф-3.5); ≤ 4 активных элемента одновременно
(Ф-3.6);
- **экран «История»** (Ф-5): список finished/cancelled (дата,
длительность, число подходов; средний пульс — если есть),
карточка тренировки: подходы (упражнение, вес × повторения,
источник «голос/часы/правка» — в m10 «правка», метка плана,
RPE), отчёт план/факт по тренировке (доля подходов «по плану» —
Ф-11.3, локально по in_plan);
- **экран «Программы»** (Ф-10/Ф-11): активная версия (недели →
сессии → упражнения → план подходов вес × повторы, target RPE/
отдых — если заданы), план на сегодня (сессия дня недели);
список локально известных версий; 🛡 версии только читаются —
активация/применение rules-draft в v1 — консоль владельца (m08;
решение гейта 1.3);
- **экран «Профиль»** (Ф-6): пол, год рождения, вес, макс. пульс
(`Hr.MaxBpm` вручную или расчёт Танаки 208 − 0,7 × возраст);
зоны 50/70/85 % (показ; на часы — m12); сохранение →
`saveProfile` → sync `profile`;
- **экран «Библиотека»** (Ф-4): список упражнений (название, группа,
базовое/изоляция, активные/исключённые), добавить, переименовать,
исключить (`is_active=false` 🛡 логическое, Ф-4.2); выбор
упражнения при вводе подхода — из плана сессии + библиотека;
- **экран «Настройки»** (tech-req 4.1): `Server.BaseUrl`
(валидация — абсолютный https:// URL, иначе «Сохранить» неактивна),
`Server.ApiKey` (поле-пароль, 🛡 не отображается в открытом виде
и не логируется), `Sync.WifiOnly`, `Hr.MaxBpm` (120–240/пусто),
`Rest.DefaultSec` (30–600), `Safety.*` (BpCancel*, BpCardio*,
RestingHrSitting, HrStrengthMax 100–180) — расширение
`AppSettings` m09 (+ `hrMaxBpm`, `hrStrengthMax`); кнопка
«Синхронизировать сейчас» (+結果-баннер); первый запуск —
экран настройки подключения показывается до остальных вкладок;
- **баннеры синхронизации** (Ф-7.3/7.5): тихий статус — «в очереди
N записей», «Синхронизация временно недоступна» (сбой сети/
ретрай), «Данные успешно синхронизированы» (первая успешная),
ошибки авторизации/конфликта из флагов SyncWorker (401 — «ключ
неверен», 409 — «конфликт версии»); состояние — WorkInfo
unique-work «sync» + `SyncDao.count()`;
- сервисы UI: `ProgramView` — разбор body активной версии
(чистая функция поверх `PlanMatch`: сессия дня → список
упражнений с сетами); `ZoneCalculator` (Танака/ручной, зоны
50/70/85); расширение `AppSettings`/`SettingsRepository`;
расписание sync — UI вызывает `SyncWorker.schedule` после
действий WorkoutCore и по кнопке (WorkoutCore ядро остаётся без
Android-контекста);
- unit-тесты (pure JVM): `ProgramView` (сессия дня, пустой/
битый body), `ZoneCalculator`, валидация настроек (URL/диапазоны).
**Вне границ модуля:** STT/TTS и голосовые команды (m11 — кнопка
микрофона остаётся заглушкой ручного ввода), пульс/связь с часами
и предупреждение `HrStrengthMax` во время тренировки (m12 — канал;
настройка вводится в m10), редактор программ и создание версий
`author=user` (решение гейта 1.3 — v1 просмотр; создание — консоль),
применение rules-draft подтверждением атлета (Ф-12.3 — в v1
консоль владельца; эндпоинт активации для атлета — кандидат v2),
ответ атлета на авто-break (Ф-14.2 — серверного пути записи ответа
нет, кандидат v2), домашний поддерживающий комплекс (Ф-14.6, v2),
восстановление пульса пропущенного периода (m12), админ-функции.
## 2. Решения интерфейса (tech-req 6, ui-ux разд. 3/5)
- Тёмная тема по умолчанию, Material 3; шрифт ≥ 16 pt, контраст
WCAG AA, цели касания ≥ 48 dp;
- ключевые действия — нижняя треть экрана (одна рука);
- числовой ввод — пикеры (вес шаг 2,5 кг; повторы шаг 1), не
клавиатура; RPE/самочувствие/боль — сегмент-контролы, не слайдеры;
- цветовые сигналы дублируются текстом/иконкой (таймер отдыха,
статусы допуска, баннеры);
- предупреждения — спокойные формулировки («Пульс выше порога.
Отдохните или завершите»), без тревожной лексики;
- уведомления только значимые (SUS ≥ 80 — порог релиза; приёмка
вручную владельцем, эмулятора в среде нет).
## 3. Инварианты (🛡 — нарушать запрещено)
1. **UI не пишет в LocalDb** — только вызовы `WorkoutCore`
(единственный писатель, инвариант m09); ViewModel хранит только
UI-состояние.
2. **Офлайн-first** — каждый экран работает без сети (КУ-3); сеть —
только SyncQueue по действиям пользователя (кнопка/фоновое
расписание).
3. **Тайны** — API-ключ не отображается открыто и не логируется
(З-6); в UI — замаскированное поле.
4. **Допуск** — блокировки по `Safety.*` снимаются только явными
действиями с логированием (`startAnyway` / отмена) — Ф-13.2/13.5.
5. **Версии программ на телефоне неизменяемы и только читаются**
(Ф-10.1); активная версия фиксируется у тренировки при старте
(Ф-10.3 — уже в m09).
6. **Удаление упражнения — только логическое** (`is_active=false`,
Ф-4.2); история читаема.
## 4. Критерии приёмки модуля
1. `assembleDebug` собирается, APK запускается (вручную владельцем);
unit-тесты зелёные (ProgramView/зоны/валидация настроек).
2. Ручной смок сценария на устройстве/эмуляторе владельца: первый
запуск (настройки) → «Сегодня» (дневник) → допуск (все 4 исхода
по порогам) → тренировка (2–3 подхода с меткой плана, таймер
отдыха) → закончить → история (карточка с план/факт) → программы
(план на сегодня) → профиль → библиотека (добавить/исключить).
3. Смок синхронизации на живом (docker) сервере: действия сценария
п. 2 уходят пакетами `/api/v1/sync`, подтверждённые GUID
удаляются из очереди (счётчик «Сегодня» → 0), строки видны
в `src.*` (банее-статусы соответствуют).
4. Экраны соответствуют UI/UX-стандарту (разд. 2): тёмная тема,
пикеры/сегменты, дублирование цвета текстом — проверка владельцем
при приёмке.