Commit graph

236 commits

Author SHA1 Message Date
802b2cc6e9 Bump version (build.sh output) 2026-10-19 14:12:04 +03:00
eeca9a7d94 HR connect: one BT-enable prompt per start, only on user action
setHrOn gains an 'interactive' flag; it pops the OS enable-Bluetooth dialog
only on a user tap (record-screen toggle). Auto-calls at recording start no
longer re-request enable after the single ensureSystemReady prompt, so a
decline is not immediately followed by the system dialog and is not re-asked
until the next start.
2026-10-19 13:43:55 +03:00
13c61f506a BleHrService: survive Bluetooth being turned off (no native crash)
Single Handler for all postDelayed work, cancelled on teardown; a BT
ACTION_STATE_CHANGED receiver that cleanly stops the service on STATE_OFF;
try/catch around every native scan/connect/GATT call. Prevents the libc
destroyed-mutex abort when the adapter is disabled mid-connection.
2026-10-19 13:43:55 +03:00
1df24000a3 Track detail: HR chart as its own collapsible section + 'what if by HR' kcal comparison
- Speed/Elevation/Пульс are now collapsible <details> sections; the HR chart
  moved out of the Elevation block into its own 'Пульс' section (avg/max + chart),
  shown when the track has HR.
- Калории now also shows the Keytel HR-based kcal as a COMPARISON when HR is
  present ('По ЧСС (сравнение)'). The activity balance keeps the physics/MET
  number unchanged - this is only to see the difference.
2026-10-17 14:53:21 +03:00
87a7fccfcc Record screen: remove the status line + its black bar, tighten button padding, move ⛔/↪ off the zoom controls
- Drop the status line (and any text it showed) from the record screen; keep
  a no-op statusEl sink so existing writes don't crash. Removes the empty
  black bar above the buttons. Tighter .rec-bottom padding.
- The nogo (⛔) and reroute (↪) buttons had no position class, so they piled
  at the map top-left over the zoom controls. Give them stack slots.
2026-10-17 14:43:57 +03:00
69b36be591 Record buttons equal width (border-box + uniform padding); HR strap charge as a background fill on the HR toggle
- Стоп was narrower: buttons had different horizontal padding and weren't
  border-box, so flex-basis:0 didn't equalize them. Force box-sizing + one
  padding on all three .rec-bottom buttons.
- HR strap battery now paints the HR toggle's background bottom-up 0-100%
  (--bat), coloured green/amber/red by level (setHrBatteryFill), instead of
  a number; cleared when HR is toggled off.
2026-10-17 14:35:54 +03:00
e88c2756f7 Record screen: big digits in the top strip (match bottom), drop the black status-bar backdrop band and the extra control offset
Top strip time/temp/clock now use the same 27px bold as the bottom stats. The
old .rec-map-wrap::before status-bar backdrop (and the leaflet-top safe-area
margin) are gone - the top strip already backs the status bar, so that strip
showed as a black band between the bar and the map.
2026-10-17 14:30:42 +03:00
dffadf3cd8 Record screen: regroup stats (top strip time/temp/clock, bottom HR/dist/speed/alt), equal-width buttons; reset stale HR per session
1) Layout: a top strip shows training time | temperature | clock ('external'
   things); the bottom panel row is now HR, distance, speed, altitude (bigger);
   the separate HR bar is gone; the three controls (HR toggle, pause, stop)
   share the width equally instead of clustering right.
2) Clear currentHr/currentBleData at recording start (+ ble_clear_hr) so a
   stale bpm from the previous session no longer hangs on the display or gets
   written onto this session's points; show -- until a fresh reading.
