Make the thumbnails while the originals are still in hand

An import read every byte of every original, uploaded them, and then left the
grid to fetch a preview range back out of each one over the network — for
files that had been on this machine minutes earlier.

The pixels are now made from the bytes already in memory, on the fast path
FR-CAT-3 names: locate the camera's own embedded JPEG, decode a few hundred
KB, downscale, orient. Never a demosaic. A file with no usable preview yields
none, which is not an error and simply leaves the grid to fetch one later.

The filing waits for the upload, and only the filing. The shard store is keyed
by `oc:fileid` (FR-NC-5) and that does not exist until the server has the
file — so the thumbnail is made from the local copy and held until an id can
be attached to it. One listing per folder supplies every id at once, rather
than a PROPFIND per photograph over a link that may be mobile data.

Best-effort throughout: a thumbnail that cannot be filed costs the grid one
preview fetch later, and failing an import over it would be the wrong trade.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 19:20:13 +02:00
co-authored by Claude Opus 5
parent e3dd1526e0
commit 28325af448
5 changed files with 303 additions and 50 deletions
+10
View File
@@ -908,6 +908,12 @@ pub fn run(paths: Vec<PathBuf>) -> Result<()> {
// this runs once at startup, where a library can be opened, closed and
// re-opened for the whole life of the window.
{
// Whether the header offers Import at all. A fact about the platform,
// set once: it cannot change while the window is open, and on Android
// it is false because there is no card to reach and nothing to write
// through (`dr_plat::imports_supported`).
window.set_import_supported(dr_plat::imports_supported());
let import = import_ui::ImportController::new(settings.clone(), activity.clone());
let library_for_context = library.clone();
let weak = window.as_weak();
@@ -927,6 +933,10 @@ pub fn run(paths: Vec<PathBuf>) -> Result<()> {
credentials: creds,
user_id: session.user_id.clone(),
library: session.root.clone(),
// The same shard store the grid reads and the sync
// pushes, so a thumbnail made during an import is the
// one every other client gets.
thumbs: library::thumbs_dir(&session.server, &session.user_id),
}),
})
},