# Спецификация 04: экраны «История» и «Программы», сервис ProgramView Источники: Ф-5 (история), Ф-11.3 (отчёт план/факт), Ф-10 (просмотр), m09 `PlanMatch`/DAO. Единицы 5–6 + сервис 11. ## 1. ProgramView (чистая функция над body активной версии) Вход: `body` (JSON-строка), `dayOfWeekIso` (1=понедельник … 7=воскресенье, m09 PlanMatch). Выход: ``` SessionView(day: String, focus: String?, items: List) ItemView(exerciseName: String, planSets: List) SetPlan(weightKg: Double, reps: Int) ``` Правила: первая сессия дня недели из `weeks[].sessions[]` (та же семантика, что `PlanMatch.planFor` — m09); порядок недель — по номеру, упражнения — как в JSON; подходы упражнения — все из `sets[]`; битый/пустой body или нет сессии дня — пустой список (экран — «план на сегодня не задан»); дни недели — ISO-имена (`monday…sunday`). Отдельно `allWeeks(body)` для экрана «Программы» (полная структура недель без привязки к дню). ## 2. «История» (Ф-5) `HistoryViewModel`: `history` (Flow: finished/cancelled по убыванию started_at — m09 DAO). Список: дата/время, длительность (endedAt − startedAt; незавершённая — «—»), число подходов, веха вида (normal/return/deload/test). Карточка тренировки (по выбору): - шапка: дата, длительность, статус (завершена/отменена), вид; - список подходов: упражнение, вес × повторы, источник («правка» в v1; «голос/часы» — словарь m09 `source`), метка «по плану»/ «отклонение», RPE, боль в колене (если есть); - отчёт план/факт (Ф-11.3, локально): доля подходов `in_plan` = inPlan / all (процент + текст «из N подходов по плану»); средний пульс — если записан (v1 обычно «—», .fit-факты — сервер); - всё из LocalDb, без сети (Ф-5.3). ## 3. «Программы» (Ф-10, просмотр) `ProgramsViewModel`: `activeProgram` (Flow, m09 DAO), список локально известных версий (`program_version` таблица: номер, статус, автор, дата). Экран: - сводка активной: номер версии, статус active, автор, дата; - «План на сегодня» — `ProgramView.sessionFor(activeBody, today)`: упражнения с планом вес × повторы (тот же блок, что на тренировке); нет сессии — «сегодня по плану отдыха»; - полная структура — `allWeeks`: неделя № → сессии (день, фокус) → упражнения → план подходов; сворачиваемые карточки недель; - 🛡 только чтение: активация/применение rules-draft — консоль владельца (решение гейта 1.3 m10; Ф-12.3 телефонный путь — кандидат v2); - нет активной версии — заглушка «Программа не назначена — обратитесь к владельцу» + кнопка «Обновить» (GET programs/active, m09 ApiClient → запись в LocalDb + schedule sync). Словарь групп (общий для экранов): push «жим», pull «тяга», legs «ноги», core «кор», cardio «кардио». ## 4. Тесты (unit, pure JVM) | # | Проверка | Ожидание | |---|---|---| | 1 | `sessionFor` — среда, две сессии в дне | первая сессия, подходы по порядку | | 2 | `sessionFor` — день без сессий / пустой body / битый JSON | пустой список, исключений нет | | 3 | `sessionFor` согласован с `PlanMatch.planFor` | упражнение/вес/повторы первой сессии совпадают | | 4 | `allWeeks` — порядок недель/упражнений | как в JSON | | 5 | План/факт карточки: 2 in_plan из 5 | 40 %, текст «из 5 подходов по плану 2» |