cbe3e0eeaf
- Skip MapLibre on Android <29 (Karoo): SELinux denies kgsl-3d0 access from untrusted_app context, crashing the GPU driver on any OpenGL surface. Replace with SvgRouteView — equirectangular SVG route trace using react-native-svg, no native GL surface needed. - Add +/- zoom buttons to full-screen MapLibre map on modern devices via Camera ref and onRegionDidChange. - Skip PyodideWebView on Android <29: same GPU driver conflict; set _engineUnavailable at module init via API level gate (< 29). - Add engine_unavailable fast path in PyodideWebView: post message immediately if WebAssembly.Global is absent (Chrome <69) instead of attempting 30 MB Pyodide download. - Add server-side extraction fallback (extractServer.ts): when engine unavailable, POST raw file as base64 to /api/upload/raw; server runs full Python pipeline and returns extracted data. - Add /api/upload/raw endpoint in server.py. - Add pre-flight auth check (checkServerAuth) before batch import so an expired token errors immediately rather than after N files. - Fix uploadLocalActivities in sync.ts: was reading original_path as JSON (binary FIT file, always threw), silently skipping every upload. Now reads detail_json from DB directly. - Redesign Feed header: replace single Sync button with Upload / Download / Refresh. Pull-to-refresh and Refresh button are local-only. Auto-refresh on tab focus via useFocusEffect. - Replace ActivityIndicator with plain Text everywhere (native animation also crashes Karoo GPU driver). - Raise macOS open-file limit in dev_test.py to prevent EMFILE errors from Astro file watcher. - Document all Karoo hardware constraints in docs/mobile-app.md.
64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
import type { ExtractionResult } from './extractActivity';
|
|
|
|
export async function checkServerAuth(instanceUrl: string, token: string): Promise<void> {
|
|
let resp: Response;
|
|
try {
|
|
resp = await fetch(`${instanceUrl}/api/feed`, {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
} catch {
|
|
throw new Error('Could not reach Bincio instance — check your connection.');
|
|
}
|
|
if (resp.status === 401) throw new Error('Session expired — reconnect in Settings.');
|
|
if (!resp.ok) throw new Error(`Server error (${resp.status})`);
|
|
}
|
|
|
|
export async function extractFileViaServer(
|
|
filename: string,
|
|
base64: string,
|
|
instanceUrl: string,
|
|
token: string,
|
|
onStatus: (msg: string) => void = () => {},
|
|
): Promise<ExtractionResult> {
|
|
onStatus('Uploading to Bincio instance…');
|
|
|
|
let resp: Response;
|
|
try {
|
|
resp = await fetch(`${instanceUrl}/api/upload/raw`, {
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ filename, base64 }),
|
|
});
|
|
} catch {
|
|
throw new Error('Could not reach Bincio instance — check your connection.');
|
|
}
|
|
|
|
if (resp.status === 401) throw new Error('Session expired — reconnect in Settings.');
|
|
if (resp.status === 422) {
|
|
const body = await resp.json().catch(() => ({})) as { detail?: string };
|
|
throw new Error(body.detail ?? 'Server could not process this file.');
|
|
}
|
|
if (!resp.ok) throw new Error(`Server error (${resp.status})`);
|
|
|
|
onStatus('Processing on server…');
|
|
const data = await resp.json() as {
|
|
ok: boolean;
|
|
id: string;
|
|
detail: object;
|
|
timeseries: object | null;
|
|
geojson: object | null;
|
|
source_hash: string;
|
|
};
|
|
|
|
return {
|
|
id: data.id,
|
|
detail: data.detail,
|
|
timeseries: data.timeseries,
|
|
geojson: data.geojson,
|
|
sourceHash: data.source_hash,
|
|
};
|
|
}
|