2026-10-17 12:29:14 +03:00
0a4ffcb49d HR toggle: white icon+bpm on solid red when active (contrast)
Active state was red text on faint-red; use white on solid red.
2026-10-17 10:59:31 +03:00
553a4fcf80 Record screen: show the live HR number on the HR toggle button
The HR toggle (ex-wind button) showed only the heart+pulse icon. Now the
current bpm renders on it (onHrUpdate writes #rec-hr-num); it clears when HR
is toggled off, leaving just the grey icon.
2026-10-17 10:57:08 +03:00
2d0e51bd8d Prompt to enable Bluetooth/location at recording start + two 'don't ask' settings
User forgets to turn BT/GPS on. Modern Android won't let an app toggle them
silently, so prompt and act: BT via the system enable dialog, location via
the location-settings screen.

- ensureSystemReady(needBt, needGps) runs before startRecording: BT off ->
  confirm -> ble_request_enable; location off -> confirm -> open settings.
  Gated by two settings (baldav_dontask_bt / _gps); declining proceeds.
- GPS.isLocationEnabled polls a new Kotlin check (check_location writes
  location_state.json via LocationManager; read_state_file reads it);
  open_location_settings opens ACTION_LOCATION_SOURCE_SETTINGS.
- Settings: 'Не спрашивать про Bluetooth' / '... геолокацию' checkboxes.
2026-10-17 02:07:44 +03:00
f7ba059628 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.)
2026-10-17 01:45:02 +03:00
62434d6155 HR strap battery + low-charge voice/beep alerts at 10% and 5%
- BleHrService reads the standard Battery service (0x180F/0x2A19) 2.5s after
  the HR subscribe and every 60s; writes 'bat' into ble_hr_data.json.
- HrReading gains battery: Option<u8> (serde alias 'bat').
- gps.js: the HR poll captures reading.battery; _checkBatteryAlert speaks
  (speechSynthesis ru-RU) and beeps once at 10% and 5% (beep is the
  guaranteed cue where TTS is absent), resetting above 15%.
- Workout screen shows the strap charge in its status line.
2026-10-17 00:58:31 +03:00
f704498d11 Workout mode: HR-only recording (зарядка) without GPS
New 'Зарядка' activity type records a session with no GPS - no location
service, no watchPosition, no track points - just the heart-rate poll and a
timer, for indoor exercise. kcal comes from HR (Keytel gross minus BMR, net
like the rest of the app) and counts in the daily balance.

- gps.js: GPS.hrKcalNet; startRecording/stopRecording 'workout' branches;
  the HR poll appends [relSec,bpm] samples.
- db.js: gps_sessions.hr_samples column + setSessionHrSamples.
- main.js: 'Зарядка (пульс)' option; renderWorkoutInline (map-less live
  screen: big HR, timer, kcal, connect-sensor button); renderWorkoutDetail
  (HR chart by zones, load, avg/max).
- tools/hr_log.py: background HR logger (standard 0x180D, no pairing).

Sensor read from the desktop confirmed on a Coospo H808S (F7:72:74:A4:FB:07,
~1 Hz) without pairing.
2026-10-17 00:54:21 +03:00
dd1642b6e9 BLE HR: connect manually only, no auto-scan on every ride (battery)
Recording auto-called ble_connect each ride, and the Kotlin service held a
GATT connect to an absent band (radio busy) plus START_STICKY churn -
draining the battery when the band was away or Bluetooth off.

- gps.js _startHrMonitor: drop the auto ble_connect; keep only the cheap HR
  poll so a manual connect (now or mid-ride) lands HR in the track.
- Settings: a 'Подключить' button for the paired band, usable any time incl.
  during a ride. BT off -> ble_request_enable (system enable dialog); on ->
  ble_connect, start the poll if recording, report connected / not found.
- ble.rs: ble_request_enable command (+ handler registration).
- MainActivity: ble_request_enable -> ACTION_REQUEST_ENABLE (BLUETOOTH_CONNECT
  already in manifest).
- BleHrService: START_NOT_STICKY; if the 5s scan doesn't find the address,
  stopSelf instead of directConnect to an absent device.
2026-10-02 14:03:16 +03:00
93908e3365 Gap-fill: bridge dropouts over your own ridden roads first, public BRouter only as fallback
fillGaps used the public BRouter shortest only, so a dropout where you rode
a trail/track absent from OSM was left unbridged (detour >2x or noroute),
even though your own track went straight through. Add opts.routeFn: the
detail view now tries rideRoute (the ride-graph over your tracks) first and
falls back to public BRouter only where you've never ridden. A ridden bridge
is trusted as-is (no detour-too-long rejection); public routing keeps that
guard. Clearer 'not bridged' message split by reason (public detour vs no
road data).
2026-09-30 00:23:28 +03:00
3e2a6e47f7 Progress on recompute/refine/roads-rebuild + remember map zoom
- .btn-progress fills a button's bg by --pct (setBtnProgress). Elevation
  refine drives it from fetchElevations network batches (0-80%) then save
  (85-100%); recompute from recalculateSession phase milestones; roads
  rebuild from a new Rust roads_progress event (rebuild_roads emits
  [current,total] every ~2000 points - first Rust->JS event in the app,
  adds use tauri::Emitter) so it no longer just hangs silently.
