feat(viewer): thumbnails drawn at load, kept on disk by hash; no picture crashes it
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
Tiles draw a thumbnail, not the file: the top of the first page, 560 pixels wide (never scaled up) and at most 420 tall, rendered by two workers of their own so opening a file never waits behind them. Every file's thumbnail starts when the books load, before the documents page is opened, and the live viewer keeps each as <sha>.png in $XDG_CACHE_HOME (else ~/.cache)/wanderbooks/thumbs/v1-560 (private to the user, written whole and renamed into place), so the next launch reads small PNGs, not PDFs. A file's name is its content's hash, so a thumbnail always matches the file the books hold; the blob is still read through the verifying store each time, so a corrupt or missing file is an error, never a kept picture. From review: a picture or page past the device's largest texture is scaled to fit (egui panicked on it, in the full view too); a renderer panic is that file's error, not the end of its worker; a thumbnail asked for before the cache moved is dropped, never shown over a newer one; text thumbnails keep 2 KiB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
This commit is contained in:
4 files changed
+454
-36
No files matched your search
@@ -163,6 +163,7 @@ impl App {
|
||||
);
|
||||
let mut app = Self::bare(&cc.egui_ctx, scheme);
|
||||
app.filter = filter;
|
||||
app.receipts.thumb_dir = crate::receipts::thumb_dir();
|
||||
app.loader = Some(Loader::spawn(source, cc.egui_ctx.clone()));
|
||||
app
|
||||
}
|
||||
@@ -170,6 +171,7 @@ impl App {
|
||||
/// An app showing fixed books (tests and screenshots).
|
||||
pub fn with_books(ctx: &egui::Context, books: Books, dark: bool, start: Route) -> Self {
|
||||
let mut app = Self::bare(ctx, schemes::own(dark));
|
||||
app.receipts.prefetch(&books);
|
||||
app.books = Some(Arc::new(books));
|
||||
app.nav = Nav::new(start);
|
||||
app
|
||||
@@ -369,6 +371,22 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
/// Keep thumbnails on disk in `dir` (the live viewer keeps them in
|
||||
/// the user's cache directory, `wanderbooks/thumbs`); tests point it
|
||||
/// at their own.
|
||||
pub fn keep_thumbs_in(&mut self, dir: std::path::PathBuf) {
|
||||
self.receipts.thumb_dir = Some(dir);
|
||||
self.receipts.forget_thumbs();
|
||||
if let Some(b) = self.books.clone() {
|
||||
self.receipts.prefetch(&b);
|
||||
}
|
||||
}
|
||||
|
||||
/// The size in pixels of a file's thumbnail, once drawn (tests).
|
||||
pub fn thumb_size(&self, sha: &str) -> Option<[usize; 2]> {
|
||||
self.receipts.thumb_size(sha)
|
||||
}
|
||||
|
||||
/// Block until every receipt on screen has rendered (screenshots).
|
||||
pub fn settle(&mut self, ctx: &egui::Context) {
|
||||
self.receipts.settle(ctx);
|
||||
@@ -1622,6 +1640,7 @@ impl eframe::App for App {
|
||||
if self.books.is_some() {
|
||||
self.updated_at = ui.input(|i| i.time);
|
||||
}
|
||||
self.receipts.prefetch(&b);
|
||||
self.books = Some(b);
|
||||
self.error = None;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user