commit 330550581da465659d9e6446295db28a3790fb18
parent f3a3695b80630e357f339d5804d932dec8e89bce
Author: kernelkind <kernelkind@gmail.com>
Date: Sat, 22 Nov 2025 20:22:09 -0700
feat(blur): add BlurCache
Signed-off-by: kernelkind <kernelkind@gmail.com>
Diffstat:
2 files changed, 86 insertions(+), 3 deletions(-)
diff --git a/crates/notedeck/src/media/blur.rs b/crates/notedeck/src/media/blur.rs
@@ -1,10 +1,15 @@
use std::collections::HashMap;
+use egui::TextureHandle;
use nostrdb::Note;
use crate::{
- jobs::{Job, JobError, JobParamsOwned},
+ jobs::{
+ CompleteResponse, Job, JobError, JobOutput, JobPackage, JobParamsOwned, JobRun,
+ MediaJobKind, MediaJobResult, MediaJobSender, RunType,
+ },
media::load_texture_checked,
+ TextureState,
};
#[derive(Clone)]
@@ -205,3 +210,81 @@ fn generate_blurhash_texturehandle(
let img = egui::ColorImage::from_rgba_unmultiplied([width as usize, height as usize], &bytes);
Ok(load_texture_checked(ctx, url, img, Default::default()))
}
+
+#[derive(Default)]
+pub struct BlurCache {
+ pub(crate) cache: HashMap<String, BlurState>,
+}
+
+pub struct BlurState {
+ pub tex_state: TextureState<TextureHandle>,
+ pub finished_transitioning: bool,
+}
+
+impl From<TextureState<TextureHandle>> for BlurState {
+ fn from(value: TextureState<TextureHandle>) -> Self {
+ BlurState {
+ tex_state: value,
+ finished_transitioning: false,
+ }
+ }
+}
+
+impl BlurCache {
+ pub fn get(&self, url: &str) -> Option<&BlurState> {
+ self.cache.get(url)
+ }
+
+ pub fn get_or_request(
+ &self,
+ jobs: &MediaJobSender,
+ ui: &egui::Ui,
+ url: &str,
+ blurhash: &ImageMetadata,
+ size: egui::Vec2,
+ ) -> &BlurState {
+ if let Some(res) = self.cache.get(url) {
+ return res;
+ }
+
+ let available_points = PointDimensions {
+ x: size.x,
+ y: size.y,
+ };
+ let pixel_sizes = blurhash.scaled_pixel_dimensions(ui, available_points);
+ let blurhash = blurhash.blurhash.to_owned();
+ let url = url.to_owned();
+ let ctx = ui.ctx().clone();
+
+ if let Err(e) = jobs.send(JobPackage::new(
+ url.to_owned(),
+ MediaJobKind::Blurhash,
+ RunType::Output(JobRun::Sync(Box::new(move || {
+ tracing::trace!("Starting blur job for {url}");
+ let res = generate_blurhash_texturehandle(
+ &ctx,
+ &blurhash,
+ &url,
+ pixel_sizes.x,
+ pixel_sizes.y,
+ );
+ JobOutput::Complete(CompleteResponse::new(MediaJobResult::Blurhash(res)))
+ }))),
+ )) {
+ tracing::error!("{e}");
+ }
+
+ &BlurState {
+ tex_state: TextureState::Pending,
+ finished_transitioning: false,
+ }
+ }
+
+ pub fn finished_transitioning(&mut self, url: &str) {
+ let Some(state) = self.cache.get_mut(url) else {
+ return;
+ };
+
+ state.finished_transitioning = true;
+ }
+}
diff --git a/crates/notedeck/src/media/mod.rs b/crates/notedeck/src/media/mod.rs
@@ -8,8 +8,8 @@ pub mod renderable;
pub use action::{MediaAction, MediaInfo, ViewMediaInfo};
pub use blur::{
- compute_blurhash, update_imeta_blurhashes, ImageMetadata, ObfuscationType, PixelDimensions,
- PointDimensions,
+ compute_blurhash, update_imeta_blurhashes, BlurCache, ImageMetadata, ObfuscationType,
+ PixelDimensions, PointDimensions,
};
use egui::{ColorImage, TextureHandle};
pub use images::ImageType;