fix(gps): resolve place name when the watermark is switched on

A photo picked while the GPS chip was off kept its coordinates but no
locality (the geocode only ran when the chip was already on), and
handleToggleGeotag skipped GPS loading entirely when coordinates already
existed -- so switching the chip on showed STREET VIEW. Request location
permission inside reverseGeocode (expo-location's Android geocoder throws
LocationUnauthorizedException without it) and re-resolve the name from an
effect whenever the mark has coordinates but no place name. Both paths now
share localityName() so camera and photo stamps cannot disagree.
This commit is contained in:
2026-09-10 17:01:48 +07:00
parent 67a2a52a6f
commit 423bf533f8
2 changed files with 33 additions and 6 deletions
+16 -1
View File
@@ -19,7 +19,7 @@ import PhotoViewerModal from './src/components/PhotoViewerModal';
import { Recipe, ColorAdjustments, CustomWatermark, GpsWatermark, FrameId, GPSInfo, AspectRatio, MeterMode, PhotoEntry, ShutterSound, StartupMode } from './src/types';
import { getAllRecipes, saveCustomRecipe, deleteCustomRecipe } from './src/utils/storageUtils';
import { DEFAULT_ADJUSTMENTS, FILM_SIMS, filmSimToRecipe } from './src/utils/defaultRecipes';
import { getCurrentGPS, requestLocationPermissions } from './src/utils/locationUtils';
import { getCurrentGPS, requestLocationPermissions, reverseGeocode } from './src/utils/locationUtils';
import { resolvePhotoGPS } from './src/utils/photoGps';
import { processAndExportPhoto } from './src/utils/exportEngine';
import { processAndExportPhotoNative } from './src/utils/nativeExport';
@@ -245,6 +245,21 @@ export default function App() {
}
}, []);
// A photo picked while the GPS chip was OFF kept its coordinates but no place
// name (the geocode only ran when the chip was already on), and toggleGeotag
// skips GPS loading entirely when coordinates exist — so turning the chip on
// showed "STREET VIEW". Resolve the name whenever the mark needs one.
useEffect(() => {
if (!useGeotag || !gpsInfo || gpsInfo.locality) return;
let stale = false;
reverseGeocode(gpsInfo.latitude, gpsInfo.longitude).then((name) => {
if (!stale && name) setGpsInfo((g) => (g && !g.locality ? { ...g, locality: name } : g));
});
return () => {
stale = true;
};
}, [useGeotag, gpsInfo]);
// Save/restore session on app lifecycle changes
useEffect(() => {
const subscription = AppState.addEventListener('change', async (nextAppState) => {
+17 -5
View File
@@ -29,8 +29,7 @@ export async function getCurrentGPS(): Promise<GPSInfo | null> {
if (geocode && geocode.length > 0) {
const address = geocode[0];
// Combine city, region, street or subregion to form a retro looking place string
locality = address.subregion || address.city || address.district || address.region || 'LOCAL REGION';
locality = locality.toUpperCase();
locality = localityName(address) || 'LOCAL REGION';
country = (address.country || '').toUpperCase();
}
} catch (e) {
@@ -50,12 +49,25 @@ export async function getCurrentGPS(): Promise<GPSInfo | null> {
}
}
// The one place-name picker. Order is the camera's original one
// (subregion = subAdminArea = district/county first, then city, district,
// region) kept verbatim so already-working camera stamps do not shift; only
// the photo path used to drop the district term. Shared so the camera stamp
// and a photo's stamp can never disagree about the same coordinates.
export function localityName(address: Location.LocationGeocodedAddress): string | null {
const name = address.subregion || address.city || address.district || address.region;
return name ? name.toUpperCase() : null;
}
export async function reverseGeocode(latitude: number, longitude: number): Promise<string | null> {
// Foreground permission is not optional here: expo-location's Android
// geocoder throws LocationUnauthorizedException without it. A photo picked
// before the camera ever asked for location therefore resolved to no name at
// all and the stamp fell back to "STREET VIEW" — so ask before every call.
await requestLocationPermissions();
try {
const geo = await Location.reverseGeocodeAsync({ latitude, longitude });
if (geo && geo.length > 0) {
return (geo[0].subregion || geo[0].city || geo[0].region || '').toUpperCase() || null;
}
if (geo && geo.length > 0) return localityName(geo[0]);
} catch (e) {
console.warn('Reverse geocode failed:', e);
}