GPS altitude: accel-based glitch filter (accel=0 + speed = GPS drift), altitude jump >100m filter, timestamp sanity (>24h = remove). Per-point Crr from accel vibration (smooth/mixed/gravel). Gap interpolation on map with dashed lines when accel confirms movement. Walk/run separate speed limits (configurable). Adaptive GPS accuracy (auto x2 when signal bad). Dead reckoning points when GPS silent but accel shows movement. Locale.US fix for sensor JSON. Sensors: accelerometer + gyroscope in GpsRecorderService (RMS, max, pitch, yaw). Columns in gps_points. Dynamic addGpsPoint INSERT (safe if columns missing). Manual routes: draw on map by tapping points, elevation from past tracks + open-meteo API, realistic timestamps by activity speed. Manual sessions skip glitch filtering on recalculate. Speed from GPS.config not hardcoded. Water tracking: water_pct field in product add/edit forms, searchProducts returns water_pct, "ml" label for liquids, recipe water from ingredients. BMR: moving average weight (7 days), fixed charts using dailyBase not raw bmr. BLE: ble_clear_hr on stop, recovery toast, serde alias for ts/timestamp. Products: 217 Gridnev products (bakery, desserts, bread, ready meals). Magnit scraper fix (NUXT_DATA name/value pairs, not indices). Supplements addSupplement with all 41 columns. Nutrient fallback RDI includes omega/EPA/DHA. Export/import: custom products + recipes + supplements in single JSON bundle. Export all or single product. Dedup on import by name_lower + source. OTA: router upload (LAN, always), VPS upload (-u flag). Kotlin checks router first (2s timeout), then VPS. Update URL from update_info.json. Session detail: renderToken prevents stale setTimeout callbacks after recalculate. WAL disabled (PRAGMA journal_mode=DELETE).
71 lines
2.6 KiB
JavaScript
71 lines
2.6 KiB
JavaScript
// Mifflin-St Jeor BMR formula.
|
|
// Males: BMR = 10*weight + 6.25*height - 5*age - 5
|
|
// Females: BMR = 10*weight + 6.25*height - 5*age + 161
|
|
|
|
function calculateBmr(weightKg, heightCm, age, sex) {
|
|
const base = 10 * weightKg + 6.25 * heightCm - 5 * age;
|
|
return Math.round(sex === "m" ? base - 5 : base + 161);
|
|
}
|
|
|
|
function getAge(birthYear) {
|
|
return new Date().getFullYear() - birthYear;
|
|
}
|
|
|
|
// RDI loaded from DB (rdi_standards + rdi_values tables).
|
|
// Fallback hardcoded RU values used until DB is ready.
|
|
let RDI_TYPES = {}; // { nutrient_key: "rdi" | "aup" }
|
|
let RDI = {
|
|
vit_a_mcg: 800, vit_c_mg: 60, vit_e_mg: 10, vit_b1_mg: 1.4, vit_b2_mg: 1.6,
|
|
vit_b3_mg: 18, vit_b5_mg: 6, vit_b6_mg: 2, vit_b7_mcg: 50, folate_mcg: 200,
|
|
vit_b12_mcg: 1, vit_d_mcg: 5, vit_k_mcg: 120, calcium_mg: 1000, magnesium_mg: 400,
|
|
zinc_mg: 15, iron_mg: 14, iodine_mg: 0.15, selenium_mcg: 70, molybdenum_mcg: 70,
|
|
manganese_mg: 2, copper_mg: 1, chromium_mg: 0.05, phosphorus_mg: 800,
|
|
potassium_mg: 3500, sodium_mg: 2400,
|
|
omega3_mg: 1000, epa_mg: 250, dha_mg: 250,
|
|
lutein_mg: 5, lycopene_mg: 5, silicon_mg: 30, vanadium_mg: 0.04,
|
|
};
|
|
|
|
// Load RDI from DB for selected standard. Called after DB ready.
|
|
async function loadRDI(standardCode) {
|
|
try {
|
|
const std = await window.__TAURI__.core.invoke("plugin:sql|select", {
|
|
db: "sqlite:baldav.db",
|
|
query: "SELECT id FROM rdi_standards WHERE code = ?1",
|
|
values: [standardCode || "RU"],
|
|
});
|
|
if (!std.length) return;
|
|
const vals = await window.__TAURI__.core.invoke("plugin:sql|select", {
|
|
db: "sqlite:baldav.db",
|
|
query: "SELECT nutrient_key, value, norm_type FROM rdi_values WHERE standard_id = ?1",
|
|
values: [std[0].id],
|
|
});
|
|
const loaded = {};
|
|
RDI_TYPES = {};
|
|
for (const v of vals) {
|
|
loaded[v.nutrient_key] = v.value;
|
|
RDI_TYPES[v.nutrient_key] = v.norm_type || "rdi";
|
|
}
|
|
if (Object.keys(loaded).length > 0) RDI = loaded;
|
|
} catch (e) { console.error("[BMR] loadRDI error:", e); }
|
|
}
|
|
|
|
// Nutrient half-life data loaded from DB
|
|
let HALFLIFE = {}; // { nutrient_key: halflife_avg_days }
|
|
|
|
async function loadHalflife() {
|
|
try {
|
|
const rows = await window.__TAURI__.core.invoke("plugin:sql|select", {
|
|
db: "sqlite:baldav.db",
|
|
query: "SELECT nutrient_key, halflife_avg_days FROM nutrient_halflife",
|
|
values: [],
|
|
});
|
|
HALFLIFE = {};
|
|
for (const r of rows) HALFLIFE[r.nutrient_key] = r.halflife_avg_days;
|
|
} catch (e) { console.error("[BMR] loadHalflife error:", e); }
|
|
}
|
|
|
|
window.BMR = { calculateBmr, getAge, loadRDI, loadHalflife,
|
|
get RDI() { return RDI; },
|
|
get RDI_TYPES() { return RDI_TYPES; },
|
|
get HALFLIFE() { return HALFLIFE; },
|
|
};
|