Commit graph

189 commits

Author SHA1 Message Date
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
d6139a99f7 Docs: repeat-detection findings and interval backlog notes 2026-09-21 12:42:57 +03:00
db62d52650 Bump version to 0.1.464 (build.sh output) 2026-09-21 12:36:51 +03:00
15a2881c6d Split a track at a point; block merging tracks with different bikes 2026-09-21 12:36:03 +03:00
44bb08e81e Bump version to 0.1.463 (build.sh output) 2026-09-21 11:28:37 +03:00
ea462ad9c4 Repeat analysis: detect a segment ridden twice (minPasses 3 -> 2); count no longer blocks 2-rep sessions 2026-09-21 11:27:24 +03:00
c5386ae22b Bump version to 0.1.462 (build.sh output) 2026-09-18 00:09:14 +03:00
cfadad4690 Merge rides: long-press to multi-select tracks and combine them into one (reversible via orig_session_id) 2026-09-18 00:08:25 +03:00
4895cbb042 Bump version to 0.1.461 (build.sh output) 2026-09-17 23:49:12 +03:00
2ffaf1581d Repeat analysis: project onto the reference line (lateral drift no longer truncates a rep); pass time counts moving seconds only 2026-09-17 23:46:32 +03:00
de93f77c3a Bump version to 0.1.460 (build.sh output) 2026-09-17 23:20:37 +03:00
7d2581dc2d Repeat analysis: bridge a stop inside a pass, count 70%+ passes (dropped-seat rep now counts) 2026-09-17 23:17:47 +03:00
1a57f36621 Bump version to 0.1.459 (build.sh output) 2026-09-17 22:51:10 +03:00
0d8b5f97b9 Repeat analysis: pick the longest corridor traversal as reference (fix short segment) 2026-09-17 22:50:24 +03:00
b2defb4564 Bump version to 0.1.458 (build.sh output) 2026-09-17 22:12:18 +03:00
7717a73129 Repeat/interval analysis: auto-find repeated segments in one ride, table + last/first verdict 2026-09-17 22:11:10 +03:00
6dfe262801 Docs: ridden-roads router, share field selection, segments accordion 2026-09-14 13:44:09 +03:00
d79a9f217a Bump version to 0.1.457 (build.sh output) 2026-09-14 13:28:11 +03:00
4f31088af9 Track detail: fold the segment list into an accordion so action buttons stay reachable 2026-09-14 13:27:29 +03:00
0be980849c Bump version to 0.1.456 (build.sh output) 2026-09-14 13:08:17 +03:00
d9a3254ffb Share image: pick which fields go on the picture (remembered), add max speed 2026-09-14 13:07:32 +03:00
999361a2e9 Bump version to 0.1.455 (build.sh output) 2026-09-14 12:58:33 +03:00
eb2aab3e6b Share modal joins the window stack so back closes it, not the screens behind 2026-09-14 12:57:52 +03:00
a2cc150298 Bump version to 0.1.454 (build.sh output) 2026-09-14 12:47:04 +03:00
a30c742bc6 Ridden-roads-preferred router: plan over your own tracks first
Planner now tries a route over roads you have actually ridden before
falling back to BRouter public data:
- Rust get_ride_graph(min_speed): nodes snapped to ~20m grid (walk=1
  points excluded), edges between consecutive same-session points with
  weight = node-to-node distance (consecutive-point distance loses
  intra-cell travel and makes Dijkstra underestimate).
- JS loadRideGraph cache, grid-indexed nearest-node, Dijkstra, rideRoute
  (snap <=60m, drop if >2.5x straight line).
- routeDirty: rideRoute first, BRouter(+nogos) in the gaps. Ridden leg
  has no elevation -> thin line; BRouter -> casing (visually distinct).
