commit 4413e185072a7b960b6f018bd2dc2eb4e479ac88
parent 3b9d3338499bace951a2ba4c487ff892992419e2
Author: kernelkind <kernelkind@gmail.com>
Date: Sat, 22 Nov 2025 22:31:11 -0700
refactor: remove unnecessary old JobsCache code
Signed-off-by: kernelkind <kernelkind@gmail.com>
Diffstat:
9 files changed, 15 insertions(+), 1060 deletions(-)
diff --git a/crates/notedeck/src/imgcache.rs b/crates/notedeck/src/imgcache.rs
@@ -1,5 +1,5 @@
use crate::jobs::MediaJobSender;
-use crate::media::gif::{ensure_latest_texture_from_cache, AnimatedImgTexCache};
+use crate::media::gif::AnimatedImgTexCache;
use crate::media::images::ImageType;
use crate::media::static_imgs::StaticImgTexCache;
use crate::media::{
@@ -12,13 +12,11 @@ use crate::RenderableMedia;
use crate::Result;
use egui::TextureHandle;
use image::{Delay, Frame};
-use poll_promise::Promise;
use egui::ColorImage;
use std::collections::HashMap;
use std::fs::{self, create_dir_all, File};
-use std::sync::mpsc::Receiver;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant, SystemTime};
use std::{io, thread};
@@ -29,85 +27,6 @@ use std::path::PathBuf;
use std::path::{self, Path};
use tracing::warn;
-#[derive(Default)]
-pub struct TexturesCacheOld {
- pub cache: hashbrown::HashMap<String, TextureStateInternal>,
-}
-
-impl TexturesCacheOld {
- pub fn handle_and_get_or_insert_loadable(
- &mut self,
- url: &str,
- closure: impl FnOnce() -> Promise<Option<Result<TexturedImage>>>,
- ) -> LoadableTextureState<'_> {
- let internal = self.handle_and_get_state_internal(url, true, closure);
-
- internal.into()
- }
-
- pub fn handle_and_get_or_insert(
- &mut self,
- url: &str,
- closure: impl FnOnce() -> Promise<Option<Result<TexturedImage>>>,
- ) -> TextureStateOld<'_> {
- let internal = self.handle_and_get_state_internal(url, false, closure);
-
- internal.into()
- }
-
- fn handle_and_get_state_internal(
- &mut self,
- url: &str,
- use_loading: bool,
- closure: impl FnOnce() -> Promise<Option<Result<TexturedImage>>>,
- ) -> &mut TextureStateInternal {
- let state = match self.cache.raw_entry_mut().from_key(url) {
- hashbrown::hash_map::RawEntryMut::Occupied(entry) => {
- let state = entry.into_mut();
- handle_occupied(state, use_loading);
-
- state
- }
- hashbrown::hash_map::RawEntryMut::Vacant(entry) => {
- let res = closure();
- let (_, state) = entry.insert(url.to_owned(), TextureStateInternal::Pending(res));
-
- state
- }
- };
-
- state
- }
-
- pub fn insert_pending(&mut self, url: &str, promise: Promise<Option<Result<TexturedImage>>>) {
- self.cache
- .insert(url.to_owned(), TextureStateInternal::Pending(promise));
- }
-
- pub fn move_to_loaded(&mut self, url: &str) {
- let hashbrown::hash_map::RawEntryMut::Occupied(entry) =
- self.cache.raw_entry_mut().from_key(url)
- else {
- return;
- };
-
- entry.replace_entry_with(|_, v| {
- let TextureStateInternal::Loading(textured) = v else {
- return Some(v);
- };
-
- Some(TextureStateInternal::Loaded(textured))
- });
- }
-
- pub fn get_and_handle(&mut self, url: &str) -> Option<LoadableTextureState<'_>> {
- self.cache.get_mut(url).map(|state| {
- handle_occupied(state, true);
- state.into()
- })
- }
-}
-
pub struct TexturesCache {
pub static_image: StaticImgTexCache,
pub blurred: BlurCache,
@@ -128,55 +47,6 @@ impl TexturesCache {
}
}
-fn handle_occupied(state: &mut TextureStateInternal, use_loading: bool) {
- let TextureStateInternal::Pending(promise) = state else {
- return;
- };
-
- let Some(res) = promise.ready_mut() else {
- return;
- };
-
- let Some(res) = res.take() else {
- tracing::error!("Failed to take the promise");
- *state =
- TextureStateInternal::Error(crate::Error::Generic("Promise already taken".to_owned()));
- return;
- };
-
- match res {
- Ok(textured) => {
- *state = if use_loading {
- TextureStateInternal::Loading(textured)
- } else {
- TextureStateInternal::Loaded(textured)
- }
- }
- Err(e) => *state = TextureStateInternal::Error(e),
- }
-}
-
-pub enum LoadableTextureState<'a> {
- Pending,
- Error(&'a crate::Error),
- Loading {
- actual_image_tex: &'a mut TexturedImage,
- }, // the texture is in the loading state, for transitioning between the pending and loaded states
- Loaded(&'a mut TexturedImage),
-}
-
-pub enum TextureStateOld<'a> {
- Pending,
- Error(&'a crate::Error),
- Loaded(&'a mut TexturedImage),
-}
-
-impl<'a> TextureStateOld<'a> {
- pub fn is_loaded(&self) -> bool {
- matches!(self, Self::Loaded(_))
- }
-}
-
pub enum TextureState<T> {
Pending,
Error(crate::Error),
@@ -193,75 +63,6 @@ impl<T> std::fmt::Debug for TextureState<T> {
}
}
-impl<'a> From<&'a mut TextureStateInternal> for TextureStateOld<'a> {
- fn from(value: &'a mut TextureStateInternal) -> Self {
- match value {
- TextureStateInternal::Pending(_) => TextureStateOld::Pending,
- TextureStateInternal::Error(error) => TextureStateOld::Error(error),
- TextureStateInternal::Loading(textured_image) => {
- TextureStateOld::Loaded(textured_image)
- }
- TextureStateInternal::Loaded(textured_image) => TextureStateOld::Loaded(textured_image),
- }
- }
-}
-
-pub enum TextureStateInternal {
- Pending(Promise<Option<Result<TexturedImage>>>),
- Error(crate::Error),
- Loading(TexturedImage), // the image is in the loading state, for transitioning between blur and image
- Loaded(TexturedImage),
-}
-
-impl<'a> From<&'a mut TextureStateInternal> for LoadableTextureState<'a> {
- fn from(value: &'a mut TextureStateInternal) -> Self {
- match value {
- TextureStateInternal::Pending(_) => LoadableTextureState::Pending,
- TextureStateInternal::Error(error) => LoadableTextureState::Error(error),
- TextureStateInternal::Loading(textured_image) => LoadableTextureState::Loading {
- actual_image_tex: textured_image,
- },
- TextureStateInternal::Loaded(textured_image) => {
- LoadableTextureState::Loaded(textured_image)
- }
- }
- }
-}
-
-pub enum TexturedImage {
- Static(TextureHandle),
- Animated(AnimationOld),
-}
-
-impl TexturedImage {
- pub fn get_first_texture(&self) -> &TextureHandle {
- match self {
- TexturedImage::Static(texture_handle) => texture_handle,
- TexturedImage::Animated(animation) => &animation.first_frame.texture,
- }
- }
-}
-
-pub struct AnimationOld {
- pub first_frame: TextureFrame,
- pub other_frames: Vec<TextureFrame>,
- pub receiver: Option<Receiver<TextureFrame>>,
-}
-
-impl AnimationOld {
- pub fn get_frame(&self, index: usize) -> Option<&TextureFrame> {
- if index == 0 {
- Some(&self.first_frame)
- } else {
- self.other_frames.get(index - 1)
- }
- }
-
- pub fn num_frames(&self) -> usize {
- self.other_frames.len() + 1
- }
-}
-
pub struct Animation {
pub first_frame: TextureFrame,
pub other_frames: Vec<TextureFrame>,
@@ -293,7 +94,6 @@ pub struct ImageFrame {
pub struct MediaCache {
pub cache_dir: path::PathBuf,
- pub textures_cache: TexturesCacheOld,
pub cache_type: MediaCacheType,
pub cache_size: Arc<Mutex<Option<u64>>>,
}
@@ -327,7 +127,6 @@ impl MediaCache {
Self {
cache_dir,
- textures_cache: TexturesCacheOld::default(),
cache_type,
cache_size,
}
@@ -431,7 +230,6 @@ impl MediaCache {
}
fn clear(&mut self) {
- self.textures_cache.cache.clear();
*self.cache_size.try_lock().unwrap() = Some(0);
}
}
@@ -523,42 +321,6 @@ impl Images {
})
}
- pub fn latest_texture_old(
- &mut self,
- ui: &mut egui::Ui,
- url: &str,
- img_type: ImageType,
- animation_mode: AnimationMode,
- ) -> Option<TextureHandle> {
- let cache_type = crate::urls::supported_mime_hosted_at_url(&mut self.urls, url)?;
-
- let cache_dir = self.get_cache(cache_type).cache_dir.clone();
- let is_loaded = self
- .get_cache_mut(cache_type)
- .textures_cache
- .handle_and_get_or_insert(url, || {
- crate::media::images::fetch_img(&cache_dir, ui.ctx(), url, img_type, cache_type)
- })
- .is_loaded();
-
- if !is_loaded {
- return None;
- }
-
- let cache = match cache_type {
- MediaCacheType::Image => &mut self.static_imgs,
- MediaCacheType::Gif => &mut self.gifs,
- };
-
- ensure_latest_texture_from_cache(
- ui,
- url,
- &mut self.gif_states,
- &mut cache.textures_cache,
- animation_mode,
- )
- }
-
pub fn latest_texture<'a>(
&'a mut self,
jobs: &MediaJobSender,
@@ -655,31 +417,3 @@ pub struct LatestTexture {
pub texture: TextureHandle,
pub request_next_repaint: Option<SystemTime>,
}
-
-#[profiling::function]
-pub fn get_render_state<'a>(
- ctx: &egui::Context,
- images: &'a mut Images,
- cache_type: MediaCacheType,
- url: &str,
- img_type: ImageType,
-) -> RenderState<'a> {
- let cache = match cache_type {
- MediaCacheType::Image => &mut images.static_imgs,
- MediaCacheType::Gif => &mut images.gifs,
- };
-
- let texture_state = cache.textures_cache.handle_and_get_or_insert(url, || {
- crate::media::images::fetch_img(&cache.cache_dir, ctx, url, img_type, cache_type)
- });
-
- RenderState {
- texture_state,
- gifs: &mut images.gif_states,
- }
-}
-
-pub struct RenderState<'a> {
- pub texture_state: TextureStateOld<'a>,
- pub gifs: &'a mut GifStateMap,
-}
diff --git a/crates/notedeck/src/jobs/cache_old.rs b/crates/notedeck/src/jobs/cache_old.rs
@@ -1,154 +0,0 @@
-use egui::TextureHandle;
-use hashbrown::{hash_map::RawEntryMut, HashMap};
-use poll_promise::Promise;
-
-use crate::jobs::JobPool;
-
-#[derive(Default)]
-pub struct JobsCacheOld {
- jobs: HashMap<JobIdOwned, JobState>,
-}
-
-pub enum JobState {
- Pending(Promise<Option<Result<Job, JobError>>>),
- Error(JobError),
- Completed(Job),
-}
-
-pub enum JobError {
- InvalidParameters,
-}
-
-#[derive(Debug)]
-pub enum JobParams<'a> {
- Blurhash(BlurhashParams<'a>),
-}
-
-#[derive(Debug)]
-pub enum JobParamsOwned {
- Blurhash(BlurhashParamsOwned),
-}
-
-impl<'a> From<BlurhashParams<'a>> for BlurhashParamsOwned {
- fn from(params: BlurhashParams<'a>) -> Self {
- BlurhashParamsOwned {
- blurhash: params.blurhash.to_owned(),
- url: params.url.to_owned(),
- ctx: params.ctx.clone(),
- }
- }
-}
-
-impl<'a> From<JobParams<'a>> for JobParamsOwned {
- fn from(params: JobParams<'a>) -> Self {
- match params {
- JobParams::Blurhash(bp) => JobParamsOwned::Blurhash(bp.into()),
- }
- }
-}
-
-#[derive(Debug)]
-pub struct BlurhashParams<'a> {
- pub blurhash: &'a str,
- pub url: &'a str,
- pub ctx: &'a egui::Context,
-}
-
-#[derive(Debug)]
-pub struct BlurhashParamsOwned {
- pub blurhash: String,
- pub url: String,
- pub ctx: egui::Context,
-}
-
-impl JobsCacheOld {
- pub fn get_or_insert_with<
- 'a,
- F: FnOnce(Option<JobParamsOwned>) -> Result<Job, JobError> + Send + 'static,
- >(
- &'a mut self,
- job_pool: &mut JobPool,
- jobid: &JobIdOld,
- params: Option<JobParams>,
- run_job: F,
- ) -> &'a mut JobState {
- match self.jobs.raw_entry_mut().from_key(jobid) {
- RawEntryMut::Occupied(entry) => 's: {
- let mut state = entry.into_mut();
-
- let JobState::Pending(promise) = &mut state else {
- break 's state;
- };
-
- let Some(res) = promise.ready_mut() else {
- break 's state;
- };
-
- let Some(res) = res.take() else {
- tracing::error!("Failed to take the promise for job: {:?}", jobid);
- break 's state;
- };
-
- *state = match res {
- Ok(j) => JobState::Completed(j),
- Err(e) => JobState::Error(e),
- };
-
- state
- }
- RawEntryMut::Vacant(entry) => {
- let owned_params = params.map(JobParams::into);
- let wrapped: Box<dyn FnOnce() -> Option<Result<Job, JobError>> + Send + 'static> =
- Box::new(move || Some(run_job(owned_params)));
-
- let promise = Promise::spawn_async(job_pool.schedule(wrapped));
-
- let (_, state) = entry.insert(jobid.into(), JobState::Pending(promise));
-
- state
- }
- }
- }
-
- pub fn get(&self, jobid: &JobIdOld) -> Option<&JobState> {
- self.jobs.get(jobid)
- }
-}
-
-impl<'a> From<&JobIdOld<'a>> for JobIdOwned {
- fn from(jobid: &JobIdOld<'a>) -> Self {
- match jobid {
- JobIdOld::Blurhash(s) => JobIdOwned::Blurhash(s.to_string()),
- }
- }
-}
-
-impl hashbrown::Equivalent<JobIdOwned> for JobIdOld<'_> {
- fn equivalent(&self, key: &JobIdOwned) -> bool {
- match (self, key) {
- (JobIdOld::Blurhash(a), JobIdOwned::Blurhash(b)) => *a == b.as_str(),
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Hash)]
-enum JobIdOwned {
- Blurhash(String), // image URL
-}
-
-#[derive(Debug, Hash)]
-pub enum JobIdOld<'a> {
- Blurhash(&'a str), // image URL
-}
-
-pub enum Job {
- Blurhash(Option<TextureHandle>),
-}
-
-impl std::fmt::Debug for Job {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Job::Blurhash(_) => write!(f, "Blurhash"),
- }
- }
-}
diff --git a/crates/notedeck/src/jobs/mod.rs b/crates/notedeck/src/jobs/mod.rs
@@ -1,5 +1,4 @@
mod cache;
-mod cache_old;
mod job_pool;
mod media;
pub(crate) mod types;
@@ -8,9 +7,6 @@ pub use crate::jobs::types::{
CompleteResponse, JobOutput, JobPackage, JobRun, NoOutputRun, RunType,
};
pub use cache::JobCache;
-pub use cache_old::{
- BlurhashParams, Job, JobError, JobIdOld, JobParams, JobParamsOwned, JobState, JobsCacheOld,
-};
pub use job_pool::JobPool;
pub use media::{
deliver_completed_media_job, run_media_job_pre_action, MediaJobKind, MediaJobResult,
diff --git a/crates/notedeck/src/lib.rs b/crates/notedeck/src/lib.rs
@@ -54,18 +54,16 @@ pub use filter::{FilterState, FilterStates, UnifiedSubscription};
pub use fonts::NamedFontFamily;
pub use i18n::{CacheStats, FluentArgs, FluentValue, LanguageIdentifier, Localization};
pub use imgcache::{
- get_render_state, Animation, AnimationOld, GifState, GifStateMap, ImageFrame, Images,
- LatestTexture, LoadableTextureState, MediaCache, MediaCacheType, RenderState, TextureFrame,
- TextureState, TextureStateOld, TexturedImage, TexturesCache, TexturesCacheOld,
+ Animation, GifState, GifStateMap, ImageFrame, Images, LatestTexture, MediaCache,
+ MediaCacheType, TextureFrame, TextureState, TexturesCache,
};
pub use jobs::{
- deliver_completed_media_job, run_media_job_pre_action, BlurhashParams, Job, JobCache, JobError,
- JobIdOld, JobParams, JobParamsOwned, JobPool, JobState, JobsCacheOld, MediaJobSender,
+ deliver_completed_media_job, run_media_job_pre_action, JobCache, JobPool, MediaJobSender,
MediaJobs,
};
pub use media::{
- compute_blurhash, update_imeta_blurhashes, ImageMetadata, ImageType, MediaAction,
- ObfuscationType, PixelDimensions, PointDimensions, RenderableMedia,
+ update_imeta_blurhashes, ImageMetadata, ImageType, MediaAction, ObfuscationType,
+ PixelDimensions, PointDimensions, RenderableMedia,
};
pub use muted::{MuteFun, Muted};
pub use name::NostrName;
diff --git a/crates/notedeck/src/media/blur.rs b/crates/notedeck/src/media/blur.rs
@@ -5,8 +5,8 @@ use nostrdb::Note;
use crate::{
jobs::{
- CompleteResponse, Job, JobError, JobOutput, JobPackage, JobParamsOwned, JobRun,
- MediaJobKind, MediaJobResult, MediaJobSender, RunType,
+ CompleteResponse, JobOutput, JobPackage, JobRun, MediaJobKind, MediaJobResult,
+ MediaJobSender, RunType,
},
media::load_texture_checked,
TextureState,
@@ -170,33 +170,6 @@ pub enum ObfuscationType {
Default,
}
-pub fn compute_blurhash(
- params: Option<JobParamsOwned>,
- dims: PixelDimensions,
-) -> Result<Job, JobError> {
- #[allow(irrefutable_let_patterns)]
- let Some(JobParamsOwned::Blurhash(params)) = params
- else {
- return Err(JobError::InvalidParameters);
- };
-
- let maybe_handle = match generate_blurhash_texturehandle(
- ¶ms.ctx,
- ¶ms.blurhash,
- ¶ms.url,
- dims.x,
- dims.y,
- ) {
- Ok(tex) => Some(tex),
- Err(e) => {
- tracing::error!("failed to render blurhash: {e}");
- None
- }
- };
-
- Ok(Job::Blurhash(maybe_handle))
-}
-
fn generate_blurhash_texturehandle(
ctx: &egui::Context,
blurhash: &str,
diff --git a/crates/notedeck/src/media/gif.rs b/crates/notedeck/src/media/gif.rs
@@ -2,10 +2,10 @@ use std::{
collections::{HashMap, VecDeque},
io::Cursor,
path::PathBuf,
- sync::mpsc::TryRecvError,
time::{Instant, SystemTime},
};
+use crate::GifState;
use crate::{
jobs::{
CompleteResponse, JobOutput, JobPackage, JobRun, MediaJobKind, MediaJobResult,
@@ -15,125 +15,13 @@ use crate::{
images::{buffer_to_color_image, process_image},
load_texture_checked,
},
- AnimationOld, Error, ImageFrame, ImageType, MediaCache, TextureFrame, TextureState,
+ Error, ImageFrame, ImageType, MediaCache, TextureFrame, TextureState,
};
use crate::{media::AnimationMode, Animation};
-use crate::{GifState, GifStateMap, TextureStateOld, TexturedImage, TexturesCacheOld};
use egui::{ColorImage, TextureHandle};
use image::{codecs::gif::GifDecoder, AnimationDecoder, DynamicImage, Frame};
use std::time::Duration;
-pub fn ensure_latest_texture_from_cache(
- ui: &egui::Ui,
- url: &str,
- gifs: &mut GifStateMap,
- textures: &mut TexturesCacheOld,
- animation_mode: AnimationMode,
-) -> Option<TextureHandle> {
- let tstate = textures.cache.get_mut(url)?;
-
- let TextureStateOld::Loaded(img) = tstate.into() else {
- return None;
- };
-
- Some(ensure_latest_texture(ui, url, gifs, img, animation_mode))
-}
-
-struct ProcessedGifFrameOld {
- texture: TextureHandle,
- maybe_new_state: Option<GifState>,
- repaint_at: Option<SystemTime>,
-}
-
-/// Process a gif state frame, and optionally present a new
-/// state and when to repaint it
-fn process_gif_frame_old(
- animation: &AnimationOld,
- frame_state: Option<&GifState>,
- animation_mode: AnimationMode,
-) -> ProcessedGifFrameOld {
- let now = Instant::now();
-
- match frame_state {
- Some(prev_state) => {
- let should_advance = animation_mode.can_animate()
- && (now - prev_state.last_frame_rendered >= prev_state.last_frame_duration);
-
- if should_advance {
- let maybe_new_index = if animation.receiver.is_some()
- || prev_state.last_frame_index < animation.num_frames() - 1
- {
- prev_state.last_frame_index + 1
- } else {
- 0
- };
-
- match animation.get_frame(maybe_new_index) {
- Some(frame) => {
- let next_frame_time = match animation_mode {
- AnimationMode::Continuous { fps } => match fps {
- Some(fps) => {
- let max_delay_ms = Duration::from_millis((1000.0 / fps) as u64);
- SystemTime::now().checked_add(frame.delay.max(max_delay_ms))
- }
- None => SystemTime::now().checked_add(frame.delay),
- },
-
- AnimationMode::NoAnimation | AnimationMode::Reactive => None,
- };
-
- ProcessedGifFrameOld {
- texture: frame.texture.clone(),
- maybe_new_state: Some(GifState {
- last_frame_rendered: now,
- last_frame_duration: frame.delay,
- next_frame_time,
- last_frame_index: maybe_new_index,
- }),
- repaint_at: next_frame_time,
- }
- }
- None => {
- let (texture, maybe_new_state) =
- match animation.get_frame(prev_state.last_frame_index) {
- Some(frame) => (frame.texture.clone(), None),
- None => (animation.first_frame.texture.clone(), None),
- };
-
- ProcessedGifFrameOld {
- texture,
- maybe_new_state,
- repaint_at: prev_state.next_frame_time,
- }
- }
- }
- } else {
- let (texture, maybe_new_state) =
- match animation.get_frame(prev_state.last_frame_index) {
- Some(frame) => (frame.texture.clone(), None),
- None => (animation.first_frame.texture.clone(), None),
- };
-
- ProcessedGifFrameOld {
- texture,
- maybe_new_state,
- repaint_at: prev_state.next_frame_time,
- }
- }
- }
- None => ProcessedGifFrameOld {
- texture: animation.first_frame.texture.clone(),
- maybe_new_state: Some(GifState {
- last_frame_rendered: now,
- last_frame_duration: animation.first_frame.delay,
- next_frame_time: None,
- last_frame_index: 0,
- }),
- repaint_at: None,
- },
- }
-}
-
pub(crate) struct ProcessedGifFrame<'a> {
pub texture: &'a TextureHandle,
pub maybe_new_state: Option<GifState>,
@@ -221,49 +109,6 @@ pub(crate) fn process_gif_frame<'a>(
}
}
-pub fn ensure_latest_texture(
- ui: &egui::Ui,
- url: &str,
- gifs: &mut GifStateMap,
- img: &mut TexturedImage,
- animation_mode: AnimationMode,
-) -> TextureHandle {
- match img {
- TexturedImage::Static(handle) => handle.clone(),
- TexturedImage::Animated(animation) => {
- if let Some(receiver) = &animation.receiver {
- loop {
- match receiver.try_recv() {
- Ok(frame) => animation.other_frames.push(frame),
- Err(TryRecvError::Empty) => {
- break;
- }
- Err(TryRecvError::Disconnected) => {
- animation.receiver = None;
- break;
- }
- }
- }
- }
-
- let next_state = process_gif_frame_old(animation, gifs.get(url), animation_mode);
-
- if let Some(new_state) = next_state.maybe_new_state {
- gifs.insert(url.to_owned(), new_state);
- }
-
- if let Some(repaint) = next_state.repaint_at {
- tracing::trace!("requesting repaint for {url} after {repaint:?}");
- if let Ok(dur) = repaint.duration_since(SystemTime::now()) {
- ui.ctx().request_repaint_after(dur);
- }
- }
-
- next_state.texture
- }
- }
-}
-
pub struct AnimatedImgTexCache {
pub(crate) cache: HashMap<String, TextureState<Animation>>,
animated_img_cache_path: PathBuf,
diff --git a/crates/notedeck/src/media/images.rs b/crates/notedeck/src/media/images.rs
@@ -1,20 +1,8 @@
-use crate::media::load_texture_checked;
use crate::media::network::HyperHttpResponse;
-use crate::{AnimationOld, ImageFrame, MediaCache, MediaCacheType, TextureFrame, TexturedImage};
-use egui::{pos2, Color32, ColorImage, Context, Rect, Sense, SizeHint};
-use image::codecs::gif::GifDecoder;
+use egui::{pos2, Color32, ColorImage, Rect, Sense, SizeHint};
use image::imageops::FilterType;
-use image::{AnimationDecoder, DynamicImage, FlatSamples, Frame};
-use poll_promise::Promise;
-use std::collections::VecDeque;
-use std::io::Cursor;
+use image::FlatSamples;
use std::path::PathBuf;
-use std::path::{self, Path};
-use std::sync::mpsc;
-use std::sync::mpsc::SyncSender;
-use std::thread;
-use std::time::Duration;
-use tokio::fs;
// NOTE(jb55): chatgpt wrote this because I was too dumb to
pub fn aspect_fill(
@@ -185,34 +173,6 @@ pub fn process_image(imgtyp: ImageType, mut image: image::DynamicImage) -> Color
}
#[profiling::function]
-fn parse_img_response_old(
- response: ehttp::Response,
- imgtyp: ImageType,
-) -> Result<ColorImage, crate::Error> {
- let content_type = response.content_type().unwrap_or_default();
- let size_hint = match imgtyp {
- ImageType::Profile(size) => SizeHint::Size(size, size),
- ImageType::Content(Some((w, h))) => SizeHint::Size(w, h),
- ImageType::Content(None) => SizeHint::default(),
- };
-
- if content_type.starts_with("image/svg") {
- profiling::scope!("load_svg");
-
- let mut color_image =
- egui_extras::image::load_svg_bytes_with_size(&response.bytes, Some(size_hint))?;
- round_image(&mut color_image);
- Ok(color_image)
- } else if content_type.starts_with("image/") {
- profiling::scope!("load_from_memory");
- let dyn_image = image::load_from_memory(&response.bytes)?;
- Ok(process_image(imgtyp, dyn_image))
- } else {
- Err(format!("Expected image, found content-type {content_type:?}").into())
- }
-}
-
-#[profiling::function]
pub fn parse_img_response(
response: HyperHttpResponse,
imgtyp: ImageType,
@@ -240,166 +200,6 @@ pub fn parse_img_response(
}
}
-fn fetch_img_from_disk(
- ctx: &egui::Context,
- url: &str,
- path: &path::Path,
- cache_type: MediaCacheType,
-) -> Promise<Option<Result<TexturedImage, crate::Error>>> {
- let ctx = ctx.clone();
- let url = url.to_owned();
- let path = path.to_owned();
-
- Promise::spawn_async(async move {
- Some(async_fetch_img_from_disk(ctx, url, &path, cache_type).await)
- })
-}
-
-async fn async_fetch_img_from_disk(
- ctx: egui::Context,
- url: String,
- path: &path::Path,
- cache_type: MediaCacheType,
-) -> Result<TexturedImage, crate::Error> {
- match cache_type {
- MediaCacheType::Image => {
- let data = fs::read(path).await?;
- let image_buffer = image::load_from_memory(&data).map_err(crate::Error::Image)?;
-
- let img = buffer_to_color_image(
- image_buffer.as_flat_samples_u8(),
- image_buffer.width(),
- image_buffer.height(),
- );
- Ok(TexturedImage::Static(load_texture_checked(
- &ctx,
- &url,
- img,
- Default::default(),
- )))
- }
- MediaCacheType::Gif => {
- let gif_bytes = fs::read(path).await?; // Read entire file into a Vec<u8>
- generate_gif(ctx, url, path, gif_bytes, false, |i| {
- buffer_to_color_image(i.as_flat_samples_u8(), i.width(), i.height())
- })
- }
- }
-}
-
-fn generate_gif(
- ctx: egui::Context,
- url: String,
- path: &path::Path,
- data: Vec<u8>,
- write_to_disk: bool,
- process_to_egui: impl Fn(DynamicImage) -> ColorImage + Send + Copy + 'static,
-) -> Result<TexturedImage, crate::Error> {
- let decoder = {
- let reader = Cursor::new(data.as_slice());
- GifDecoder::new(reader)?
- };
- let (tex_input, tex_output) = mpsc::sync_channel(4);
- let (maybe_encoder_input, maybe_encoder_output) = if write_to_disk {
- let (inp, out) = mpsc::sync_channel(4);
- (Some(inp), Some(out))
- } else {
- (None, None)
- };
-
- let mut frames: VecDeque<Frame> = decoder
- .into_frames()
- .collect::<std::result::Result<VecDeque<_>, image::ImageError>>()
- .map_err(|e| crate::Error::Generic(e.to_string()))?;
-
- let first_frame = frames.pop_front().map(|frame| {
- generate_animation_frame(
- &ctx,
- &url,
- 0,
- frame,
- maybe_encoder_input.as_ref(),
- process_to_egui,
- )
- });
-
- let cur_url = url.clone();
- thread::spawn(move || {
- for (index, frame) in frames.into_iter().enumerate() {
- let texture_frame = generate_animation_frame(
- &ctx,
- &cur_url,
- index,
- frame,
- maybe_encoder_input.as_ref(),
- process_to_egui,
- );
-
- if tex_input.send(texture_frame).is_err() {
- //tracing::debug!("AnimationTextureFrame mpsc stopped abruptly");
- break;
- }
- }
- });
-
- if let Some(encoder_output) = maybe_encoder_output {
- let path = path.to_owned();
-
- thread::spawn(move || {
- let mut imgs = Vec::new();
- while let Ok(img) = encoder_output.recv() {
- imgs.push(img);
- }
-
- if let Err(e) = MediaCache::write_gif(&path, &url, imgs) {
- tracing::error!("Could not write gif to disk: {e}");
- }
- });
- }
-
- first_frame.map_or_else(
- || {
- Err(crate::Error::Generic(
- "first frame not found for gif".to_owned(),
- ))
- },
- |first_frame| {
- Ok(TexturedImage::Animated(AnimationOld {
- other_frames: Default::default(),
- receiver: Some(tex_output),
- first_frame,
- }))
- },
- )
-}
-
-fn generate_animation_frame(
- ctx: &egui::Context,
- url: &str,
- index: usize,
- frame: image::Frame,
- maybe_encoder_input: Option<&SyncSender<ImageFrame>>,
- process_to_egui: impl Fn(DynamicImage) -> ColorImage + Send + 'static,
-) -> TextureFrame {
- let delay = Duration::from(frame.delay());
- let img = DynamicImage::ImageRgba8(frame.into_buffer());
- let color_img = process_to_egui(img);
-
- if let Some(sender) = maybe_encoder_input {
- if let Err(e) = sender.send(ImageFrame {
- delay,
- image: color_img.clone(),
- }) {
- tracing::error!("ImageFrame mpsc unexpectedly closed: {e}");
- }
- }
-
- TextureFrame {
- delay,
- texture: load_texture_checked(ctx, format!("{url}{index}"), color_img, Default::default()),
- }
-}
-
pub fn buffer_to_color_image(
samples: Option<FlatSamples<&[u8]>>,
width: u32,
@@ -422,89 +222,3 @@ pub enum ImageType {
/// Content Image with optional size hint
Content(Option<(u32, u32)>),
}
-
-pub fn fetch_img(
- img_cache_path: &Path,
- ctx: &egui::Context,
- url: &str,
- imgtyp: ImageType,
- cache_type: MediaCacheType,
-) -> Promise<Option<Result<TexturedImage, crate::Error>>> {
- let key = MediaCache::key(url);
- let path = img_cache_path.join(key);
-
- if path.exists() {
- fetch_img_from_disk(ctx, url, &path, cache_type)
- } else {
- fetch_img_from_net(img_cache_path, ctx, url, imgtyp, cache_type)
- }
-
- // TODO: fetch image from local cache
-}
-
-fn fetch_img_from_net(
- cache_path: &path::Path,
- ctx: &egui::Context,
- url: &str,
- imgtyp: ImageType,
- cache_type: MediaCacheType,
-) -> Promise<Option<Result<TexturedImage, crate::Error>>> {
- let (sender, promise) = Promise::new();
- let request = ehttp::Request::get(url);
- let ctx = ctx.clone();
- let cloned_url = url.to_owned();
- let cache_path = cache_path.to_owned();
- ehttp::fetch(request, move |response| {
- let handle = response.map_err(crate::Error::Generic).and_then(|resp| {
- match cache_type {
- MediaCacheType::Image => {
- let img = parse_img_response_old(resp, imgtyp);
- img.map(|img| {
- let texture_handle = load_texture_checked(
- &ctx,
- &cloned_url,
- img.clone(),
- Default::default(),
- );
-
- // write to disk
- std::thread::spawn(move || {
- MediaCache::write(&cache_path, &cloned_url, img)
- });
-
- TexturedImage::Static(texture_handle)
- })
- }
- MediaCacheType::Gif => {
- let gif_bytes = resp.bytes;
- generate_gif(
- ctx.clone(),
- cloned_url,
- &cache_path,
- gif_bytes,
- true,
- move |img| process_image(imgtyp, img),
- )
- }
- }
- });
-
- sender.send(Some(handle)); // send the results back to the UI thread.
- ctx.request_repaint();
- });
-
- promise
-}
-
-pub fn fetch_no_pfp_promise(
- ctx: &Context,
- cache: &MediaCache,
-) -> Promise<Option<Result<TexturedImage, crate::Error>>> {
- crate::media::images::fetch_img(
- &cache.cache_dir,
- ctx,
- crate::profile::no_pfp_url(),
- ImageType::Profile(128),
- MediaCacheType::Image,
- )
-}
diff --git a/crates/notedeck/src/media/mod.rs b/crates/notedeck/src/media/mod.rs
@@ -10,8 +10,8 @@ pub mod static_imgs;
pub use action::{MediaAction, MediaInfo, ViewMediaInfo};
pub use blur::{
- compute_blurhash, update_imeta_blurhashes, BlurCache, ImageMetadata, ObfuscationType,
- PixelDimensions, PointDimensions,
+ update_imeta_blurhashes, BlurCache, ImageMetadata, ObfuscationType, PixelDimensions,
+ PointDimensions,
};
use egui::{ColorImage, TextureHandle};
pub use images::ImageType;
diff --git a/crates/notedeck_ui/src/note/media.rs b/crates/notedeck_ui/src/note/media.rs
@@ -1,15 +1,10 @@
-use std::path::Path;
-
use bitflags::bitflags;
use egui::{
vec2, Button, Color32, Context, CornerRadius, FontId, Image, InnerResponse, Response,
TextureHandle, Vec2,
};
use notedeck::media::latest::ObfuscatedTexture;
-use notedeck::{
- compute_blurhash, BlurhashParams, Job, JobIdOld, JobParams, JobPool, JobState, JobsCacheOld,
- MediaJobSender, ObfuscationType, PointDimensions, TexturedImage, TexturesCacheOld,
-};
+use notedeck::MediaJobSender;
use notedeck::{
fonts::get_font_size, show_one_error_message, tr, Images, Localization, MediaAction,
MediaCacheType, NotedeckTextStyle, RenderableMedia,
@@ -217,115 +212,6 @@ impl MediaUIAction {
}
}
-#[allow(clippy::too_many_arguments)]
-pub fn get_content_media_render_state<'a>(
- ui: &mut egui::Ui,
- job_pool: &'a mut JobPool,
- jobs: &'a mut JobsCacheOld,
- media_trusted: bool,
- size: Vec2,
- cache: &'a mut TexturesCacheOld,
- url: &'a str,
- cache_type: MediaCacheType,
- cache_dir: &Path,
- obfuscation_type: &'a ObfuscationType,
-) -> MediaRenderStateOld<'a> {
- let render_type = if media_trusted {
- cache.handle_and_get_or_insert_loadable(url, || {
- notedeck::media::images::fetch_img(
- cache_dir,
- ui.ctx(),
- url,
- ImageType::Content(None),
- cache_type,
- )
- })
- } else if let Some(render_type) = cache.get_and_handle(url) {
- render_type
- } else {
- return MediaRenderStateOld::Obfuscated(get_obfuscated(
- ui,
- url,
- obfuscation_type,
- job_pool,
- jobs,
- size,
- ));
- };
-
- match render_type {
- notedeck::LoadableTextureState::Pending => MediaRenderStateOld::Shimmering(get_obfuscated(
- ui,
- url,
- obfuscation_type,
- job_pool,
- jobs,
- size,
- )),
- notedeck::LoadableTextureState::Error(e) => MediaRenderStateOld::Error(e),
- notedeck::LoadableTextureState::Loading { actual_image_tex } => {
- let obfuscation = get_obfuscated(ui, url, obfuscation_type, job_pool, jobs, size);
- MediaRenderStateOld::Transitioning {
- image: actual_image_tex,
- obfuscation,
- }
- }
- notedeck::LoadableTextureState::Loaded(textured_image) => {
- MediaRenderStateOld::ActualImage(textured_image)
- }
- }
-}
-
-fn get_obfuscated<'a>(
- ui: &mut egui::Ui,
- url: &str,
- obfuscation_type: &'a ObfuscationType,
- job_pool: &'a mut JobPool,
- jobs: &'a mut JobsCacheOld,
- size: Vec2,
-) -> ObfuscatedTextureOld<'a> {
- let ObfuscationType::Blurhash(renderable_blur) = obfuscation_type else {
- return ObfuscatedTextureOld::Default;
- };
-
- let params = BlurhashParams {
- blurhash: &renderable_blur.blurhash,
- url,
- ctx: ui.ctx(),
- };
-
- let available_points = PointDimensions {
- x: size.x,
- y: size.y,
- };
-
- let pixel_sizes = renderable_blur.scaled_pixel_dimensions(ui, available_points);
-
- let job_state = jobs.get_or_insert_with(
- job_pool,
- &JobIdOld::Blurhash(url),
- Some(JobParams::Blurhash(params)),
- move |params| compute_blurhash(params, pixel_sizes),
- );
-
- let JobState::Completed(m_blur_job) = job_state else {
- return ObfuscatedTextureOld::Default;
- };
-
- #[allow(irrefutable_let_patterns)]
- let Job::Blurhash(m_texture_handle) = m_blur_job
- else {
- tracing::error!("Did not get the correct job type: {:?}", m_blur_job);
- return ObfuscatedTextureOld::Default;
- };
-
- let Some(texture_handle) = m_texture_handle else {
- return ObfuscatedTextureOld::Default;
- };
-
- ObfuscatedTextureOld::Blur(texture_handle)
-}
-
fn copy_link(i18n: &mut Localization, url: &str, img_resp: &Response) {
img_resp.context_menu(|ui| {
if ui
@@ -556,43 +442,6 @@ fn render_default_blur_bg(
response
}
-pub enum MediaRenderStateOld<'a> {
- ActualImage(&'a mut TexturedImage),
- Transitioning {
- image: &'a mut TexturedImage,
- obfuscation: ObfuscatedTextureOld<'a>,
- },
- Error(&'a notedeck::Error),
- Shimmering(ObfuscatedTextureOld<'a>),
- Obfuscated(ObfuscatedTextureOld<'a>),
-}
-
-pub enum ObfuscatedTextureOld<'a> {
- Blur(&'a TextureHandle),
- Default,
-}
-
-/*
-pub(crate) fn find_renderable_media<'a>(
- urls: &mut UrlMimes,
- imeta: &'a HashMap<String, ImageMetadata>,
- url: &'a str,
-) -> Option<RenderableMedia> {
- let media_type = supported_mime_hosted_at_url(urls, url)?;
-
- let obfuscation_type = match imeta.get(url) {
- Some(blur) => ObfuscationType::Blurhash(blur.clone()),
- None => ObfuscationType::Default,
- };
-
- Some(RenderableMedia {
- url,
- media_type,
- obfuscation_type,
- })
-}
-*/
-
#[allow(clippy::too_many_arguments)]
fn render_success_media(
ui: &mut egui::Ui,