# Спецификация 01: каркас приложения (shell) Источники: архитектура 1.2 (TrainingUi), Ф-3.6, Ф-7.3/7.5, tech-req 4.1/6, ui-ux разд. 3. Единица 1 (каркас) + баннеры (10). ## 1. Каркас - `WatchBodyApp` (Application) — ручной DI-контейнер (без Hilt в v1): `AppDatabase` (m09 build), `WorkoutCore`, `SettingsRepository`, ленивый `ApiClient` (создаётся по актуальным настройкам); - `MainActivity` — единственная activity; `WatchBodyTheme` — тёмная colorScheme Material 3, типографика ≥ 16 sp; - нижняя навигация `NavigationBar` — 5 вкладок: Сегодня / Тренировка / История / Программы / Профиль; состояние — один `NavController` (compose-navigation), вкладки — `popUpTo(start) saveState/restore`; - «Библиотека» и «Настройки» — экраны-переходы (иконки в appbar «Сегодня» и «Профиля»); системный Back — к вкладке. ## 2. Первый запуск Если `baseUrl` или `apiKey` пусты — поверх вкладок показывается экран «Настройки» (без него остальное неактивно); после сохранения валидных значений — возврат на «Сегодня». Повторно гейт не срабатывает. ## 3. Баннеры синхронизации (Ф-7.3/7.5) Источник состояния: `WorkManager.getWorkInfosForUniqueWorkFlow("sync")` + `SyncDao.count()` (Flow). Правила отображения (верх экрана, тихий цветовой код + текст — цвет дублируется текстом 🛡): | Состояние | Баннер | |---|---| | очередь > 0, work нет/не RUNNING | «В очереди на отправку: N» | | work RUNNING | «Синхронизация…» | | SUCCEEDED и очередь стала 0 | «Данные успешно синхронизированы» (скрывается через ~5 с, показ однократно на смену состояния) | | FAILED флаг `authError` (401) | «Ключ API неверен — проверьте настройки» (постоянно до успешной синхронизации) | | FAILED флаг `conflict` (409) | «Конфликт версии программы — обратитесь к владельцу» | | FAILED прочее (ретрай/сеть) | «Синхронизация временно недоступна — повторим автоматически» | Индикатор сети в статус-строке тренировки: `ConnectivityManager` (онлайн/офлайн) — информационный, ничего не блокирует (офлайн-first). ## 4. Расписание отправки - после каждого действия пользователя через `WorkoutCore` (дневник/подход/старт/финиш/профиль/упражнение/перерыв) — `SyncWorker.schedule(context, wifiOnly)` (m09, unique KEEP — повторные вызовы не плодят работы); - кнопка «Синхронизировать сейчас» (Настройки) — новый `SyncWorker.scheduleNow(context)`: те же worker/имя/ретраи, ограничение только CONNECTED (явное действие — Wi-Fi-ограничение не применяется; расширение m09, readme m09 п. 6). ## 5. Правила - 🛡 UI не обращается к DAO/Api напрямую — только `WorkoutCore`, `SettingsRepository`, DAO-чтения (Flow) для списков истории/ очереди (чтение напрямую разрешено — единственный писатель WorkoutCore, m09); - ViewModels — `ViewModel` + viewModelFactory из контейнера; состояние экранов — `StateFlow`; - строковые ресурсы — ru (локализация одного языка в v1).