- formatDistance now rounds metres (was 966.145...m).
2026-09-14 12:35:39 +03:00
c564c419db Walk detection in rides: colour it, keep it out of the ridden roads
Stage B of the ridden-roads work. GPS.detectWalk() flags contiguous low-speed
runs (< walkDetectKmh, or the single-speed 30-rpm push speed, for >= walkMinRunSec)
as walking inside a bike/other ride. Persisted per point (gps_points.walk, via
DB.setWalkFlags in recalculateSession + recomputeAllStats). rebuild_roads maps a
walk point to atype 'walk' so it colours as walking and is not treated as a
rideable road. Track detail colours walk runs and shows 'пешком: N мин / X км'.
Verified detectWalk on real tracks: 98% on a mostly-pushed 4km ride vs 1% on a
normal 16km ride.
2026-09-14 12:14:04 +03:00
abdcb94f55 Bump version to 0.1.453 (build.sh output) 2026-09-14 11:53:11 +03:00
5fe30399ab Share image Stage 2: native save/share + settings background picker
Rust export_image(filename,base64,action) + read_file_base64(path) (registered).
Kotlin exportimg: branch — base64-decode, then SAF-save the PNG (CreateDocument
image/png) or share it via FileProvider + ACTION_SEND chooser. Settings gets a
'Фон для картинки' row: pick a photo (pickLocalFile image/*), read it as base64,
downscale to <=1080 and store as a data URL in localStorage for the 'С фото'
variant. Rust compiles in tauri dev; native paths need an APK rebuild to test.
2026-09-14 10:38:29 +03:00
69f6fdac18 Share image (Похвастаться): render + preview modal + detail button
Stage 1 (pure JS). buildShareImage() draws a 9:16 story PNG: track shape (colored
glowing line), big Distance/Time/Speed + small elevation/kcal/date, on a
transparent or photo background. showShareModal() previews it with a
transparent/photo toggle and Share/Save buttons; a 'Похвастаться' button in the
track detail opens it. Native export (SAF save + share intent) and the settings
background picker come in Stage 2 (needs an APK rebuild); on desktop the export
buttons toast an error.
2026-09-14 10:25:34 +03:00
7bb764d2ca Bump version to 0.1.452 (build.sh output) 2026-09-12 23:15:52 +03:00
e40f6e25b7 Reroute: rejoin the active route past a blockage from the current position
Stage 2. Recording-map button ↪ builds a detour from the current GPS position
back ONTO the active route past the blockage: reference = nearest nogo on the
route (else current pos), target = a route point ~1.5km further (steps further on
failure to the route end), avoiding nogos and 180° turns (bearing helper). Drawn
as a transient magenta navigation overlay with the rejoin point; long-press the
button clears it. Does not modify the saved route or interrupt recording.
2026-09-12 23:05:58 +03:00
1c326ab19c Nogo areas: routing avoids impassable spots (planner + engine + RouteServer)
Stage 1 of the nogo/reroute work. Mark impassable circles that BRouter routes
around, end to end:
- DB nogo_areas table + CRUD; drawNogoAreas() red circles (tap to remove).
- BRouter.route(points, profile, nogos): &nogos=lon,lat,r on the RouteServer and
  nogos in the embedded-engine request; Rust brouter_route passes it through;
  Kotlin builds OsmNodeNamed(radius,isNogo,nogoWeight=NaN) -> rc.nogopoints +
  prepareNogoPoints (needs an APK rebuild for offline use).
- Planner: ⛔ button toggles nogo-placement (tap map/line), each leg re-routes
  around nogos. Recording map: ⛔ marks the current spot impassable. Detail map
  shows the circles.
Verified the RouteServer detours around a nogo (2873m -> 3329m).
2026-09-12 22:55:51 +03:00
5a80469bba Bump version to 0.1.451 (build.sh output) 2026-09-11 01:30:52 +03:00
aa7022ec6b routes: return a reliable id from addRoute (re-read, not lastInsertId)
Found in desktop testing: saving a built route showed 'Маршрут пуст' and dropped
to the list — addRoute returned the INSERT lastInsertId, an i64 the SQL plugin
corrupts by ±1, so showRouteDetail opened a non-existent id. Re-read the id via
CAST(id AS TEXT) (same guard importGpxSession uses). Session log: desktop
verification of all 6 fixes.
2026-09-11 01:25:28 +03:00
e45c92f09a Route editor + gap-fill: 6 fixes (casing/slope, controls, tap-insert, waypoints, precise fill)
- Editor shows the route with casing + slope/elevation colouring like the detail
  view (drawRoutePolyline over the routed geometry); day/night, slope/elev and
  locate controls added. Root cause of the plain thin line: ele was dropped when
  building leg geometry — now kept from BRouter, so casing/slope work here and in
  showRouteDetail. Straight legs (no ele) stay a thin line.
- Insert a point is now a TAP on the line (fat invisible hit target,
  pointer-events:stroke); long-press toggles road/straight.
- Routes store editable waypoints (routes.waypoints_json {waypoints,legMode})
  alongside the dense geometry, so re-editing shows the 5-6 points, not thousands.
- Bottom bar reworked (.re-bottom): hint on top, buttons in a row, cancel below.
- Gap-fill is conservative: only real long dropouts (dt>60s, chord>150m), skips
  big detours (>2x chord) and no-gain fills (road ~ straight).
2026-09-11 01:06:06 +03:00
80e35aa096 Bump version to 0.1.450 (build.sh output) 2026-09-10 16:23:14 +03:00
ceee0a48eb gap-fill: reload detail via reopenDetail (in-place), not a stacked screen
Found in desktop testing: showSessionDetail() from the save/revert handlers
pushed a second detail overlay whose map rendered blank. reopenDetail() collapses
the stack and re-renders in place (the pattern recalc/refine already use). Session
log updated with the desktop verification results.
2026-09-10 15:51:34 +03:00
cfe0212bbc BRouter UX: gap-fill preview+reversible save; per-segment route planner
Gap-fill (track detail): GPS.fillGaps now returns {points,gaps} with per-gap
status; the 🧩 control previews ONLY the filled dropouts (cyan casing; unfilled
= red dashed) with a Save/Cancel panel. Save is a reversible in-place patch
(estimated points added, original untouched; DB.saveGapFill/revertGapFill +
estimated/gap_filled columns), then recalculateSession. Revert removes them.

Route planner: renamed menu 'Нарисовать маршрут' → 'Нарисовать тренировку'
(it makes a workout session, not a route); routes empty-state now points at the
on-phone planner. showRouteEditor rewritten per-leg: each leg road (BRouter) or
straight independently, road by default, tap a leg to toggle it, long-press to
insert, silent straight fallback where no road; the global button sets all legs.
2026-09-10 15:26:05 +03:00
2551394cd3 Bump version to 0.1.449 (build.sh output) 2026-09-10 00:55:45 +03:00
99cd4c8d30 Scrub location/identity: home city name and external mirror IP → placeholders
Remove the home-city name from docs/comments/UI strings and the external
mirror IP (WAN) from code, docs and the Android cleartext allowlist, replacing
the IP with mirror.invalid (set the real host locally, uncommitted). LAN mirror
and routing keep working; the WAN fallback needs the real host set. Generic
big-city map presets are kept (not identifying).
2026-09-10 00:55:45 +03:00
d504315229 brouter-web: white+black casing under the slope-colored route
leaflet-hotline has a single outlineColor, so render the colored core thin
(outlineWidth 0) and add two plain polylines beneath it in a dedicated pane
just under the hotline pane: a wide black one and a narrower white one — black
rim, white rim, colored core, legible on any map background. Map captured via
L.Map addInitHook to build the casing pane.
2026-09-10 00:17:42 +03:00
5fce4197a3 brouter-web: hover box above the route; color route by slope (BalDav palette)
- .height-focus.label (on-map hover box) lifted 42px so it no longer covers
  the route line.
- Repoint the 'Route quality' overlay's incline provider from signed incline
  (degrees, blue->green->red) to |grade %| with BalDav's discrete bands
  (green->yellow->red->brown->black, >=10% black), via addInitHook before the
  control is built; best-effort auto-enable the overlay.
2026-09-09 21:31:40 +03:00
f3b0710790 brouter-web: readable elevation hover tooltip in dark theme
The .focusbox tooltip rect stayed white and our .elevation text rule turned
its text light — light-on-light, unreadable on the dark chart. Give the box a
dark ground with light text (same for the on-line height label), and lighten
the near-black guide lines/markers so they show on the dark chart.
2026-09-09 21:17:21 +03:00
9fc7cd5a49 Bump version to 0.1.448 (build.sh output) 2026-09-09 20:30:08 +03:00
60dd364a9f gitignore: build output (binaries/, test.exe) and local PDFs 2026-09-09 20:30:08 +03:00
1546e947e7 BRouter: fix routed-line re-route loop; verify planning + gap-fill on desktop
doBrouter() ended with changed(), which nulled routeGeom and re-queued
doBrouter — an endless re-route loop where the road line was never drawn
(editor kept the straight line, distance unchanged). Draw directly instead
(updatePolyline/updateStats).

Verified end-to-end in the UI on a virtual display (Xvfb) against the
RouteServer: editor 'По дорогам' turns a 1.69km straight line into a 2.25km
road-following route; the gap-fill '🧩' overlay draws a shortest-road cyan
dashed line across a track's GPS dropouts. Docs (README/PROJECT_MAP/plan/log)
updated to match; router.js/poi.js now listed in PROJECT_MAP.
2026-09-09 18:18:35 +03:00
cd98078682 BRouter: gap-fill along roads + release hardening
Stage 4 — gap fill: GPS.fillGaps(points) routes each GPS dropout (dt>gap
threshold, chord>60m) with the shortest road path and splices the routed points
in (flagged estimated), falling back to the chord when the road is >3x the chord
(graph detoured). A 🧩 button on the track detail draws the road-filled path as
a cyan dashed overlay — non-destructive (stats recompute over filled points is a
follow-up). Also fixes doBrouter: parseRouteGPX returns {name,points}, not an
array (planning would have kept the straight line).

Release hardening: network_security_config.xml permits cleartext only to the
mirror/RouteServer hosts (base off, debug-overrides on) — wired via
android:networkSecurityConfig; proguard keeps btools.** so release minification
doesn't strip the embedded engine.
2026-09-09 17:43:56 +03:00
8e720ecd17 BRouter: offline route planning by waypoints + segment download UI
Stage 3 — planning: showRouteEditor gets a "🚲 По дорогам" toggle. Waypoints
stay editable markers; with it on, the line between them (and the saved
geometry) follows roads via BRouter (brouterMode/routeGeom, 450ms debounce on
edits). BRouter.route (router.js) now: Android -> embedded engine, otherwise
(desktop / at home) -> the PC RouteServer over HTTP (http_request bypasses the
WebView CSP; LAN 192.168.1.18:17777 / WAN mirror.invalid:17777). Lets planning be
debugged on the desktop.

Stage 2 — segment UI: a "Сегменты" button on the roads screen opens
showBrouterSegments — region tiles (E35_N45/E40_N45), "есть" status, a
Download/Update button with percent progress via BRouter.downloadTileAndWait.

Verified: RouteServer returns 83 trkpt for a 3-waypoint trekking route (3594 m),
parseRouteGPX reads trkpt; both files compile into the apk. End-to-end UI (tap
waypoints -> routed line; in-app segment download) pending desktop/phone run.
2026-09-09 17:33:11 +03:00