5.3 KiB
Спецификация 03: экран поля — макет и отрисовка
Источники: module_reqs разд. 1 (единица 5) и 2, Ф-2.1/Ф-2.2 (с errata), ui-ux разд. 2 (glanceable, цвет дублируется текстом), tech-req 6 п. 1. Единица 5.
1. Макет (resources\layouts\layout.xml)
Параметрический макет семейства квадратных MIP-экранов — якоря
(loc="center" и верх/низ), без единой фиксированной координаты:
позиции и шрифты вычисляются от dc.getWidth()/getHeight() в
onLayout. Один макет на всё семейство (fenix6x 280×280, fenix6
260×260, fenix6s 240×240 — добавление таргета без правок, инвариант
5).
Элементы (сверху вниз):
| Элемент | Содержимое | Шрифт |
|---|---|---|
zoneLbl |
подпись зоны + цветная плашка-ободок | FONT_TINY |
hrLbl |
текущий пульс или «—» | FONT_NUMBER_LARGE (запасной FONT_NUMBER_MEDIUM — §3) |
unitLbl |
«уд/мин» | FONT_TINY |
stateLbl |
«ОТДЫХ mm:ss» / «ПОДХОД mm:сс · ср N» | FONT_SMALL |
2. Содержимое и цвета
- фон — чёрный (
COLOR_BLACK), текст — белый; MIP, читаемость на солнце без подсветки; - зона: плашка/ободок цвета зоны (
COLOR_BLUE/GREEN/YELLOW/REDпо ZoneCalc) вокруг подписи зоны; подпись текстом — цвет не единственный носитель (ui-ux): «восстановление»/«лёгкая»/ «средняя»/«высокая»; нет пульса → NONE: серая плашка (COLOR_DK_GRAY), подпись «—»; - пульс: крупное число
currentHeartRate; null → «—» (unitLbl гасится); - строка состояния:
- идёт отдых (
RestTimer.isResting) → «ОТДЫХ 1:48» — обратный отсчёт остатка (mm:сс, при остатке ≥ 10 мин «мм:сс» с ведущими разрядами не рвётся — форматm:ss/mm:ss); - иначе → «ПОДХОД 2:05 · ср 132»:
SetTracker.elapsedMs(время с последнего Lap — errata Ф-2.1) иSetTracker.avgBpm; среднее null → «ср —»;
- идёт отдых (
- форматирование времени — чистая функция
mmss(ms)(округление вниз до секунд; часы не нужны — интервалы < 10 мин).
3. Шрифт пульса (адаптивный)
onLayout: берётся FONT_NUMBER_LARGE; если высота глифов +
прочих элементов не влезает в высоту области (мелкие страницы
данных, 2+ поля на странице) — шаг вниз до FONT_NUMBER_MEDIUM.
Пульс — главное число экрана (Ф-2.1: шрифт пульса максимальный из
доступных на области).
4. Класс FenixDataField (связка)
initialize(): создание ядра (SetTracker/RestTimer/ZoneCalc/ Vibe/FieldSettings), начальное состояние — «нет данных» (переменные инициализируются здесь, не вcompute— асинхронность compute/onUpdate по документации);compute(info): раз в секунду —currentHeartRate→SetTracker.onSample, кэш пульса;RestTimer.onEnd(timerTime)→ лёгкая вибрация;Vibe.onZone(zone, timerTime)→ двойная при красной (гистерезис);onTimerLap():SetTracker.onLap+RestTimer.start— Lap = конец подхода = старт отдыха (errata Ф-2.3);onTimerStart/Reset:SetTrackerк нулю,RestTimerне активен;onUpdate(dc): отрисовка по кэшу (§2); данные могли ещё не прийти — рисуем прочерки;onTimerPause/Resume: без кода —timerTimeстоит/идёт, таймеры замирают сами (спека 02 §3).
5. Симуляторный смок (критерий приёмки 2, шаг 3)
- Поле добавляется в профиль Strength симулятора, отображается без ошибок отрисовки;
- симуляция пульса: число обновляется ≈1/с, плашка зоны и подпись соответствуют порогам (прогнать пульс через все 4 зоны);
- Lap (симулятор): метрики обнуляются, строка «ОТДЫХ …» тикает вниз, по нулю — однократная вибрация (лог симулятора);
- пульс в красной зоне — двойная вибрация, повтор не чаще 60 с;
- пауза активности — отсчёты стоят; resume — продолжаются;
- нулевой/отсутствующий пульс — «—», поле живое (не падает).