Rename LIGHT GLOW to HDF EFFECT and gate it behind PRO: LITE renders the
chip greyed out with a PRO tag and cannot open its slider; restoration of
older settings that carry hdf > 0 still blocks export in LITE.
Play/licence pass:
- drop unused permissions (ACTIVITY_RECOGNITION, READ_MEDIA_AUDIO/VIDEO,
SYSTEM_ALERT_WINDOW) and requestLegacyExternalStorage
- rename the Leica sims to LC STREETLIFE CLASSIC/VIVID, drop the brand from
comments; fix app name text, canvaskit copyright, LICENSE owner
- remove expo-image-picker and expo-sensors (no JS import), delete dead
exports (computeMatrixTint, cinemaSeasonName, base64 helpers,
formatCoordinate)
- versionCode 3 / versionName 1.2.1, drop the personal email from About
- add docs/privacy-policy.html for the Play listing
Size: R8 + shrinkResources + bundle compression + ABI trim, 161 MB -> 76 MB.
Both flavors build from one JS tree: `lite` hands out the free apk
(com.locphamtran.recipescamera), `pro` sells as-is (same id + .pro, label
"RecipesCam Pro"). Release is signed from android/keystore.properties, both
files gitignored - lose either and no later build can install over this one.
The tier reaches JS through src/provariant.ts, which tools/set-variant.mjs
rewrites before each build (`npm run apk:lite` / `apk:pro`); the gradle flavor
alone would ship a Pro apk that thinks it is Lite.
The dev scaffolding goes: the three src/dev probes and their App effects, the
EXPO_PUBLIC_CAPTURE_MODE [CAPTURE] timing log, and the -PdevtestSuffix
side-by-side install hook. 'balanced' stays the shipped capture mode, which is
what those probes measured on the 12S Ultra.
Looking at the picture: WB now converts kelvin through the Planckian locus into
a luma-normalised gain (unity at 5500K, symmetric tint) instead of the old
one-sided push; LEITZ STREETLIFE splits into CLASSIC and VIVID; selecting a
recipe loads every knob it carries over the defaults and stays editable, and
RESET hands the panel back to the sim's own values. The in-app library picker,
the ultra-wide native module and recipe share/import land here too.
CLARITY and LIGHT GLOW existed only on the camera worklet and the export
engine, so a photo opened from the library ignored both. They now run in all
three library preview branches (libPhoto), and the preview clips them to the
drawn image - the export engine always clipped its bloom to the canvas, the
preview drew it over the whole rect, so the bloom bled past the photo onto the
black letterbox and over the frame's mat.
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.
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.