Skip to content

Commit eb88802

Browse files
committed
Implement image cache and background preloading of adjacent images to achieve instant navigation
1 parent 96c453b commit eb88802

2 files changed

Lines changed: 47 additions & 4 deletions

File tree

crates/media-sort-gui/src/app.rs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -555,11 +555,26 @@ pub fn update(state: &mut AppState, message: Message) -> Task<Message> {
555555
match result {
556556
Ok((w, h, pixels)) => {
557557
let handle = iced::widget::image::Handle::from_rgba(w, h, pixels);
558-
state.selected_image = Some((path, handle));
558+
state.image_cache.push(path.clone(), handle.clone());
559+
if let Some(idx) = state.selected_index {
560+
let entries = state.filtered_media_entries();
561+
if let Some(entry) = entries.get(idx) {
562+
if entry.path == path {
563+
state.selected_image = Some((path, handle));
564+
}
565+
}
566+
}
559567
}
560568
Err(err) => {
561569
log::error!("Failed to load full image: {err}");
562-
state.selected_image = None;
570+
if let Some(idx) = state.selected_index {
571+
let entries = state.filtered_media_entries();
572+
if let Some(entry) = entries.get(idx) {
573+
if entry.path == path {
574+
state.selected_image = None;
575+
}
576+
}
577+
}
563578
}
564579
}
565580
Task::none()
@@ -659,14 +674,39 @@ fn select_and_load_entry(state: &mut AppState, index: usize) -> Task<Message> {
659674
thumbnail_paths.push(filtered[i].path.clone());
660675
}
661676
}
677+
678+
// Pre-load the next and previous full images!
679+
let mut preload_tasks = Vec::new();
680+
if index + 1 < filtered_len {
681+
let next_entry = filtered[index + 1];
682+
if next_entry.media_type == media_sort_core::media_type::MediaType::Image && !state.image_cache.contains(&next_entry.path) {
683+
preload_tasks.push(load_full_image(next_entry.path.clone(), next_entry.media_type));
684+
}
685+
}
686+
if index > 0 {
687+
let prev_entry = filtered[index - 1];
688+
if prev_entry.media_type == media_sort_core::media_type::MediaType::Image && !state.image_cache.contains(&prev_entry.path) {
689+
preload_tasks.push(load_full_image(prev_entry.path.clone(), prev_entry.media_type));
690+
}
691+
}
692+
662693
drop(filtered);
663694

664695
state.selected_index = Some(index);
665696
state.current_metadata = None;
666-
state.selected_image = None;
667697

668698
let mut tasks = vec![load_metadata(state, index)];
669-
tasks.push(load_full_image(path, media_type));
699+
700+
if let Some(handle) = state.image_cache.get(&path) {
701+
state.selected_image = Some((path, handle.clone()));
702+
} else {
703+
state.selected_image = None;
704+
tasks.push(load_full_image(path, media_type));
705+
}
706+
707+
for t in preload_tasks {
708+
tasks.push(t);
709+
}
670710

671711
for p in thumbnail_paths {
672712
if !state.thumbnail_cache.contains(&p) {

crates/media-sort-gui/src/state.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub struct AppState {
3636
pub audio_player: Option<AudioPlayer>,
3737

3838
pub thumbnail_cache: LruCache<PathBuf, Vec<u8>>,
39+
pub image_cache: LruCache<PathBuf, iced::widget::image::Handle>,
3940
pub selected_folder: Option<PathBuf>,
4041
pub selected_image: Option<(PathBuf, iced::widget::image::Handle)>,
4142
pub renaming_path: Option<PathBuf>,
@@ -92,6 +93,7 @@ impl AppState {
9293
show_keybindings: false,
9394
audio_player,
9495
thumbnail_cache: LruCache::new(cache_size),
96+
image_cache: LruCache::new(NonZeroUsize::new(20).unwrap()),
9597
selected_folder: None,
9698
selected_image: None,
9799
renaming_path: None,
@@ -112,6 +114,7 @@ impl AppState {
112114
self.current_metadata = None;
113115
self.selected_folder = None;
114116
self.selected_image = None;
117+
self.image_cache.clear();
115118
}
116119

117120
pub fn scan_media(&mut self) {

0 commit comments

Comments
 (0)