refactor: prepare for parrelel loading with MaybeImage

This commit is contained in:
electria 2026-08-09 14:40:30 -07:00
commit eaf0c674ab
Signed by: electria
SSH key fingerprint: SHA256:8LlB3ucPbBHqozqkhsNbaV5oG3SlzzqUj8FZDL6IPQs
2 changed files with 41 additions and 9 deletions

30
src/app/maybe_image.rs Normal file
View file

@ -0,0 +1,30 @@
use iced::{task, widget};
use image::DynamicImage;
#[derive(Clone, Debug, Default)]
pub enum MaybeImage {
#[default]
Unloaded,
Loading(task::Handle),
Loaded(widget::image::Handle),
}
impl MaybeImage {
pub fn handle(&self) -> Option<&widget::image::Handle> {
match self {
Self::Loaded(h) => Some(&h),
_ => None,
}
}
pub fn unload(&mut self) {
match self {
Self::Loading(task_handle) => task_handle.abort(),
_ => {}
}
*self = Self::Unloaded;
}
}
pub fn handle_from_image(image: DynamicImage) -> widget::image::Handle {
widget::image::Handle::from_rgba(image.width(), image.height(), image.into_rgba8().into_raw())
}

View file

@ -14,7 +14,9 @@ use ignore::{WalkBuilder, types::TypesBuilder};
use rayon::iter::{ParallelBridge, ParallelIterator};
use rfd::AsyncFileDialog;
use crate::SUPPORTED_TYPES;
use crate::{SUPPORTED_TYPES, app::maybe_image::MaybeImage};
mod maybe_image;
#[derive(Clone, Debug)]
enum Message {
@ -30,7 +32,7 @@ enum Message {
#[derive(Default)]
struct State {
images: BTreeMap<PathBuf, Option<widget::image::Handle>>,
images: BTreeMap<PathBuf, MaybeImage>,
columns: usize,
@ -56,12 +58,12 @@ impl State {
fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::LoadImage(path) => {
self.images
.entry(path.clone())
.and_modify(|e| *e = Some(widget::image::Handle::from_path(path)));
self.images.entry(path.clone()).and_modify(|e| {
*e = MaybeImage::Loaded(widget::image::Handle::from_path(path))
});
}
Message::UnloadImage(path) => {
self.images.entry(path).and_modify(|e| *e = None);
self.images.entry(path).and_modify(MaybeImage::unload);
}
Message::OpenImage(path) => {
@ -119,10 +121,10 @@ impl State {
fn view(&self) -> Element<'_, Message, Theme, Renderer> {
widget::column([
widget::scrollable(
widget::grid(self.images.iter().map(|(path, opt_handle)| {
widget::grid(self.images.iter().map(|(path, maybe_image)| {
widget::button(widget::column([
widget::container(
widget::sensor(opt_handle.as_ref().map_or_else(
widget::sensor(maybe_image.handle().map_or_else(
|| Element::from(widget::space()),
|handle| widget::image(handle).into(),
))
@ -184,7 +186,7 @@ impl State {
.map(|entry| entry.into_path())
})
.filter(|path| path.is_file())
.map(|path| (path, None))
.map(|path| (path, MaybeImage::Unloaded))
.collect();
}
}