fix(gps): stop stamping the phone's current location on a picked photo

The library flow ended in a device-GPS fallback: whenever a photo's own
coordinates could not be read, getCurrentGPS() supplied the phone's present
spot, so the mark named wherever the user was standing instead of where the
photo was taken. Drop that tier entirely -- a photo with no readable location
gets no GPS mark. Also keep the legacy Android picker unconditionally so the
picked file keeps its EXIF GPS whatever the chip state, and prefer the city
over subAdminArea (county/district) as the displayed place name.
This commit is contained in:
2026-09-10 17:08:09 +07:00
parent 423bf533f8
commit 614ebb170b
3 changed files with 26 additions and 39 deletions
+5 -6
View File
@@ -49,13 +49,12 @@ 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.
// The one place-name picker: city first, because "the place" on a stamp means
// the town people would name, while subregion is Android's subAdminArea — the
// county/district, i.e. the wrong name for the same coordinates. Shared so the
// camera stamp and a photo's stamp can never disagree.
export function localityName(address: Location.LocationGeocodedAddress): string | null {
const name = address.subregion || address.city || address.district || address.region;
const name = address.city || address.subregion || address.district || address.region;
return name ? name.toUpperCase() : null;
}
+7 -12
View File
@@ -3,7 +3,7 @@ import * as MediaLibrary from 'expo-media-library';
import { getAssetInfoAsync } from 'expo-media-library/legacy';
import { GPSInfo } from '../types';
import { parseExifGPS, parseExifTimestamp, ExifLike } from './exifGps';
import { getCurrentGPS, reverseGeocode } from './locationUtils';
import { reverseGeocode } from './locationUtils';
export interface PickedPhotoAsset {
uri?: string;
@@ -89,12 +89,14 @@ async function resolveFromMediaLibrary(
}
// Resolve GPS for a picked photo: EXIF → MediaLibrary (needs ACCESS_MEDIA_LOCATION
// on Android 10+) → device GPS fallback.
// on Android 10+). A photo that carries no location gets NO stamp: the device's
// current spot is not where the photo was taken, and substituting it only ever
// shows the wrong place name.
export async function resolvePhotoGPS(
asset: PickedPhotoAsset,
opts: { useGeotag: boolean; allowDeviceFallback?: boolean }
opts: { useGeotag: boolean }
): Promise<PhotoGpsResult> {
const { useGeotag, allowDeviceFallback = true } = opts;
const { useGeotag } = opts;
// Tier 1 — EXIF embedded in the file (needs no extra permission)
const exifCoord = parseExifGPS(asset.exif);
@@ -117,13 +119,6 @@ export async function resolvePhotoGPS(
console.warn('Photo GPS tier-2 skipped — no asset id/uri');
}
// Tier 3 — device fallback (photo has no location; stamp the device's current spot)
if (allowDeviceFallback) {
const deviceGps = await getCurrentGPS();
if (deviceGps) {
return { gps: { ...deviceGps, source: 'device' } };
}
}
console.warn('Photo has no readable location — stamping no GPS mark');
return { gps: null };
}