64 lines
3.8 KiB
Markdown
64 lines
3.8 KiB
Markdown
# Спецификация 04: настройки поля и вибрации
|
||
|
||
Источники: module_reqs разд. 1 (единицы 6–7), Ф-2.2 (границы зон —
|
||
настройки поля), Ф-2.4 errata (длительность отдыха — настройка,
|
||
умолчание `Rest.DefaultSec`), решение гейта 1.3 № 3 (sideload живёт
|
||
на умолчаниях) и № 5 (красная зона процентная). Единицы 6–7.
|
||
|
||
## 1. Properties (resources\settings\settings.xml)
|
||
|
||
| Свойство | Тип | Диапазон редактора | Умолчание | Смысл |
|
||
|---|---|---|---|---|
|
||
| `restSec` | numeric | 30–600 | 120 | длительность автономного таймера отдыха, с (= `Rest.DefaultSec` телефона) |
|
||
| `hrMaxBpm` | numeric | 0–250 | 0 | макс. ЧСС для зон; 0 — расчёт по формуле Танаки от `age` |
|
||
| `age` | numeric | 14–100 | 45 | возраст для формулы Танаки (208 − 0,7 × возраст) |
|
||
|
||
- подписи/описания — ru/en (строки в settings.xml + strings);
|
||
- значения читаются `FieldSettings` при `initialize()`; смена
|
||
настроек применяется при следующем запуске активности (поле
|
||
перезапускается платформой);
|
||
- правка значений на устройстве — только через Garmin Connect
|
||
Mobile/Express для приложений из магазина CIQ (решение 3 гейта
|
||
1.3): sideload-сборка живёт на умолчаниях, смена поведения =
|
||
пересборка.
|
||
|
||
## 2. `FieldSettings` (клампы — защита от кривых значений)
|
||
|
||
Чистый класс: чтение property → кламп → поле:
|
||
|
||
- `restSec`: вне 30–600 или не число → 120;
|
||
- `hrMaxBpm`: вне 0–250 → 0 (авто);
|
||
- `age`: вне 14–100 → 45.
|
||
|
||
`maxBpm()` delegирует в `ZoneCalc.maxBpmFor(hrMaxBpm, age)`.
|
||
|
||
## 3. Вибрации (`Vibe.mc`)
|
||
|
||
`Attention.vibrate([...])`, до 8 `VibeProfile(duty, мс)`:
|
||
|
||
| Событие | Паттерн | Вызов |
|
||
|---|---|---|
|
||
| конец отдыха (RestTimer.onEnd == true) | `[VibeProfile(25, 300)]` — однократная лёгкая | из `compute` |
|
||
| красная зона (Vibe-гистерезис сработал) | `[VibeProfile(75, 200), VibeProfile(0, 150), VibeProfile(75, 200)]` — двойная заметная | из `compute` |
|
||
|
||
- вибрация различается паттерном (ui-ux: паттерны различаются —
|
||
отдых/предупреждение);
|
||
- недоступность вибрации на модели — вызов молча пропускается
|
||
(проверка наличия/`try-catch`; инвариант 4, Ф-2.8);
|
||
- гистерезис красной зоны: повторная двойная не раньше 60 000 мс;
|
||
выход в GREEN/BLUE/NONE сбрасывает (спека 02 §4);
|
||
- вибрации не стекаются: не чаще одной причины за проход `compute`.
|
||
|
||
## 4. Тесты (Toybox.Test, дополняют спеку 02)
|
||
|
||
`FieldSettings` (чистые клампы):
|
||
1. `clampRest(10) == 120`, `clampRest(600) == 600`, `clampRest(30) == 30`;
|
||
2. `clampRest(null) == 120` (property отсутствует);
|
||
3. `clampHr(-5) == 0`, `clampHr(250) == 250`;
|
||
4. `clampAge(200) == 45`, `clampAge(14) == 14`;
|
||
5. `maxBpm()`: hrMaxBpm 190 → 190; hrMaxBpm 0 + age 45 → 177.
|
||
|
||
`mmss` (форматирование строки состояния, спека 03 §2):
|
||
6. `mmss(0) == "0:00"`, `mmss(59_999) == "0:59"`, `mmss(60_000) == "1:00"`,
|
||
`mmss(65_000) == "1:05"`, `mmss(600_000) == "10:00"`.
|