diff --git a/Cargo.lock b/Cargo.lock index 2e7f40d..c61fd41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,6 +48,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + [[package]] name = "aligned" version = "0.4.3" @@ -490,6 +499,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bstr" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530" +dependencies = [ + "memchr", + "serde_core", +] + [[package]] name = "built" version = "0.8.1" @@ -1398,6 +1417,21 @@ dependencies = [ "slab", ] +[[package]] +name = "gallery" +version = "0.1.0" +dependencies = [ + "iced", + "ignore", + "image", + "jxl-oxide", + "kra-image-integration", + "rayon", + "rfd", + "size", + "zip", +] + [[package]] name = "gethostname" version = "1.1.0" @@ -1460,6 +1494,19 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" +[[package]] +name = "globset" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + [[package]] name = "glow" version = "0.16.0" @@ -1659,19 +1706,6 @@ dependencies = [ "thiserror 2.0.19", ] -[[package]] -name = "iced-template" -version = "0.1.0" -dependencies = [ - "iced", - "image", - "jxl-oxide", - "kra-image-integration", - "rfd", - "size", - "zip", -] - [[package]] name = "iced_core" version = "0.14.0" @@ -1842,6 +1876,22 @@ dependencies = [ "winit", ] +[[package]] +name = "ignore" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "image" version = "0.25.10" @@ -3536,6 +3586,23 @@ dependencies = [ "bitflags 2.13.1", ] +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + [[package]] name = "renderdoc-sys" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 181caf1..fe8ff82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,9 @@ edition = "2024" license = "AGPL-3.0-or-later" [dependencies] +ignore = "0.4.33" kra-image-integration = "0.1.0" +rayon = "1.12.0" rfd = "0.17.2" size = "0.5.0" zip = "8.6.0" diff --git a/src/app/mod.rs b/src/app/mod.rs index 6e662ab..7605a6e 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,26 +1,88 @@ +use std::{ + borrow::Cow, + collections::HashMap, + env, + path::{Path, PathBuf}, +}; + use iced::{Color, Element, Renderer, Task, Theme, application, theme, widget}; +use ignore::{WalkBuilder, types::TypesBuilder}; +use image::{DynamicImage, EncodableLayout, RgbaImage}; +use rayon::iter::{ParallelBridge, ParallelIterator}; + +use crate::SUPPORTED_TYPES; enum Message {} +#[derive(Default)] enum Mode { - Focused(usize), + Focused(PathBuf), + #[default] Gallery, } +#[derive(Default)] struct State { mode: Mode, + images: HashMap>, } impl State { fn new() -> Self { + let mut builder = TypesBuilder::new(); + builder.add_defaults(); + for ext in SUPPORTED_TYPES { + builder.add("supportedImages", ext).unwrap(); + } + builder.select("supportedImages"); + Self { mode: Mode::Gallery, + images: WalkBuilder::new( + env::args() + .nth(1) + .map(Cow::Owned) + .unwrap_or(Cow::Borrowed("./")) + .as_ref(), + ) + .types(builder.build().unwrap()) + .max_depth(Some(1)) + .build() + .par_bridge() + .filter_map(|r| { + r.inspect_err(|e| eprintln!("{e}")) + .ok() + .map(|entry| entry.into_path()) + }) + .filter(|path| path.is_file()) + .map(|path| { + let image = image::open(&path) + .inspect_err(|e| eprintln!("{e}")) + .ok() + .map(DynamicImage::into_rgba8); + let handle = image.as_ref().map(|image| { + widget::image::Handle::from_rgba(image.width(), image.height(), unsafe { + std::mem::transmute::<&[u8], &'static [u8]>(image.as_bytes()) + }) + }); + (path, image.map(|image| (image, handle.unwrap()))) + }) + .collect(), } } fn update(&mut self, message: Message) -> Task { Task::none() } fn view(&self) -> Element<'_, Message, Theme, Renderer> { - widget::text("hiiiiiii").into() + widget::scrollable(widget::column( + self.images + .iter() + .filter_map(|(_k, v)| v.as_ref()) + .map(|(_image, handle)| { + dbg!(); + widget::image(handle).into() + }), + )) + .into() } } diff --git a/src/main.rs b/src/main.rs index 2e13470..8a836ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,13 @@ mod app; +const SUPPORTED_TYPES: &[&str; 20] = &[ + "*.png", "*.PNG", "*.jpg", "*.JPG", "*.jpeg", "*.JPEG", "*.avif", "*.jxl", "*.bmp", "*.exr", + "*.ff", "*.gif", "*.hdr", "*.ico", "*.pnm", "*.qoi", "*.tga", "*.tiff", "*.webp", "*.kra", +]; + fn main() -> Result<(), impl std::error::Error> { + jxl_oxide::integration::register_image_decoding_hook(); + kra_image_integration::register(); + app::run() }