feat(hobbs-organizer): v1.3.0 photo gallery + Shield photo app 1.1, slideshow 15s

- /photo/gallery: D-pad grid, OK opens full screen, arrows browse, Back returns
- 400px gallery tiles cached per photo (sync + uploads)
- com.dayline.photos 1.1: launcher tile opens the gallery, takes remote input,
  Back steps through WebView history; screensaver unchanged
- slideshow interval 20s -> 15s (live settings)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E9NnVEico3WvFxLyjy1iW3
This commit is contained in:
2026-11-04 21:19:24 -06:00
parent 5cfd2de432
commit 00e0cc42cf
16 changed files with 382 additions and 33 deletions
@@ -381,7 +381,7 @@ function ago(timestamp: number | null) {
return hours < 48 ? `${hours} h ago` : `${Math.round(hours / 24)} days ago`;
}
/** Resize in the browser to a 1920px JPEG and a 64px thumbnail, so the server needs no image library. */
/** Resize in the browser to a 1920px JPEG, a 400px gallery tile and a 64px thumbnail, so the server needs no image library. */
async function resizeForUpload(file: File) {
const bitmap = await createImageBitmap(file);
const encode = async (edge: number, quality: number) => {
@@ -395,9 +395,10 @@ async function resizeForUpload(file: File) {
return { blob, width: canvas.width, height: canvas.height };
};
const photo = await encode(1920, 0.88);
const tile = await encode(400, 0.82);
const thumb = await encode(64, 0.7);
bitmap.close();
return { photo, thumb };
return { photo, tile, thumb };
}
function PhotosTab() {
@@ -500,10 +501,11 @@ function PhotosTab() {
for (const file of Array.from(files)) {
setUploading(`Uploading ${done + failed + 1} of ${files.length}…`);
try {
const { photo, thumb } = await resizeForUpload(file);
const { photo, tile, thumb } = await resizeForUpload(file);
const form = new FormData();
form.append("photo", photo.blob, "photo.jpg");
form.append("thumb", thumb.blob, "thumb.jpg");
form.append("tile", tile.blob, "tile.jpg");
form.append("width", String(photo.width));
form.append("height", String(photo.height));
form.append("takenAt", String(file.lastModified || ""));