Add per-photo-widget lock (freezes current photo until unlocked)
Build and push server image / test (push) Successful in 33s
Build and push server image / build-and-push (push) Successful in 2m32s
Build and push server image / deploy (push) Successful in 57s

A "Lock this photo" button in the photos widget's dialog toggles
PhotoWidgetConfig.locked, which suppresses both the timer-elapsed
auto-advance and the advance/back button actions until unlocked. The
Layout tab canvas shows a lock badge on any locked photo widget's box.
This commit is contained in:
2026-07-27 21:07:54 +00:00
parent 4e8c6e534b
commit 9911151d8d
14 changed files with 274 additions and 8 deletions
+34
View File
@@ -8,6 +8,33 @@
// FRAME_API + a global loadQueue()" contract queue.js has always had.
let photosPollTimer = null;
let photoLocked = false;
let photoHasCurrent = false;
function renderLockButton() {
const btn = document.getElementById('lock-photo-btn');
if (!btn) return;
btn.textContent = photoLocked ? 'Unlock this photo' : 'Lock this photo';
btn.classList.toggle('active', photoLocked);
btn.disabled = !photoHasCurrent && !photoLocked; // nothing displayed yet to lock
}
async function toggleLock() {
const next = !photoLocked;
try {
const resp = await fetch(`${window.FRAME_API}/lock`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ locked: next }),
});
if (!resp.ok) throw new Error(await apiError(resp));
photoLocked = next;
renderLockButton();
showStatus(true, photoLocked ? 'Locked -- this photo will stay put.' : 'Unlocked.');
} catch (e) {
showStatus(false, e.message);
}
}
async function loadQueue() {
if (dragState) {
@@ -21,9 +48,14 @@ async function loadQueue() {
currentEl.innerHTML =
'<p class="sub">Not available yet -- the owner needs to connect Immich (Settings) and pick an album.</p>';
renderUpcoming([]);
photoHasCurrent = false;
renderLockButton();
return;
}
const data = await resp.json();
photoLocked = !!data.locked;
photoHasCurrent = !!data.current;
renderLockButton();
currentEl.innerHTML = '';
if (data.current) {
const wrap = document.createElement('div');
@@ -109,6 +141,8 @@ function initPhotosDialog() {
}
});
document.getElementById('lock-photo-btn').addEventListener('click', toggleLock);
loadQueue();
// Slow poll: picks up real changes (new photo displayed, queue edited
// from elsewhere) without a manual refresh. Skipped mid-drag.