diff --git a/mobile/db/sync.ts b/mobile/db/sync.ts index f17f7d6..5e010b0 100644 --- a/mobile/db/sync.ts +++ b/mobile/db/sync.ts @@ -1,3 +1,4 @@ +import * as FileSystem from 'expo-file-system/legacy'; import type { SQLiteDatabase } from 'expo-sqlite'; import { getSetting, upsertRemoteActivity } from './queries'; @@ -158,8 +159,14 @@ async function uploadLocalActivities( token: string, onProgress?: (n: number, total: number) => void, ): Promise<{ uploaded: number; failed: number }> { - const rows = db.getAllSync<{ id: string; detail_json: string; timeseries_json: string | null; geojson: string | null }>( - `SELECT id, detail_json, timeseries_json, geojson + const rows = db.getAllSync<{ + id: string; + detail_json: string; + timeseries_json: string | null; + geojson: string | null; + original_path: string | null; + }>( + `SELECT id, detail_json, timeseries_json, geojson, original_path FROM activities WHERE origin = 'local' AND synced_at IS NULL`, ); @@ -173,28 +180,44 @@ async function uploadLocalActivities( const row = rows[i]; onProgress?.(i + 1, total); try { - const detail = JSON.parse(row.detail_json); - const activity = { id: row.id, ...detail }; + let resp: Response; - const body: Record = { activity }; - if (row.timeseries_json) body.timeseries = JSON.parse(row.timeseries_json); - if (row.geojson) body.geojson = JSON.parse(row.geojson); + // Prefer raw upload when the original FIT/GPX/TCX file is still on disk. + // The server re-extracts it with DEM elevation correction, producing better data. + const useRaw = row.original_path !== null && + (await FileSystem.getInfoAsync(row.original_path)).exists; - const resp = await fetch(`${instanceUrl}/api/upload/bas`, { - method: 'POST', - headers, - body: JSON.stringify(body), - }); + if (useRaw) { + const filename = row.original_path!.split('/').pop() ?? 'activity.fit'; + const base64 = await FileSystem.readAsStringAsync(row.original_path!, { + encoding: FileSystem.EncodingType.Base64, + }); + resp = await fetch(`${instanceUrl}/api/upload/raw`, { + method: 'POST', + headers, + body: JSON.stringify({ filename, base64 }), + }); + } else { + const detail = JSON.parse(row.detail_json); + const body: Record = { activity: { id: row.id, ...detail } }; + if (row.timeseries_json) body.timeseries = JSON.parse(row.timeseries_json); + if (row.geojson) body.geojson = JSON.parse(row.geojson); + resp = await fetch(`${instanceUrl}/api/upload/bas`, { + method: 'POST', + headers, + body: JSON.stringify(body), + }); + } if (resp.ok) { await db.runAsync(`UPDATE activities SET synced_at = ? WHERE id = ?`, [now, row.id]); uploaded++; } else { - console.warn(`upload/bas ${row.id}: HTTP ${resp.status}`); + console.warn(`upload ${row.id}: HTTP ${resp.status}`); failed++; } } catch (err) { - console.warn(`upload/bas ${row.id}:`, err); + console.warn(`upload ${row.id}:`, err); failed++; } }