- recalc/refine now reopen the detail via reopenDetail (awaits the
  popstate) instead of the manual pop+history.back+render race.
- Track detail remembers its map view per session (_sdMapView, moveend) and
  restores it on reopen/return instead of re-fitting the whole track; the
  recording map persists its zoom in localStorage across screen switches.
2026-09-29 23:19:37 +03:00
fd178ad97d Track detail: await history.go popstates before re-render after gap-fill revert/save
reopenDetail fired history.go(-count) then re-rendered synchronously, so the
async map/chart build raced the popstate unwind: the pending popstates
desynced the back stack and bumped the detail render token, and the render
bailed at the token check - map and charts came up blank until the next
event repainted them. Make reopenDetail async and await the popstate(s)
before showSessionDetail, the same resolve-on-popstate pattern as closeThen
(no setTimeout/setInterval).
2026-09-29 16:03:52 +03:00
06cc77fdec Maps: trim tile retention, simplify big tracks by zoom, thin POIs when zoomed out
Canvas (prev commit) made the big-track map self-recover but the Chromium
compositor still hit 'tile memory limits exceeded' ~46x and 10k segments
still janked. Three cheap levers:
- tilecache: keepBuffer 2->1 and updateWhenZooming:false - fewer retained
  off-screen tiles in the compositor's raster budget on a high-DPI screen.
- track/roads polylines: smoothFactor 2.5 (Douglas-Peucker in pixels) - a
  10k-point track draws far fewer segments zoomed out, full detail zoomed in.
- POI: cap markers by zoom (z>=16:500, 15:200, 14:80, 13:30) instead of a
  flat 500 - a handful near min-zoom, everything only when zoomed in close.
2026-09-29 15:49:02 +03:00
834204a58a Maps: canvas renderer for heavy-vector maps (SVG blew Chromium tile memory, tiles vanished)
Viewing a big track (10865-pt, 60km) and zooming/panning threw
'cc/tiles/tile_manager tile memory limits exceeded, some content may not
draw' dozens of times - Chromium's compositor tile-memory cap. The track
is drawn by Leaflet's default SVG renderer, multi-layered (casing/core +
per-1%-slope segments), so the giant SVG layer exceeds the raster budget
and the map tiles stop drawing until a force-stop resets the compositor.

Set preferCanvas:true on the heavy-vector view maps - showSessionDetail,
showRoadsMap (many road polylines, also reported laggy), showComparisonView,
showRouteDetail. Canvas draws into one viewport-bounded canvas instead of
thousands of SVG paths. Left the recording map on SVG (rotate:true;
leaflet-rotate barely supports Canvas) and the route editor (line clicks).
2026-09-29 13:20:53 +03:00
74f3ec4d6e Startup: batch the seq repair (per-point loop made cold start ~15s, every boot)
The startup seq repair (runMigrations) assigned seq to NULL-seq sessions
one UPDATE per point. Merge/split leave seq=NULL by design, so recent
merged tracks (10865 + 3614 points) meant ~15000 sequential IPC writes on
every launch - and for the big sessions the writes did not persist before
the next launch re-ran the whole thing. That was the slow start.

