feat(mobile): Karoo GPU crash fix, server-side extraction, upload fix, feed redesign

- 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.
This commit is contained in:
Davide Scaini
2026-04-26 21:00:12 +02:00
parent 4cabbea0d4
commit cbe3e0eeaf
10 changed files with 760 additions and 156 deletions
+9 -1
View File
@@ -77,6 +77,14 @@ var initError = null;
(async function init() {
try {
// WebAssembly.Global was added in Chrome 69. Without it Pyodide cannot
// initialise on any version. Bail out immediately so the mobile app can
// fall back to server-side extraction without attempting a 35 MB download.
if (typeof WebAssembly === 'undefined' || typeof WebAssembly.Global === 'undefined') {
_post({ type: 'engine_unavailable', reason: 'wasm_global' });
return;
}
_post({ type: 'progress', msg: 'Loading Python runtime…' });
// Chrome <80 is missing features that modern Pyodide uses in its JS wrapper:
@@ -108,7 +116,7 @@ var initError = null;
var _pyResp = await fetch(_CDN_COMPAT + 'pyodide.js');
if (!_pyResp.ok) throw new Error('Could not fetch pyodide.js (' + _pyResp.status + ')');
var _pyCode = await _pyResp.text();
_pyCode = 'var globalThis=typeof globalThis!=="undefined"?globalThis:self;\n' + _pyCode;
_pyCode = 'var globalThis=typeof globalThis!=="undefined"?globalThis:self;\\n' + _pyCode;
_pyCode = _pyCode.split('import(').join('__loadScript(');
_pyCode = _pyCode.split('for await(').join('for(');
await new Promise(function(res, rej) {