The album grid now shows a filtered + sorted view of the list:
- SQUARE (or tap the header pill) opens the keyboard to filter albums
by name (case-insensitive); O clears the filter before going back.
- SELECT (or tap the chip) cycles the order: modified newest/oldest,
name A-Z/Z-A. Uses the album's updatedAt from GET /api/albums.
- Cover eviction no longer drops a texture that a visible card still
uses when two albums share the same cover photo.
- README: albums controls.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add albums browsing and navigation (src/albums.c, src/app.c)
- Extract API calls into dedicated src/api.c module
- Improve display and UI components
- Update CMakeLists.txt to include new source files
- Refactor Dockerfile for better build process
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Base map / tiles:
- Switch the base map to the mapchart city-label world map; re-derive its
Web-Mercator georeferencing (MAP_LON0/1, MAP_IMG_MY0/1) by least-squares
against the pixel-identical graticule export.
- Add a 1.5x LANCZOS supersample LOD and bump tile quality 90->94 so city
labels stay crisp when zoomed in (tools/png_to_tiles.py).
- Fill the map view background with the ocean colour instead of black.
Navigation / clustering:
- Snap the cluster grid to power-of-two zoom octaves so the bubbles stop
jittering during a continuous zoom.
- Replace the loose zoom clamps with named MAP_SCALE_MIN/MAX (whole map fills
the screen .. country/region level).
- Add a toggleable computed lat/lon graticule overlay (TRIANGLE).
Cluster gallery:
- Selecting a bubble now opens all its photos on the same justified grid as
the timeline/search (a g_gallery_active filter). Members not already paged
in are appended as hidden g_asset entries (kept out of the main timeline);
a background metadata worker resolves each one's date/aspect so the grid
reflows into month sections + true aspect ratios.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uKJQMYDE9Nrq9ECsU3MxH
- Video: probe the MP4 header (range request for moov) before downloading
the whole clip; if the average bitrate overruns the declared H.264 level
the Vita's decoder enforces, show the "too high" message up front instead
of downloading then failing at playback. Verdict validated against the
real demo videos (e.g. e75d495e: Level 3.1 @ 18.8 Mbps -> rejected).
- Error screens: word-wrap title + detail so long messages no longer run
off the edges; the bitrate message now spells out the server-side fix
(Immich transcoding policy / bitrate cap).
- Boot: one continuous spinner. A single boot worker thread does sign-in +
first page + local scan while the main thread animates one logo with a
never-resetting frame counter, instead of three separate static screens.
- Throbbers: the cloud/server-info page and smart search now fetch on a
worker thread and animate a throbber instead of freezing the UI.
- Logo: swap the in-app logo for a clean 200x200 transparent PNG (the old
one was matted from the white-background icon and had fringe); keep the
launcher icon's white background. Linear-filter the logo + cloud badges
so they scale/rotate smoothly.
- Drop AgenticLoop.md (and its CLAUDE.md reference).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
main.c was a single 6018-line translation unit. Cut it at the existing
section banners into ordered part files (state, draw, config, net, jpeg,
api, thumbs, display, ui, video, sync, app) that main.c #includes in
dependency order.
The parts form one translation unit and share all file-scope state, so
there are no headers, no extern decls, and no de-static-ing of the ~100
shared globals coupling the three threads. Only src/main.c is compiled
(CMakeLists unchanged). The slices are byte-exact: the preprocessed TU is
identical to the old main.c, so the binary is unchanged. Verified by a
clean build plus a Vita3K run (login, paging, grid, detail view, back nav,
no crash).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>