Persist device/camera settings across restarts independent of startup mode
Restore shutter sound/metering/RAW from a dedicated key under both 'default' and 'last session' startup (the session file only stores the look and is written on background events, so it can be stale after a force-kill). Guard the persist effect until hydration finishes so the mount-time defaults cannot overwrite the stored values; drop the stale session override of these three.
This commit is contained in:
@@ -30,6 +30,9 @@ import './global.css';
|
||||
|
||||
const SESSION_KEY = 'saved_session';
|
||||
const STARTUP_MODE_KEY = 'startup_mode';
|
||||
// Camera/device settings that survive restarts regardless of startup mode
|
||||
// (the session file only restores the full look under 'last session').
|
||||
const CAMERA_SETTINGS_KEY = 'camera_settings';
|
||||
|
||||
// P5: native Kotlin export path. EXPO_PUBLIC_NATIVE_EXPORT=1 swaps the Skia
|
||||
// render engine for the RecipesCamExport native pipeline (same look contract,
|
||||
@@ -204,10 +207,31 @@ export default function App() {
|
||||
return () => subscription.remove();
|
||||
}, [mode, libraryImageUri, adjustments, selectedFrame, useGeotag, selectedRecipe, gpsInfo, customWm, aspectRatio, meterMode, shutterSound]);
|
||||
|
||||
// Guards the camera-settings persist effect below: until initSession has
|
||||
// read the stored values, changes are just the initial defaults — writing
|
||||
// them would overwrite the saved settings (async restore loses the race
|
||||
// against the mount effect).
|
||||
const settingsHydratedRef = useRef(false);
|
||||
|
||||
const initSession = async () => {
|
||||
const list = await getAllRecipes();
|
||||
setRecipes(list);
|
||||
|
||||
// Device/camera settings restore first: they apply under BOTH startup
|
||||
// modes ('default' resets only the look, not these hardware choices).
|
||||
try {
|
||||
const raw = await AsyncStorage.getItem(CAMERA_SETTINGS_KEY);
|
||||
if (raw) {
|
||||
const s = JSON.parse(raw);
|
||||
if (s.shutterSound === 'on' || s.shutterSound === 'off') setShutterSound(s.shutterSound);
|
||||
if (s.meterMode === 'evaluative' || s.meterMode === 'highlight') setMeterMode(s.meterMode);
|
||||
if (typeof s.rawEnabled === 'boolean') setRawEnabled(s.rawEnabled);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to read camera settings:', e);
|
||||
}
|
||||
settingsHydratedRef.current = true;
|
||||
|
||||
// Startup mode: 'default' opens camera + PROVIA film sim (neutral
|
||||
// adjustments, DEFAULT_ADJUSTMENTS) at 4:3. 'last' restores the previous
|
||||
// session from AsyncStorage; with no saved session it falls back to the
|
||||
@@ -266,9 +290,11 @@ export default function App() {
|
||||
setAdjustments({ ...DEFAULT_ADJUSTMENTS, ...session.adjustments });
|
||||
if (session.selectedFrame) setSelectedFrame(session.selectedFrame);
|
||||
if (session.useGeotag !== undefined) setUseGeotag(session.useGeotag);
|
||||
if (session.aspectRatio === '4:3' || session.aspectRatio === '3:2') setAspectRatio(session.aspectRatio);
|
||||
if (session.meterMode === 'evaluative' || session.meterMode === 'highlight') setMeterMode(session.meterMode);
|
||||
if (session.shutterSound === 'on' || session.shutterSound === 'off') setShutterSound(session.shutterSound);
|
||||
if (session.aspectRatio === 'full' || session.aspectRatio === '4:3' || session.aspectRatio === '3:2') setAspectRatio(session.aspectRatio);
|
||||
// NOTE: meterMode/shutterSound/rawEnabled are NOT restored from the
|
||||
// session snapshot here — the session file is only written on background,
|
||||
// so it can be stale after a force-kill. CAMERA_SETTINGS_KEY above
|
||||
// persists them on every change and is authoritative for these three.
|
||||
if (session.gpsInfo) setGpsInfo(session.gpsInfo);
|
||||
if (session.customWm && typeof session.customWm === 'object') {
|
||||
// Restore defensively: a session saved by an older build may miss the
|
||||
@@ -384,6 +410,17 @@ export default function App() {
|
||||
AsyncStorage.setItem(STARTUP_MODE_KEY, mode).catch(() => {});
|
||||
};
|
||||
|
||||
// Persist device/camera settings on every change — not just on background —
|
||||
// so they survive a kill/relaunch even under 'default' startup, which only
|
||||
// resets the look (mode/ratio/recipe/geotag), not these.
|
||||
useEffect(() => {
|
||||
if (!settingsHydratedRef.current) return;
|
||||
AsyncStorage.setItem(
|
||||
CAMERA_SETTINGS_KEY,
|
||||
JSON.stringify({ shutterSound, meterMode, rawEnabled })
|
||||
).catch(() => {});
|
||||
}, [shutterSound, meterMode, rawEnabled]);
|
||||
|
||||
// Latest-rawEnabled ref so the stable session-error callback below can read
|
||||
// the live toggle without re-subscribing the Camera session on every render.
|
||||
const rawEnabledRef = useRef(rawEnabled);
|
||||
|
||||
Reference in New Issue
Block a user