feat(studio): edits follow the photo — reopening it from LIBRARY restores the whole look
Settings changed in the studio were remembered per photo, but only as a film recipe, so everything outside that recipe (straighten, flips, crop, watermark, geotag, frame, the picked sim) was gone as soon as the photo was reopened from the library in a later session. Keep the whole StudioState instead and restore it when a library photo is opened; rows written by older builds — a flat recipe — are still readable, so photos edited before this change open with their look intact. SAVE PHOTO is untouched: that remains the step that publishes a photo to the landing film strip.
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
// FileSystemHandle by itself and the whole surface is seven calls — a dependency
|
||||
// does not pay for itself here. Revisit if the catalogue grows queries (tags,
|
||||
// smart collections) that hand-rolled cursors would make ugly.
|
||||
import type { Recipe } from '../../shared/types';
|
||||
import type { StudioState } from './session';
|
||||
import { readCapturedAt } from './imageOps';
|
||||
import { isRawName, isTiffName, rawThumbnail } from './rawDevelop';
|
||||
import { heicThumbnail, heicToJpeg, isHeicName } from './heicDevelop';
|
||||
@@ -131,7 +131,10 @@ export interface LibraryDir {
|
||||
|
||||
export interface LibraryEdit {
|
||||
photoId: string;
|
||||
recipe: Recipe;
|
||||
// The whole look the frame was left at, the same record the studio keeps for
|
||||
// the working photo — frame, crop, rotation, mirrors, marks and geotag change
|
||||
// the picture as much as the recipe does, so the recipe alone was not enough.
|
||||
state: StudioState;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
@@ -2150,18 +2153,27 @@ export async function readPhotoFile(photo: LibraryPhoto): Promise<File> {
|
||||
|
||||
// --- edits -----------------------------------------------------------------
|
||||
|
||||
export async function saveEdit(id: string, recipe: Recipe): Promise<void> {
|
||||
export async function saveEdit(id: string, state: StudioState): Promise<void> {
|
||||
try {
|
||||
const edit: LibraryEdit = { photoId: id, recipe, updatedAt: Date.now() };
|
||||
const edit: LibraryEdit = { photoId: id, state, updatedAt: Date.now() };
|
||||
await ask(EDITS, 'readwrite', (s) => s.put(edit));
|
||||
} catch {
|
||||
// Private mode: the frame is still editable, it just forgets the recipe.
|
||||
// Private mode: the frame is still editable, it just forgets the look.
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadEdit(id: string): Promise<LibraryEdit | null> {
|
||||
try {
|
||||
return (await ask<LibraryEdit | undefined>(EDITS, 'readonly', (s) => s.get(id))) ?? null;
|
||||
// A row filed before the whole look was kept carries the recipe alone: lift
|
||||
// it into a state so the caller reads one shape, old rows included.
|
||||
const row = await ask<(Partial<LibraryEdit> & { recipe?: StudioState['recipe'] }) | undefined>(
|
||||
EDITS,
|
||||
'readonly',
|
||||
(s) => s.get(id),
|
||||
);
|
||||
if (!row) return null;
|
||||
if (row.state) return row as LibraryEdit;
|
||||
return { photoId: row.photoId ?? id, state: { recipe: row.recipe }, updatedAt: row.updatedAt ?? 0 };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user