GPS stop: import only the un-polled tail, not a full file re-scan

The old stop path re-added every native point "not already in the DB",
which raw-inserted points the live poll had intentionally dropped
(stationary / auto-pause / wrong state) with scrambled timestamps. The
detail view draws by seq order, so those late-written points with early
timestamps rendered as spikes across the map (distance stayed correct —
computeStats sorts by ts). Now stop imports only points past
_lastProcessedTs (the poll's processed marker): the genuinely un-polled
tail, including a screen-off stretch, without re-adding filtered points.
This commit is contained in:
4aiman 2026-07-30 00:22:27 +03:00
commit 30a9535793
4 changed files with 15 additions and 10 deletions

View file

@ -1059,23 +1059,28 @@ GPS.stopRecording = async function() {
let nativePointsFile = null;
console.log(`[stop] enter nativeService=${GPS.recording.nativeService} sessionId=${GPS.recording.sessionId}`);
if (GPS.recording.nativeService) {
// Import EVERY native point not yet in the DB. The live poll is screen-gated
// (WebView freezes timers while the screen is off), so a walk with the screen
// off leaves most points only in the native file. Idempotent by timestamp —
// same pattern as recoverSession. Then recompute stats over the COMPLETE set.
// Import ONLY the un-polled tail: native points with ts beyond the last one
// the live poll already PROCESSED (_lastProcessedTs). The poll advances that
// marker for every native point it handles, including ones it intentionally
// dropped (stationary / auto-pause / wrong state). The old code re-scanned the
// whole file and re-added everything "not in the DB" — which raw-inserted those
// dropped points back, interleaving them into the clean track and inflating
// distance with zigzag. Screen-off case still works: the poll was frozen, so
// _lastProcessedTs stays old and the whole dark stretch is beyond it.
const nativePoints = await GPS._readNativePoints();
let stopImported = 0;
if (GPS.recording.sessionId && nativePoints.length) {
const existing = await DB.getGpsPoints(GPS.recording.sessionId);
const dbTs = new Set(existing.map(p => new Date(p.ts).getTime()));
let seq = existing.length;
for (const p of nativePoints) {
if (dbTs.has(new Date(p.ts).getTime())) continue;
const pTs = new Date(p.ts).getTime();
if (pTs <= GPS.recording._lastProcessedTs) continue;
seq++;
await DB.addGpsPoint(GPS.recording.sessionId, p.ts, p.lat, p.lon, p.altitude, p.speed_ms, seq, null, p);
GPS.recording._lastProcessedTs = pTs;
stopImported++;
}
console.log(`[stop] native=${nativePoints.length} existing=${existing.length} imported=${stopImported}`);
console.log(`[stop] native=${nativePoints.length} existing=${existing.length} tail-imported=${stopImported}`);
GPS.recording.points = await DB.getGpsPoints(GPS.recording.sessionId);
} else {
console.log(`[stop] SKIP backfill: sessionId=${GPS.recording.sessionId} native=${nativePoints.length}`);

2
src-tauri/Cargo.lock generated
View file

@ -139,7 +139,7 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "baldav"
version = "0.1.382"
version = "0.1.383"
dependencies = [
"base64 0.22.1",
"btleplug",

View file

@ -1,6 +1,6 @@
[package]
name = "baldav"
version = "0.1.382"
version = "0.1.383"
edition = "2021"
[lib]

View file

@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/nicegui/tauri-v2/refs/heads/main/tooling/cli/schema.json",
"productName": "BalDav",
"version": "0.1.382",
"version": "0.1.383",
"identifier": "dev.baldav.app",
"build": {
"frontendDist": "../frontend"