192 lines
7.1 KiB
MonkeyC
192 lines
7.1 KiB
MonkeyC
// Поле данных «Феникс» для профиля «Силовая» (Ф-2, m13).
|
||
// Экран: текущий пульс (крупно) + плашка зоны цветом с подписью, строка
|
||
// «ПОДХОД мм:сс - ср N» / «ОТДЫХ мм:сс». Lap — граница подхода и старт
|
||
// автономного отдыха (errata Ф-2.3/Ф-2.4). Кнопки не перехватываются,
|
||
// запись .fit ведёт платформа Garmin (Ф-2.5–Ф-2.7).
|
||
import Toybox.Activity;
|
||
import Toybox.Graphics;
|
||
import Toybox.WatchUi;
|
||
|
||
class FenixDataField extends WatchUi.DataField {
|
||
var _settings;
|
||
var _zones;
|
||
var _set;
|
||
var _rest;
|
||
var _vibe;
|
||
var _fmt;
|
||
|
||
var _hr; // кэш пульса (Number или null)
|
||
var _maxBpm10; // макс. ЧСС ×10
|
||
var _zone; // текущая зона (идентификатор ZoneCalc)
|
||
|
||
function initialize() {
|
||
DataField.initialize();
|
||
_settings = new FieldSettings();
|
||
_zones = new ZoneCalc();
|
||
_set = new SetTracker();
|
||
_rest = new RestTimer();
|
||
_vibe = new Vibe();
|
||
_fmt = new Format();
|
||
_hr = null;
|
||
_maxBpm10 = _zones.maxBpm10For(_settings.hrMaxBpm, _settings.age);
|
||
_zone = _zones.ZONE_NONE;
|
||
}
|
||
|
||
function timerNow() {
|
||
var info = Activity.getActivityInfo();
|
||
if (info != null && info.timerTime != null) {
|
||
return info.timerTime;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
// Lap (штатно — конец подхода): метрики обнуляются, отдых стартует
|
||
function onTimerLap() {
|
||
var t = timerNow();
|
||
_set.onLap(t);
|
||
_rest.start(t, _settings.restSec);
|
||
}
|
||
|
||
function onTimerStart() {
|
||
resetState();
|
||
}
|
||
|
||
function onTimerReset() {
|
||
resetState();
|
||
}
|
||
|
||
function resetState() {
|
||
_set.onLap(0);
|
||
_rest.initialize();
|
||
}
|
||
|
||
// Раз в секунду: пульс → метрики, зоны, сигналы вибраций
|
||
function compute(info) {
|
||
_hr = info.currentHeartRate;
|
||
var t = info.timerTime;
|
||
if (t == null) {
|
||
return;
|
||
}
|
||
_set.onSample(_hr);
|
||
_zone = _zones.zoneFor(_hr, _maxBpm10);
|
||
if (_rest.onEnd(t)) {
|
||
_vibe.vibrateRestEnd();
|
||
}
|
||
_vibe.onZone(_zone == _zones.ZONE_RED, t);
|
||
}
|
||
|
||
function colorFor(zoneId) {
|
||
if (zoneId == _zones.ZONE_BLUE) {
|
||
return Graphics.COLOR_BLUE;
|
||
}
|
||
if (zoneId == _zones.ZONE_GREEN) {
|
||
return Graphics.COLOR_GREEN;
|
||
}
|
||
if (zoneId == _zones.ZONE_YELLOW) {
|
||
return Graphics.COLOR_YELLOW;
|
||
}
|
||
if (zoneId == _zones.ZONE_RED) {
|
||
return Graphics.COLOR_RED;
|
||
}
|
||
return Graphics.COLOR_DK_GRAY;
|
||
}
|
||
|
||
function labelFor(zoneId) {
|
||
if (zoneId == _zones.ZONE_BLUE) {
|
||
return WatchUi.loadResource(Rez.Strings.ZoneBlue);
|
||
}
|
||
if (zoneId == _zones.ZONE_GREEN) {
|
||
return WatchUi.loadResource(Rez.Strings.ZoneGreen);
|
||
}
|
||
if (zoneId == _zones.ZONE_YELLOW) {
|
||
return WatchUi.loadResource(Rez.Strings.ZoneYellow);
|
||
}
|
||
if (zoneId == _zones.ZONE_RED) {
|
||
return WatchUi.loadResource(Rez.Strings.ZoneRed);
|
||
}
|
||
return WatchUi.loadResource(Rez.Strings.ZoneNone);
|
||
}
|
||
|
||
// Параметрическая отрисовка по размерам области (dc): ни одной
|
||
// фиксированной координаты — один код на всё семейство экранов (Ф-2.8)
|
||
function onUpdate(dc) {
|
||
var w = dc.getWidth();
|
||
var h = dc.getHeight();
|
||
|
||
dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
|
||
dc.clear();
|
||
|
||
// 1) плашка зоны сверху: цвет зоны + подпись текстом (цвет —
|
||
// не единственный носитель, ui-ux)
|
||
var tiny = Graphics.FONT_TINY;
|
||
var zoneLabel = labelFor(_zone);
|
||
var tw = dc.getTextWidthInPixels(zoneLabel, tiny);
|
||
var th = dc.getFontHeight(tiny);
|
||
var pad = 4;
|
||
var plateW = tw + pad * 2;
|
||
var plateH = th + pad;
|
||
var plateX = (w - plateW) / 2;
|
||
var plateY = 2;
|
||
if (_zone == _zones.ZONE_NONE) {
|
||
dc.setColor(Graphics.COLOR_DK_GRAY, Graphics.COLOR_DK_GRAY);
|
||
dc.fillRectangle(plateX, plateY, plateW, plateH);
|
||
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_DK_GRAY);
|
||
} else {
|
||
var zc = colorFor(_zone);
|
||
dc.setColor(zc, zc);
|
||
dc.fillRectangle(plateX, plateY, plateW, plateH);
|
||
dc.setColor(Graphics.COLOR_BLACK, zc);
|
||
}
|
||
dc.drawText(plateX + pad, plateY + 1, tiny, zoneLabel, Graphics.TEXT_JUSTIFY_LEFT);
|
||
|
||
// 2) пульс — крупное число (адаптивный шрифт: THAI_HOT, если не
|
||
// влезает — MEDIUM; поле может делить страницу с другими полями)
|
||
var bigFont = Graphics.FONT_NUMBER_THAI_HOT;
|
||
var bigH = dc.getFontHeight(bigFont);
|
||
if (bigH > h * 5 / 10) {
|
||
bigFont = Graphics.FONT_NUMBER_MEDIUM;
|
||
bigH = dc.getFontHeight(bigFont);
|
||
}
|
||
var hrText;
|
||
if (_hr == null || _hr <= 0) {
|
||
hrText = "-";
|
||
} else {
|
||
hrText = "" + _hr;
|
||
}
|
||
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
|
||
var hw = dc.getTextWidthInPixels(hrText, bigFont);
|
||
var hrY = plateY + plateH + (h - plateH - plateY - bigH - th - 8) / 2;
|
||
if (hrY < plateY + plateH + 2) {
|
||
hrY = plateY + plateH + 2;
|
||
}
|
||
dc.drawText((w - hw) / 2, hrY, bigFont, hrText, Graphics.TEXT_JUSTIFY_LEFT);
|
||
|
||
// 3) подпись единиц под пульсом
|
||
var unit = WatchUi.loadResource(Rez.Strings.Unit);
|
||
var uw = dc.getTextWidthInPixels(unit, tiny);
|
||
dc.drawText((w - uw) / 2, hrY + bigH + 1, tiny, unit, Graphics.TEXT_JUSTIFY_LEFT);
|
||
|
||
// 4) строка состояния: ОТДЫХ (остаток) или ПОДХОД (время с границы
|
||
// Lap - средний пульс интервала)
|
||
var line;
|
||
var t = timerNow();
|
||
var small = Graphics.FONT_SMALL;
|
||
var lh = dc.getFontHeight(small);
|
||
if (_rest.isResting(t)) {
|
||
line = WatchUi.loadResource(Rez.Strings.Rest) + " " + _fmt.mmss(_rest.remainingMs(t));
|
||
} else {
|
||
var avg = _set.avgBpm();
|
||
var avgText;
|
||
if (avg == null) {
|
||
avgText = "-";
|
||
} else {
|
||
avgText = "" + avg;
|
||
}
|
||
line = WatchUi.loadResource(Rez.Strings.Set) + " " + _fmt.mmss(_set.elapsedMs(t))
|
||
+ " - " + WatchUi.loadResource(Rez.Strings.Avg) + " " + avgText;
|
||
}
|
||
var lw = dc.getTextWidthInPixels(line, small);
|
||
dc.drawText((w - lw) / 2, h - lh - 2, small, line, Graphics.TEXT_JUSTIFY_LEFT);
|
||
}
|
||
}
|