feat: make pickers async
This commit is contained in:
parent
9d4e24e809
commit
18de039e77
2 changed files with 41 additions and 31 deletions
47
src/main.rs
47
src/main.rs
|
|
@ -1,4 +1,9 @@
|
|||
use std::{borrow::Cow, env, ffi::OsStr, path::Path};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
env,
|
||||
ffi::OsStr,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use iced::{
|
||||
Alignment, Color, Element, Length, Renderer, Subscription, Task, Theme, event,
|
||||
|
|
@ -12,7 +17,9 @@ mod utils;
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Message {
|
||||
ImagePicked(Result<PathBuf, String>),
|
||||
ImageDisplayReady(Result<widget::image::Allocation, widget::image::Error>),
|
||||
SavePathPicked(Result<PathBuf, String>),
|
||||
|
||||
Event(iced::Event),
|
||||
}
|
||||
|
|
@ -74,9 +81,26 @@ impl State {
|
|||
}
|
||||
fn update(&mut self, message: Message) -> Task<Message> {
|
||||
match message {
|
||||
Message::ImagePicked(result) => match result.and_then(|path| self.load_image(path)) {
|
||||
Err(e) => self.error = Some(e),
|
||||
Ok(task) => {
|
||||
self.error = None;
|
||||
return task;
|
||||
}
|
||||
},
|
||||
Message::ImageDisplayReady(result) => {
|
||||
self.image_display = Some(result.unwrap());
|
||||
}
|
||||
Message::SavePathPicked(result) => {
|
||||
self.error = result
|
||||
.and_then(|path| {
|
||||
self.image.as_ref().map_or_else(
|
||||
|| Err("no image to save".into()),
|
||||
|image| image.save(path).map_err(|e| e.to_string()),
|
||||
)
|
||||
})
|
||||
.err();
|
||||
}
|
||||
|
||||
Message::Event(iced::Event::Keyboard(keyboard::Event::KeyPressed {
|
||||
key,
|
||||
|
|
@ -91,13 +115,9 @@ impl State {
|
|||
return widget::operation::focus_next();
|
||||
}
|
||||
|
||||
Key::Character("o") => match self.pick_and_load_image() {
|
||||
Ok(task) => {
|
||||
self.error = None;
|
||||
return task;
|
||||
Key::Character("o") => {
|
||||
return Task::perform(utils::pick_image(), Message::ImagePicked);
|
||||
}
|
||||
Err(e) => self.error = Some(e),
|
||||
},
|
||||
|
||||
Key::Character("r") => match self.image.as_ref() {
|
||||
None => self.error = Some("no image to rotate".into()),
|
||||
|
|
@ -126,7 +146,11 @@ impl State {
|
|||
}
|
||||
|
||||
Key::Character("s") => {
|
||||
self.save_image();
|
||||
if self.image.is_some() {
|
||||
self.error = None;
|
||||
return Task::perform(utils::pick_save_path(), Message::SavePathPicked);
|
||||
}
|
||||
self.error = Some("no image to save".into());
|
||||
}
|
||||
|
||||
Key::Character("q") => return window::latest().and_then(window::close),
|
||||
|
|
@ -169,13 +193,6 @@ impl State {
|
|||
self.allocate_image()
|
||||
})
|
||||
}
|
||||
fn pick_and_load_image(&mut self) -> Result<Task<Message>, String> {
|
||||
utils::pick_image().and_then(|path| self.load_image(path))
|
||||
}
|
||||
|
||||
fn save_image(&mut self) {
|
||||
self.error = utils::save_image(self.image.as_ref()).err();
|
||||
}
|
||||
|
||||
fn allocate_image(&self) -> Task<Message> {
|
||||
let Some(image) = self.image.as_ref() else {
|
||||
|
|
|
|||
23
src/utils.rs
23
src/utils.rs
|
|
@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use iced::widget;
|
||||
use image::{DynamicImage, ImageDecoder, ImageReader, ImageResult, RgbaImage};
|
||||
use rfd::FileDialog;
|
||||
use rfd::AsyncFileDialog;
|
||||
|
||||
pub fn load_image(path: impl AsRef<Path>) -> Result<RgbaImage, String> {
|
||||
load_image_impl(path).map_err(|e| e.to_string())
|
||||
|
|
@ -20,8 +20,8 @@ fn load_image_impl(path: impl AsRef<Path>) -> ImageResult<RgbaImage> {
|
|||
|
||||
Ok(decoded_image.into_rgba8())
|
||||
}
|
||||
pub fn pick_image() -> Result<PathBuf, String> {
|
||||
let Some(path) = FileDialog::new()
|
||||
pub async fn pick_image() -> Result<PathBuf, String> {
|
||||
let Some(filehandle) = AsyncFileDialog::new()
|
||||
.add_filter(
|
||||
"image",
|
||||
&[
|
||||
|
|
@ -30,27 +30,20 @@ pub fn pick_image() -> Result<PathBuf, String> {
|
|||
],
|
||||
)
|
||||
.pick_file()
|
||||
.await
|
||||
else {
|
||||
return Err("no path to open provided".into());
|
||||
};
|
||||
|
||||
Ok(path)
|
||||
Ok(filehandle.path().to_owned())
|
||||
}
|
||||
|
||||
pub fn save_image(image: Option<&RgbaImage>) -> Result<(), String> {
|
||||
let Some(image) = image else {
|
||||
return Err("no image to save".into());
|
||||
};
|
||||
|
||||
let Some(path) = FileDialog::new().save_file() else {
|
||||
pub async fn pick_save_path() -> Result<PathBuf, String> {
|
||||
let Some(filehandle) = AsyncFileDialog::new().save_file().await else {
|
||||
return Err("no path to save provided".into());
|
||||
};
|
||||
|
||||
if let Err(e) = image.save(&path) {
|
||||
return Err(e.to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(filehandle.path().to_owned())
|
||||
}
|
||||
|
||||
pub const fn string_from_filter_type(f: widget::image::FilterMethod) -> &'static str {
|
||||
|
|
|
|||
Loading…
Reference in a new issue