149 lines
12 KiB
Markdown
149 lines
12 KiB
Markdown
# Требования к модулю: 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): тёмная тема,
|
||
пикеры/сегменты, дублирование цвета текстом — проверка владельцем
|
||
при приёмке.
|