diff --git a/flake.nix b/flake.nix index e4b3c3c..0589766 100644 --- a/flake.nix +++ b/flake.nix @@ -32,6 +32,8 @@ libxcb ] ++ lib.optionals stdenv.hostPlatform.isLinux [ + dbus.lib + vulkan-loader wayland ]; diff --git a/src/app/mod.rs b/src/app/mod.rs index 50a00b7..6033d8a 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,4 +1,10 @@ -use std::{borrow::Cow, collections::BTreeMap, env, path::PathBuf, process}; +use std::{ + borrow::Cow, + collections::BTreeMap, + env, + path::{Path, PathBuf}, + process, +}; use iced::{ Color, Element, Event, Length, Renderer, Subscription, Task, Theme, application, event, @@ -6,6 +12,7 @@ use iced::{ }; use ignore::{WalkBuilder, types::TypesBuilder}; use rayon::iter::{ParallelBridge, ParallelIterator}; +use rfd::AsyncFileDialog; use crate::SUPPORTED_TYPES; @@ -16,6 +23,8 @@ enum Message { OpenImage(PathBuf), + OpenPath(Option), + KeyPressed(keyboard::Key, keyboard::Modifiers), } @@ -29,37 +38,20 @@ struct State { } 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 { - columns: 3, - error: None, - images: WalkBuilder::new( + fn new() -> (Self, Task) { + ( + Self { + columns: 3, + error: None, + images: BTreeMap::new(), + }, + Task::done(Message::OpenPath(Some( 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| (path, None)) - .collect(), - } + .unwrap_or_else(|| String::from("./")) + .into(), + ))), + ) } fn update(&mut self, message: Message) -> Task { match message { @@ -80,6 +72,17 @@ impl State { .err() } + Message::OpenPath(opt_path) => { + self.error = match opt_path { + Some(_) => None, + None => Some("no path to open given".into()), + }; + + if let Some(path) = opt_path { + self.open_path(path); + } + } + Message::KeyPressed(key, modifiers) => match key.as_ref() { // input field cycling keyboard::Key::Named(keyboard::key::Named::Tab) => { @@ -90,6 +93,13 @@ impl State { }; } + keyboard::Key::Character("o") => { + return Task::perform( + async { AsyncFileDialog::new().pick_folder().await.map(Into::into) }, + Message::OpenPath, + ); + } + keyboard::Key::Character("=" | "+") => { self.columns = (self.columns + 1).clamp(1, 10) } @@ -157,6 +167,29 @@ impl State { _ => None, }) } + + fn open_path(&mut self, path: impl AsRef) { + let mut builder = TypesBuilder::new(); + builder.add_defaults(); + for ext in SUPPORTED_TYPES { + builder.add("supportedImages", ext).unwrap(); + } + builder.select("supportedImages"); + + self.images = WalkBuilder::new(path) + .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| (path, None)) + .collect(); + } } pub fn run() -> Result<(), impl std::error::Error> {