Hydration: water intake from the food log, drop the "+вода" button
Intake is what you already log (liquids count via water_pct), so there is nothing to tap mid-ride and no guessing an amount. At session start JS seeds the native deficit from the food log — need-so-far for the time of day minus logged intake — via set_hydration_config(start_deficit_ml); the service then accrues sweat on top. Removes the +вода button, hydration_drink and water_drink.txt.
This commit is contained in:
parent
6183f0c529
commit
9a8ef04230
10 changed files with 56 additions and 86 deletions
|
|
@ -507,20 +507,6 @@ async function deleteFoodEntry(id) {
|
|||
await execute("DELETE FROM food_log WHERE id = ?1", [id]);
|
||||
}
|
||||
|
||||
// Quick "+вода": log a plain-water drink so the daily water total/bar reflects it. Finds a
|
||||
// ~100% water product at runtime (no hardcoded id). The hydration deficit is handled separately
|
||||
// (Rust hydration_drink -> native service). Returns true if it could log to the daily total.
|
||||
async function logWaterDrink(ml) {
|
||||
const now = new Date();
|
||||
const date = now.toISOString().slice(0, 10);
|
||||
const time = now.toTimeString().slice(0, 5);
|
||||
const rows = await select("SELECT id FROM products WHERE water_pct >= 99 ORDER BY water_pct DESC LIMIT 1");
|
||||
if (!rows.length) return false;
|
||||
await addFoodEntry(date, time, rows[0].id, ml, "вода", null, null);
|
||||
return true;
|
||||
}
|
||||
window.DB.logWaterDrink = logWaterDrink;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Activity log
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -2783,6 +2783,26 @@ let gpsMap = null;
|
|||
let gpsTrailLine = null;
|
||||
let gpsMarker = null;
|
||||
|
||||
// At session start, seed the native hydration deficit from the FOOD LOG: how far behind on water
|
||||
// you are for the time of day (need-so-far minus logged intake). During the session the native
|
||||
// service adds sweat on top. Intake comes from what you log, not a button.
|
||||
async function seedHydrationDeficit() {
|
||||
if (localStorage.getItem("baldav_hydr_on") !== "1") return;
|
||||
try {
|
||||
let target = parseInt(state.profile?.daily_water_ml) || 2000;
|
||||
let now = new Date();
|
||||
let nowMin = now.getHours() * 60 + now.getMinutes();
|
||||
let wakeStart = 7 * 60, wakeEnd = 23 * 60; // assume waking 07:00–23:00
|
||||
let frac = Math.max(0, Math.min(1, (nowMin - wakeStart) / (wakeEnd - wakeStart)));
|
||||
let needSoFar = target * frac;
|
||||
let intake = await DB.getDailyWaterMl(now.toISOString().slice(0, 10));
|
||||
let startDeficit = Math.max(0, Math.min(5000, Math.round(needSoFar - intake)));
|
||||
let alertMl = parseInt(localStorage.getItem("baldav_hydr_alert")) || 600;
|
||||
await window.__TAURI__.core.invoke("set_hydration_config",
|
||||
{ enabled: true, alertMl, sweatMlPerHour: 600, reAlertMin: 15, startDeficitMl: startDeficit });
|
||||
} catch (e) { console.error("seedHydration", e); }
|
||||
}
|
||||
|
||||
async function renderGpsScreen(container) {
|
||||
// Check Bluetooth state if BLE device is paired
|
||||
let bleAddr = await DB.getProfileValue("ble_device_addr");
|
||||
|
|
@ -2897,6 +2917,7 @@ async function renderGpsScreen(container) {
|
|||
heightCm: parseFloat(state.profile?.height_cm) || 178,
|
||||
} : null;
|
||||
await GPS.startRecording(type, wkg, hrProfile);
|
||||
seedHydrationDeficit();
|
||||
renderScreen("recording");
|
||||
}
|
||||
};
|
||||
|
|
@ -4976,21 +4997,6 @@ async function renderRecordingInline(container) {
|
|||
darkBtn.onclick = () => toggleDarkMap();
|
||||
btnWrap.appendChild(darkBtn);
|
||||
|
||||
// +вода: записать выпитое — гасит отставание (сигнал гидратации замолкает) и идёт в дневной итог.
|
||||
let waterBtn = document.createElement("button");
|
||||
waterBtn.className = "rec-map-btn rec-water-btn";
|
||||
waterBtn.textContent = "💧";
|
||||
waterBtn.title = "Записать воду";
|
||||
waterBtn.onclick = async () => {
|
||||
let ml = parseInt(localStorage.getItem("baldav_hydr_drink")) || 500;
|
||||
try { await window.__TAURI__.core.invoke("hydration_drink", { ml }); } catch (e) { console.error("drink", e); }
|
||||
try { await DB.logWaterDrink(ml); } catch (e) { console.error("logWater", e); }
|
||||
showToast(`+${ml} мл воды`);
|
||||
waterBtn.classList.add("active");
|
||||
setTimeout(() => waterBtn.classList.remove("active"), 800);
|
||||
};
|
||||
btnWrap.appendChild(waterBtn);
|
||||
|
||||
// Nogo: mark the current spot impassable while riding (the planner + on-the-fly reroute
|
||||
// will avoid it). Shows existing nogo circles too.
|
||||
let recNogoLayer = null;
|
||||
|
|
@ -8203,9 +8209,8 @@ function showProfileModal() {
|
|||
<input id="m-hydr-on" type="checkbox" ${localStorage.getItem("baldav_hydr_on") === "1" ? "checked" : ""}>
|
||||
Следить за питьём на тренировке
|
||||
</label>
|
||||
<div style="font-size:11px;color:#9aa4ae;margin-top:2px">Во время заезда/VR копится потребность в воде (пот). Молчит, пока успеваешь пить; громкий сигнал (канал будильника, пробивает громкость) - только когда отстаёшь. Кнопка «+вода» на записи гасит отставание.</div>
|
||||
<div style="font-size:11px;color:#9aa4ae;margin-top:2px">Во время заезда/VR копится потребность в воде (пот), а выпитое берётся из того, что ты логируешь в баланс (жидкость по water_pct). Молчит, пока успеваешь пить; громкий сигнал (канал будильника, пробивает громкость) - только когда отстаёшь сверх порога.</div>
|
||||
<label style="font-size:13px;display:block;margin-top:4px">Сигнал при отставании, мл <input id="m-hydr-alert" type="number" inputmode="numeric" min="100" max="3000" value="${localStorage.getItem("baldav_hydr_alert") || "600"}" style="width:80px"></label>
|
||||
<label style="font-size:13px;display:block">«+вода» за нажатие, мл <input id="m-hydr-drink" type="number" inputmode="numeric" min="50" max="2000" value="${localStorage.getItem("baldav_hydr_drink") || "500"}" style="width:80px"></label>
|
||||
</div>`,
|
||||
async overlay => {
|
||||
let weight = parseFloat(overlay.querySelector("#m-weight").value) || null;
|
||||
|
|
@ -8225,11 +8230,9 @@ function showProfileModal() {
|
|||
await DB.setProfileValue("daily_water_ml", waterNorm);
|
||||
let hydrOn = !!overlay.querySelector("#m-hydr-on")?.checked;
|
||||
let hydrAlert = Math.min(3000, Math.max(100, parseInt(overlay.querySelector("#m-hydr-alert")?.value) || 600));
|
||||
let hydrDrink = Math.min(2000, Math.max(50, parseInt(overlay.querySelector("#m-hydr-drink")?.value) || 500));
|
||||
localStorage.setItem("baldav_hydr_on", hydrOn ? "1" : "0");
|
||||
localStorage.setItem("baldav_hydr_alert", String(hydrAlert));
|
||||
localStorage.setItem("baldav_hydr_drink", String(hydrDrink));
|
||||
try { await window.__TAURI__.core.invoke("set_hydration_config", { enabled: hydrOn, alertMl: hydrAlert, sweatMlPerHour: 600, reAlertMin: 15 }); } catch (e) { console.error("hydration cfg", e); }
|
||||
try { await window.__TAURI__.core.invoke("set_hydration_config", { enabled: hydrOn, alertMl: hydrAlert, sweatMlPerHour: 600, reAlertMin: 15, startDeficitMl: 0 }); } catch (e) { console.error("hydration cfg", e); }
|
||||
|
||||
state.profile = { ...state.profile,
|
||||
weight_kg: weight ? weight : state.profile.weight_kg,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue