From 9c7cd5ec4eaf9e8dad4b3fd0ecf056cb22de403b Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Fri, 24 Jul 2026 22:47:48 +0700 Subject: [PATCH] Improve geolocation reliability: 3-stage fix with forgiving timeouts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the native crash is fixed (Kotlin 2.1 alignment on the Android side), the remaining issue was GPS "Location timed out" on a cold first fix / indoors. Rework the native position acquisition into three increasingly-forgiving stages that return the first success: 1. INSTANT — accept a cached/coarse fix up to 5 min old (resolves immediately on a warm chip). 2. PRECISE — high-accuracy GPS with a generous 30s window so a cold first-fix has room to complete. 3. COARSE FALLBACK — network/wifi fix with the longest window to rescue the "GPS can't lock indoors" case. Also bump the web-path timeout to 20s, and make the "Location timed out" toast actionable on native (suggests stepping near a window / retrying). Co-authored-by: shakespeare.diy --- src/lib/geolocation.ts | 54 +++++++++++++++++++++++++++++------------- src/pages/MapPage.tsx | 4 +++- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/lib/geolocation.ts b/src/lib/geolocation.ts index 1c8569b..853a940 100644 --- a/src/lib/geolocation.ts +++ b/src/lib/geolocation.ts @@ -188,31 +188,53 @@ async function getNativePosition(native: CapGeolocationPlugin): Promise + native.getCurrentPosition({ + enableHighAccuracy: false, + timeout: 8000, + maximumAge: 300000, // accept a fix up to 5 minutes old + }), + ); + return { lat: pos.coords.latitude, lng: pos.coords.longitude }; + } catch (cachedErr) { + console.warn('[geolocation] cached/coarse fix unavailable, trying GPS:', cachedErr); + } + + // Stage 2 — PRECISE: full high-accuracy GPS with a generous window so a + // cold first-fix has room to complete. try { const pos = await safeCall(() => native.getCurrentPosition({ enableHighAccuracy: true, - timeout: 10000, - maximumAge: 30000, + timeout: 30000, // give a cold GPS lock plenty of time + maximumAge: 60000, }), ); return { lat: pos.coords.latitude, lng: pos.coords.longitude }; } catch (highAccErr) { - // Fall back to a coarse (network/cell/wifi) fix with a longer window. - // This rescues the common "GPS can't lock" case that otherwise looks - // like a hard failure. console.warn('[geolocation] high-accuracy failed, trying coarse:', highAccErr); - const pos = await safeCall(() => - native.getCurrentPosition({ - enableHighAccuracy: false, - timeout: 20000, - maximumAge: 120000, - }), - ); - return { lat: pos.coords.latitude, lng: pos.coords.longitude }; } + + // Stage 3 — COARSE FALLBACK: network/cell/wifi fix with the longest window. + // This rescues the common "GPS can't lock indoors" case. + const pos = await safeCall(() => + native.getCurrentPosition({ + enableHighAccuracy: false, + timeout: 30000, + maximumAge: 300000, + }), + ); + return { lat: pos.coords.latitude, lng: pos.coords.longitude }; } catch (err) { if (err instanceof GeolocationError) throw err; const msg = (err instanceof Error ? err.message : String(err)).toLowerCase(); @@ -255,7 +277,7 @@ function getWebPosition(): Promise { reject(new GeolocationError('unavailable', 'Location unavailable.')); } }, - { enableHighAccuracy: true, timeout: 10000, maximumAge: 30000 }, + { enableHighAccuracy: true, timeout: 20000, maximumAge: 60000 }, ); }); } diff --git a/src/pages/MapPage.tsx b/src/pages/MapPage.tsx index d3f9b40..6af4ede 100644 --- a/src/pages/MapPage.tsx +++ b/src/pages/MapPage.tsx @@ -656,7 +656,9 @@ export default function MapPage() { setNearMeError('timeout'); toast({ title: 'Location timed out', - description: 'Could not get your location in time. Check your signal and try again.', + description: isNativeGeolocation() + ? "Couldn't get a GPS fix in time. This is common on the first try or indoors — step near a window or outside and tap Near Me again." + : 'Could not get your location in time. Check your signal and try again.', variant: 'destructive', }); } else {