dnd works in library now too
Some checks failed
/ test (push) Has been cancelled

This commit is contained in:
Chris Cochrun 2025-10-02 15:15:33 -05:00
parent 894c68338d
commit 7f30b4395f
2 changed files with 190 additions and 89 deletions

View file

@ -1,4 +1,4 @@
use std::{error::Error, fmt::Display}; use std::{error::Error, fmt::Display, path::PathBuf};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -21,6 +21,29 @@ pub enum ServiceItemKind {
Content(Slide), Content(Slide),
} }
impl TryFrom<PathBuf> for ServiceItemKind {
type Error = miette::Error;
fn try_from(path: PathBuf) -> Result<Self, Self::Error> {
let ext = path
.extension()
.map(|ext| ext.to_str())
.flatten()
.ok_or(miette::miette!(
"There isn't an extension on this file"
))?;
match ext {
"png" | "jpg" | "jpeg" => {
Ok(Self::Image(Image::from(path)))
}
"mp4" | "mkv" | "webm" => {
Ok(Self::Video(Video::from(path)))
}
_ => Err(miette::miette!("Unknown item")),
}
}
}
impl ServiceItemKind { impl ServiceItemKind {
pub fn title(&self) -> String { pub fn title(&self) -> String {
match self { match self {

View file

@ -31,7 +31,7 @@ use crate::core::{
self, Presentation, add_presentation_to_db, self, Presentation, add_presentation_to_db,
update_presentation_in_db, update_presentation_in_db,
}, },
service_items::{ServiceItem, ServiceTrait}, service_items::ServiceItem,
songs::{self, Song, update_song_in_db}, songs::{self, Song, update_song_in_db},
videos::{self, Video, update_video_in_db}, videos::{self, Video, update_video_in_db},
}; };
@ -100,6 +100,7 @@ pub enum Message {
Error(String), Error(String),
OpenContext(i32), OpenContext(i32),
None, None,
AddFiles(Vec<ServiceItemKind>),
AddImages(Option<Vec<Image>>), AddImages(Option<Vec<Image>>),
AddVideos(Option<Vec<Video>>), AddVideos(Option<Vec<Video>>),
AddPresentations(Option<Vec<Presentation>>), AddPresentations(Option<Vec<Presentation>>),
@ -561,6 +562,55 @@ impl<'a> Library {
self.selected_items = Some(items.to_vec()); self.selected_items = Some(items.to_vec());
self.context_menu = Some(index); self.context_menu = Some(index);
} }
Message::AddFiles(items) => {
for item in items {
match item {
ServiceItemKind::Song(song) => {
let Some(e) = self
.song_library
.add_item(song)
.err()
else {
continue;
};
error!(?e);
}
ServiceItemKind::Video(video) => {
let Some(e) = self
.video_library
.add_item(video)
.err()
else {
continue;
};
error!(?e);
}
ServiceItemKind::Image(image) => {
let Some(e) = self
.image_library
.add_item(image)
.err()
else {
continue;
};
error!(?e);
}
ServiceItemKind::Presentation(
presentation,
) => {
let Some(e) = self
.presentation_library
.add_item(presentation)
.err()
else {
continue;
};
error!(?e);
}
ServiceItemKind::Content(slide) => todo!(),
}
}
}
} }
Action::None Action::None
} }
@ -572,7 +622,7 @@ impl<'a> Library {
let presentation_library = let presentation_library =
self.library_item(&self.presentation_library); self.library_item(&self.presentation_library);
column![ let library_column = column![
text::heading("Library").center().width(Length::Fill), text::heading("Library").center().width(Length::Fill),
cosmic::iced::widget::horizontal_rule(1), cosmic::iced::widget::horizontal_rule(1),
song_library, song_library,
@ -582,8 +632,67 @@ impl<'a> Library {
] ]
.height(Length::Fill) .height(Length::Fill)
.padding(10) .padding(10)
.spacing(10) .spacing(10);
.into() let library_dnd = dnd_destination(
library_column,
vec![
"image/png".into(),
"image/jpg".into(),
"image/heif".into(),
"image/gif".into(),
"video/mp4".into(),
"video/AV1".into(),
"video/H264".into(),
"video/H265".into(),
"video/mpeg".into(),
"video/mkv".into(),
"video/webm".into(),
"video/ogg".into(),
"video/vnd.youtube.yt".into(),
"video/x-matroska".into(),
"application/pdf".into(),
"text/html".into(),
"text/md".into(),
"text/org".into(),
"text/uri-list".into(),
],
)
.on_enter(|_, _, mimes| {
warn!(?mimes);
Message::None
})
.on_finish(|mime, data, action, _, _| {
// warn!(?mime, ?data, ?action);
match mime.as_str() {
"text/uri-list" => {
let Ok(text) = str::from_utf8(&data) else {
return Message::None;
};
let mut items = Vec::new();
for line in text.lines() {
let Ok(url) = url::Url::parse(line) else {
error!(
?line,
"problem parsing this file url"
);
continue;
};
let Ok(path) = url.to_file_path() else {
error!(?url, "invalid file URL");
continue;
};
let item = ServiceItemKind::try_from(path);
match item {
Ok(item) => items.push(item),
Err(e) => error!(?e),
}
}
Message::AddFiles(items)
}
_ => Message::None,
}
});
container(library_dnd).padding(2).into()
} }
pub fn library_item<T>( pub fn library_item<T>(
@ -767,38 +876,7 @@ impl<'a> Library {
); );
let library_column = let library_column =
column![library_toolbar, items].spacing(3); column![library_toolbar, items].spacing(3);
let library_dnd = dnd_destination( Container::new(library_column).padding(5)
library_column,
vec![
"image/png".into(),
"image/jpg".into(),
"image/heif".into(),
"image/gif".into(),
"video/mp4".into(),
"video/AV1".into(),
"video/H264".into(),
"video/H265".into(),
"video/mpeg".into(),
"video/mkv".into(),
"video/webm".into(),
"video/ogg".into(),
"video/vnd.youtube.yt".into(),
"video/x-matroska".into(),
"application/pdf".into(),
"text/html".into(),
"text/md".into(),
"text/org".into(),
],
)
.on_enter(|_, _, mimes| {
warn!(?mimes);
Message::None
})
.on_finish(|mime, data, action, _, _| {
warn!(?mime, ?data, ?action);
Message::None
});
Container::new(library_dnd).padding(5)
} else { } else {
Container::new(Space::new(0, 0)) Container::new(Space::new(0, 0))
}; };