feat(library): RESET SETTING puts a frame back to the tile it came in with

This commit is contained in:
2026-10-11 12:00:22 +07:00
parent 791e7d093c
commit de5d42e272
4 changed files with 84 additions and 0 deletions
+36
View File
@@ -2249,6 +2249,14 @@ export function makeThumb(photo: LibraryPhoto): Promise<Blob | null> {
async function makeOneThumb(photo: LibraryPhoto): Promise<Blob | null> {
const kept = await getPhotoThumb(photo.id);
if (kept) return kept;
return tileFrom(photo);
}
// The tile the frame's own source gives, with neither keeper of a graded tile
// asked. The shelf is not the caller: a frame put back wears the picture it was
// first drawn with, and both the store and the backup still hold the look that
// was just taken back.
async function tileFrom(photo: LibraryPhoto): Promise<Blob | null> {
// A server's frame has no file to open: its tile is the one Immich drew, asked
// for here and kept, so the second look comes out of the store and the sync's
// own download is only paid once.
@@ -2516,6 +2524,34 @@ export async function saveEdit(id: string, state: StudioState): Promise<void> {
}
}
// Put a frame back to the picture it was first drawn with: the recipe the studio
// filed goes, and the tile it graded from the negative goes with it — the store's
// copy and the backup's, which is the same look. The tile is made here rather than
// left to the shelf to make, because the shelf's way in asks the backup first and
// the backup is holding the look just taken back. Written without `tell`: the
// reader's own click is what redraws this frame, and the shelf has no business
// being told about a rewrite it asked for.
export async function resetEdit(photo: LibraryPhoto): Promise<Blob | null> {
try {
const db = await openDb();
const hasThumbs = db.objectStoreNames.contains(THUMBS);
await new Promise<void>((resolve, reject) => {
const tx = db.transaction([EDITS, ...(hasThumbs ? [THUMBS] : [])], 'readwrite');
tx.objectStore(EDITS).delete(photo.id);
if (hasThumbs) tx.objectStore(THUMBS).delete(photo.id);
tx.oncomplete = () => resolve();
tx.onerror = () => reject(tx.error);
});
} catch {
// Private mode, or nothing filed for this frame: there is no look to take
// back, and the tile below is made all the same.
}
thumbCache.delete(photo.id);
const made = await tileFrom(photo);
if (made) await writeThumb(photo.id, made, false);
return made;
}
export async function loadEdit(id: string): Promise<LibraryEdit | null> {
try {
// A row filed before the whole look was kept carries the recipe alone: lift