Replace it with the batched CASE re-sequence (chunks of 300, like
saveGapFill/saveSmoothedTrack): ~50 UPDATEs instead of ~15000. Verified on
device: repair of all 3 sessions dropped from ~15s to ~1.1s, seq now
persists so it is one-time (boot 2 does no repair, migrations 357ms), 0
NULL seq left, seq matches ts order (0 inversions).
2026-09-29 12:37:15 +03:00
2d91c06290 gitignore build.sh (holds deploy secret) and BUILD_NUMBER (local state) 2026-09-29 12:19:15 +03:00
dbb6c2ea9f Build: auto-clean stale Android bundles per build + clean target
Each android build now removes the regenerable AAB bundles
(intermediary_bundle, outputs/bundle) and gen APK copies once the final
APK is in binaries/; a manual 'clean' target does the same on demand.
Frees ~0.5G/cycle without touching the Rust incremental cache or
binaries/. (build.sh stays untracked - it holds a deploy secret; this
documents the change.)
2026-09-27 00:04:52 +03:00
0123d3562b Bump version (build.sh output) 2026-09-27 00:04:52 +03:00
d6fe47a924 Recording map: follow toggle to free-pan while riding
New ⊕ button on the recording screen toggles map auto-follow. When off,
the map stays put so you can look around when unsure where you are (off
the track, or the track leads where there is no road); new GPS points no
longer recentre it. Tapping it back on recentres on the current position
and resumes following. Default on per screen entry (not persisted).

Guards followMode around panTo/setView in onPoint/onBatchUpdate/
onStateChange. Independent of the compass freeze/rotate controls.
2026-09-26 23:44:18 +03:00
5da02c598a Docs: versions table to build 474 (deployed to router + VPS) 2026-09-22 22:11:38 +03:00
749064ce59 Bump version (build.sh output) 2026-09-22 21:09:13 +03:00
5f58eabcc5 Gap-fill: re-sequence the session by ts on save (filled points landed at the front on merged/split tracks with NULL seq) 2026-09-22 20:58:06 +03:00
514ff4edb3 Docs: versions table to build 473 (deployed to router + VPS) 2026-09-22 11:49:48 +03:00
862b1ffc96 Bump version (build.sh output) 2026-09-22 11:32:19 +03:00
5d24f8c3a3 Keep scroll position across same-screen re-renders (day nav, add food) instead of jumping to top 2026-09-22 11:31:37 +03:00
bb9f03131d Bump version (build.sh output) 2026-09-22 11:19:37 +03:00
dff9342c0d Balance/trend/charts follow the selected day; kcal weight is per-ride (stored) and settings weight auto-syncs to the latest weigh-in 2026-09-22 11:12:24 +03:00
6534d6601c Docs: bump versions table to build 471 (deployed to router + VPS) 2026-09-21 20:40:49 +03:00
3ba8751664 Bump version (build.sh output) 2026-09-21 20:31:34 +03:00
685151b76b Repeat analysis: sweep the hot-cell threshold and keep the most passes (out-and-back reps were lost when a twice-ridden approach inflated the reference) 2026-09-21 20:30:38 +03:00
c84767fc9e Today: 7-day balance trend really covers 7 days (-7 days is an 8-day inclusive range) 2026-09-21 20:11:10 +03:00
b379160ff5 Bump version (build.sh output) 2026-09-21 13:49:27 +03:00
c913cc530c DB restore: drop unreliable auto-restart, ask user to reopen the app (reliable, restore applies on next launch) 2026-09-21 13:48:47 +03:00
ea7c6e68a8 Bump version (build.sh output) 2026-09-21 13:45:36 +03:00
492c54990f DB restore: restart via AlarmManager (startActivity+exit raced, app just closed) 2026-09-21 13:44:54 +03:00
ae90b4368b Bump version (build.sh output) 2026-09-21 13:36:43 +03:00
9e0910a35f DB backup: drop data_dir writes, use native_root only (match gps_service_read_points pattern) 2026-09-21 13:36:17 +03:00
d4faed200d Bump version to 0.1.467 (build.sh output) 2026-09-21 13:22:50 +03:00
d0abb72aba DB backup: use native_root() for the app root (not app_data_dir parent chain) - the fix we already made for point files 2026-09-21 13:22:05 +03:00
5b3239258f Bump version to 0.1.466 (build.sh output) 2026-09-21 13:20:10 +03:00
bb8a739b7e DB backup: write export/staging next to baldav.db (app_data_dir can be the app root; ../.. hit unwritable /data/user) 2026-09-21 13:19:18 +03:00
263163cf52 Bump version to 0.1.465 (build.sh output) 2026-09-21 13:05:34 +03:00
682bee6e9a Full DB backup: export all data to a file and restore it (swap DB on next launch) 2026-09-21 13:03:32 +03:00
75eca0e501 Docs: current versions table in README; note router deploy of build 464 2026-09-21 12:43:49 +03:00