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
+16
View File
@@ -18,6 +18,8 @@ URL: http://localhost:4321
"""
import argparse
import platform
import resource
import shutil
import subprocess
import sys
@@ -163,6 +165,18 @@ def start_dev(mobile: bool = False) -> None:
# ── main ──────────────────────────────────────────────────────────────────────
def raise_open_file_limit() -> None:
# Astro's file watcher opens many handles; macOS defaults to 256, which
# causes EMFILE errors under a large project tree.
if platform.system() != "Darwin":
return
target = 65536
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
if soft < target:
resource.setrlimit(resource.RLIMIT_NOFILE, (min(target, hard), hard))
ok(f"open-file limit raised to {min(target, hard)}")
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
@@ -171,6 +185,8 @@ def main() -> None:
parser.add_argument("--mobile", action="store_true", help="Bind API to 0.0.0.0 for local mobile testing")
args = parser.parse_args()
raise_open_file_limit()
print(f"\033[1mbincio dev test\033[0m → {DATA_DIR}")
if args.fresh and DATA_DIR.exists():