Fix "Show next" staleness bug; add location/date/share-QR to manage overlay
Build and push server image / build-and-push (push) Successful in 32s

Two changes, bundled since they landed in the same session and touch
overlapping files:

1. Fix: "Show next" sent the browser's full queue snapshot to
   POST /api/queue/reorder, which hard-rejected if the server's queue
   had shifted since the last fetch (e.g. right after a queue-length
   trim). New POST /api/queue/promote moves one photo to the front
   authoritatively, with no dependency on client staleness. /reorder
   itself is now tolerant too -- unrecognized IDs are dropped and
   missing ones appended, instead of rejecting the whole request.

2. Feature: the manage button's overlay now also shows the photo's
   location (top-left, only if Immich reverse-geocoded it from GPS
   EXIF), the date it was taken (bottom-right), and a QR code (bottom-
   left) linking to a 30-minute public Immich share link -- created
   lazily when someone actually scans it, not when the button's
   pressed. New server endpoints GET /frame/photo-info and
   GET /frame/share/{asset_id} (scoped to the frame's current/queued
   photos, not any arbitrary Immich asset). Firmware-side, the overlay
   mechanism generalizes from one spliced region to up to four
   (manage_qr_overlay.c), each its own small buffer, still never
   holding the full frame in RAM.
This commit is contained in:
2026-07-19 01:28:25 -04:00
parent 42d7c09f97
commit a358045cea
8 changed files with 523 additions and 83 deletions
+28 -9
View File
@@ -4,19 +4,38 @@
#include "esp_err.h"
#define MANAGE_OVERLAY_MAX_REGIONS 4
typedef struct {
uint8_t *buf; /* malloc'd (w/2)*h bytes, packed 2px/byte; caller must free */
uint8_t *buf; /* malloc'd (w/2)*h bytes, packed 2px/byte; owned by the region */
int x0, y0; /* top-left corner, panel pixel coordinates (x0 is always even) */
int w, h; /* pixel dimensions (w is always even) */
} manage_qr_overlay_t;
} manage_overlay_region_t;
typedef struct {
manage_overlay_region_t regions[MANAGE_OVERLAY_MAX_REGIONS];
int count;
} manage_overlay_set_t;
typedef struct {
const char *management_url; /* top-right QR + "SCAN TO"/"MANAGE" caption -- always shown */
const char *location; /* top-left text; NULL/empty skips this region */
const char *taken_at; /* bottom-right text; NULL/empty skips this region */
const char *share_url; /* bottom-left QR (no caption); NULL/empty skips this region */
} manage_overlay_content_t;
/**
* Renders a small "scan to manage" overlay -- a QR code encoding
* management_url plus a "SCAN TO" / "MANAGE" caption, on a white
* padded background -- into a freshly allocated buffer sized just for
* the overlay itself (not a full EPD_FRAME_BYTES frame), positioned for
* the panel's top-right corner. Caller must call manage_qr_overlay_free().
* Renders the manage-button overlay: always a "scan to manage" QR in the
* top-right corner, plus whichever of location/taken_at/share_url are
* non-NULL/non-empty in their own corners (top-left, bottom-right,
* bottom-left respectively). Each region is its own separately malloc'd
* small buffer (not a full EPD_FRAME_BYTES frame). A failure rendering
* the top-right region fails the whole call; a failure rendering one of
* the optional regions just skips that region and keeps going. Caller
* must call manage_overlay_free() on out regardless of the return value
* (out->count reflects however many regions were actually populated).
*/
esp_err_t manage_qr_overlay_render(const char *management_url, manage_qr_overlay_t *out);
esp_err_t manage_overlay_render(const manage_overlay_content_t *content, manage_overlay_set_t *out);
void manage_qr_overlay_free(manage_qr_overlay_t *overlay);
/** Frees every populated region's buffer in overlay. */
void manage_overlay_free(manage_overlay_set_t *overlay);