HR: auto-connect at recording start if a strap is paired; HR on/off toggle replaces the wind button
Earlier I over-corrected: 'don't scan when the strap is absent' became 'never auto-connect'. Restore conditional auto: at recording start (ride or workout) connect the paired strap and poll; absent strap is safe now (BleHrService scans briefly and stops - no drain). No paired strap -> HR off. - gps.js: GPS.setHrOn(on) - connect+poll / disconnect+stop; start auto-ons it. - Record screen: the inconvenient 'Ветер' button is gone; in its place an HR on/off toggle (square, heart+pulse icon; grey off, red on) -> setHrOn. (Also corrected a stale assumption: the phone DOES have Google services.)
This commit is contained in:
parent
62434d6155
commit
f7ba059628
4 changed files with 64 additions and 9 deletions
|
|
@ -44,6 +44,22 @@ project-hr-sensor.
|
|||
- Заметка: аудио в WebView может требовать user-gesture; старт записи - это жест, должно
|
||||
играть. Проверить на устройстве.
|
||||
|
||||
## Правка после теста: авто-ЧСС на старте + тоггл ВКЛ/ВЫКЛ вместо "Ветер"
|
||||
Я перестарался: по просьбе "не искать, если браслета нет" убрал автоконнект ВООБЩЕ. Нужно было
|
||||
оставить авто с проверкой наличия. Исправлено:
|
||||
- `GPS.setHrOn(on)` (gps.js): ON - проверяет BT (off -> запрос включения), коннектит привязанный
|
||||
датчик, запускает поллинг; OFF - стоп поллинг + disconnect. Безопасно: BleHrService при
|
||||
отсутствии браслета коротко сканит и `stopSelf` (драйна нет).
|
||||
- Старт записи (и GPS, и зарядки): если датчик привязан - авто `setHrOn(true)`. Так "надел
|
||||
датчик -> начал -> подключился сам", без ручного коннекта каждый раз. Нет привязанного - ЧСС off.
|
||||
- Экран записи: кнопка **"Ветер" убрана** (неудобна), на её месте **тоггл ЧСС** (квадрат с
|
||||
сердечком+линией пульса; серый = выкл, красный = вкл), дёргает `GPS.setHrOn`.
|
||||
- Ручная кнопка "Подключить" в настройках остаётся.
|
||||
|
||||
Факт-чек (я ошибся ранее): на телефоне Google-сервисы ЕСТЬ (`com.google.android.gms`, Play
|
||||
Store) - значит системный диалог включения гео через Play Services доступен. Авто-вкл BT/гео по
|
||||
запросу (попап + 2 настройки "не спрашивать") - отдельная задача, теперь подтверждено выполнимо.
|
||||
|
||||
## Проверка
|
||||
Синтаксис JS ок. На телефоне: выбрать "Зарядка", Старт (без браслета покажет "Подключите
|
||||
пульсометр"), подключить датчик -> пульс крупно + ккал растут; Стоп -> деталь с графиком.
|
||||
|
|
|
|||
|
|
@ -725,6 +725,11 @@ select {
|
|||
.wk-status { color: var(--muted); font-size: 13px; text-align: center; min-height: 18px; margin-bottom: 6px; }
|
||||
.workout-screen .btn-primary, .workout-screen .btn-secondary { margin-top: 8px; width: 100%; }
|
||||
|
||||
/* HR on/off toggle on the record screen (replaces the wind button): grey = off, coloured = on. */
|
||||
.rec-hr-toggle { color: #888; display: inline-flex; align-items: center; justify-content: center; min-width: 46px; padding: 6px 10px; }
|
||||
.rec-hr-toggle svg { display: block; }
|
||||
.rec-hr-toggle.active { color: #ef5350; background: rgba(239, 83, 80, 0.18); }
|
||||
|
||||
/* Progress fill for long-running action buttons: the background fills left-to-right by
|
||||
--pct (0-100%, set from JS). The label stays on top and readable; the unfilled part keeps
|
||||
the button's own background. Used by recompute / elevation-refine / roads-rebuild. */
|
||||
|
|
|
|||
|
|
@ -868,6 +868,28 @@ GPS._stopHrMonitor = function() {
|
|||
try { window.__TAURI__.core.invoke("ble_clear_hr"); } catch {}
|
||||
};
|
||||
|
||||
// Turn HR on/off during a recording (the toggle on the record screen). ON connects to the
|
||||
// paired strap (Kotlin scans ~5s and stops cleanly if it's absent — so no constant scanning /
|
||||
// drain when the strap isn't there) and polls; OFF stops the poll and disconnects.
|
||||
GPS.setHrOn = async function(on) {
|
||||
GPS.recording.hrOn = !!on;
|
||||
if (!on) {
|
||||
GPS._stopHrMonitor();
|
||||
try { await window.__TAURI__.core.invoke("ble_disconnect"); } catch {}
|
||||
return false;
|
||||
}
|
||||
const addr = await DB.getProfileValue("ble_device_addr");
|
||||
const type = await DB.getProfileValue("ble_device_type");
|
||||
if (!addr) { GPS.recording.hrOn = false; return false; }
|
||||
try {
|
||||
const bt = await window.__TAURI__.core.invoke("ble_check_bluetooth");
|
||||
if (bt === "off") { try { await window.__TAURI__.core.invoke("ble_request_enable"); } catch {} }
|
||||
else if (bt !== "no_adapter") { try { await window.__TAURI__.core.invoke("ble_connect", { address: addr, deviceType: type || "hr_standard" }); } catch {} }
|
||||
} catch {}
|
||||
try { await GPS._startHrMonitor(); } catch {}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Low-battery warning for the HR strap: announce (voice) and beep ONCE at 10% and 5%.
|
||||
// Resets when the strap reads healthy again (recharged / battery replaced).
|
||||
GPS._batAlerted = {};
|
||||
|
|
@ -1386,7 +1408,11 @@ GPS.startRecording = async function(activityType, weightKg, profile) {
|
|||
GPS.recording.sessionId = await DB.createGpsSession(
|
||||
new Date().toISOString().slice(0, 10), new Date().toTimeString().slice(0, 5), "workout");
|
||||
} catch (e) { console.error("[workout] createGpsSession failed:", e); }
|
||||
try { await GPS._startHrMonitor(); } catch (e) { console.error("[HR] start error:", e); }
|
||||
// Auto-connect the paired strap on start (workout = you want HR). Absent strap -> stops clean.
|
||||
try {
|
||||
const hrAddr = await DB.getProfileValue("ble_device_addr");
|
||||
if (hrAddr) await GPS.setHrOn(true); else GPS.recording.hrOn = false;
|
||||
} catch (e) { console.error("[HR] start error:", e); }
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1409,8 +1435,13 @@ GPS.startRecording = async function(activityType, weightKg, profile) {
|
|||
// Start native foreground service (Android)
|
||||
await GPS._startNativeService();
|
||||
|
||||
// Start BLE HR monitor (auto-connect to paired device)
|
||||
try { await GPS._startHrMonitor(); } catch (e) { console.error("[HR] start error:", e); }
|
||||
// HR: default ON if a strap is paired — auto-connect + poll at start (the record screen has an
|
||||
// on/off toggle). Safe: BleHrService scans briefly and stops if the strap isn't present, so no
|
||||
// constant scanning/drain when it's absent. No paired strap -> HR stays off.
|
||||
try {
|
||||
const hrAddr = await DB.getProfileValue("ble_device_addr");
|
||||
if (hrAddr) await GPS.setHrOn(true); else GPS.recording.hrOn = false;
|
||||
} catch (e) { console.error("[HR] start error:", e); }
|
||||
|
||||
// Poll native service output file
|
||||
if (GPS.recording.nativeService) {
|
||||
|
|
|
|||
|
|
@ -4578,7 +4578,7 @@ async function renderRecordingInline(container) {
|
|||
</div>
|
||||
<div class="rec-bottom">
|
||||
<div class="rec-status" id="rec-status">${GPS.recording.state === "waiting_gps" ? "Поиск GPS..." : GPS.recording.state === "ready" ? "Начните движение..." : ""}</div>
|
||||
<button id="rec-wind" class="btn-secondary"${GPS.recording._currentWind ? ' style="background:#ffb74d;color:#1a1a1a"' : ""}>Ветер</button>
|
||||
<button id="rec-hr-toggle" class="btn-secondary rec-hr-toggle${GPS.recording.hrOn ? " active" : ""}" title="Пульсометр вкл/выкл" aria-label="ЧСС"><svg viewBox="0 0 24 22" width="22" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20S3 14.5 3 8.3C3 5.6 5 4 7.2 4 9 4 10.6 5.1 12 7 13.4 5.1 15 4 16.8 4 19 4 21 5.6 21 8.3c0 1.3-.4 2.5-1 3.7"/><path d="M2 13h5l2-3 2.4 6 2-3H22"/></svg></button>
|
||||
<button id="rec-pause" class="btn-secondary">${GPS.recording.manualPaused ? "Продолжить" : "Пауза"}</button>
|
||||
<button id="rec-stop" class="btn-primary gps-rec recording">Стоп</button>
|
||||
</div>
|
||||
|
|
@ -5118,11 +5118,14 @@ async function renderRecordingInline(container) {
|
|||
|
||||
// Headwind label toggle: tap to open a "wind in the face" interval, tap to close.
|
||||
// Marks are ground truth for validating the from-track wind estimate — not kcal.
|
||||
let windBtn = container.querySelector("#rec-wind");
|
||||
if (windBtn) windBtn.onclick = () => {
|
||||
let active = GPS.toggleWindMark();
|
||||
windBtn.style.background = active ? "#ffb74d" : "";
|
||||
windBtn.style.color = active ? "#1a1a1a" : "";
|
||||
// HR on/off toggle (replaces the old "Ветер" button). ON connects the paired strap + polls;
|
||||
// OFF disconnects. Grey = off, coloured = on.
|
||||
let hrToggle = container.querySelector("#rec-hr-toggle");
|
||||
if (hrToggle) hrToggle.onclick = async () => {
|
||||
hrToggle.disabled = true;
|
||||
await GPS.setHrOn(!GPS.recording.hrOn);
|
||||
hrToggle.classList.toggle("active", !!GPS.recording.hrOn);
|
||||
hrToggle.disabled = false;
|
||||
};
|
||||
|
||||
// Pause button
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue