fixing some database and adding issues
This commit is contained in:
parent
7f30b4395f
commit
375cea2408
11 changed files with 709 additions and 392 deletions
|
|
@ -201,6 +201,27 @@ pub async fn remove_from_db(
|
|||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub async fn add_image_to_db(
|
||||
image: Image,
|
||||
db: PoolConnection<Sqlite>,
|
||||
) -> Result<()> {
|
||||
let path = image
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let mut db = db.detach();
|
||||
query!(
|
||||
r#"INSERT INTO images (title, file_path) VALUES ($1, $2)"#,
|
||||
image.title,
|
||||
path,
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_image_in_db(
|
||||
image: Image,
|
||||
db: PoolConnection<Sqlite>,
|
||||
|
|
@ -211,44 +232,6 @@ pub async fn update_image_in_db(
|
|||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let mut db = db.detach();
|
||||
let id = image.id;
|
||||
if let Err(e) = query!("SELECT id FROM images where id = $1", id)
|
||||
.fetch_one(&mut db)
|
||||
.await
|
||||
{
|
||||
if let Ok(ids) =
|
||||
query!("SELECT id FROM images").fetch_all(&mut db).await
|
||||
{
|
||||
let Some(mut max) = ids.iter().map(|r| r.id).max() else {
|
||||
return Err(miette::miette!("cannot find max id"));
|
||||
};
|
||||
debug!(?e, "Image not found");
|
||||
max += 1;
|
||||
let result = query!(
|
||||
r#"INSERT into images VALUES($1, $2, $3)"#,
|
||||
max,
|
||||
image.title,
|
||||
path,
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await
|
||||
.into_diagnostic();
|
||||
|
||||
return match result {
|
||||
Ok(_) => {
|
||||
debug!("should have been updated");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error! {?e};
|
||||
Err(e)
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return Err(miette::miette!("cannot find ids"));
|
||||
}
|
||||
};
|
||||
|
||||
debug!(?image, "should be been updated");
|
||||
let result = query!(
|
||||
r#"UPDATE images SET title = $2, file_path = $3 WHERE id = $1"#,
|
||||
|
|
|
|||
|
|
@ -310,7 +310,6 @@ pub async fn remove_from_db(
|
|||
pub async fn add_presentation_to_db(
|
||||
presentation: Presentation,
|
||||
db: PoolConnection<Sqlite>,
|
||||
id: i32,
|
||||
) -> Result<()> {
|
||||
let path = presentation
|
||||
.path
|
||||
|
|
@ -319,9 +318,8 @@ pub async fn add_presentation_to_db(
|
|||
.unwrap_or_default();
|
||||
let html = presentation.kind == PresKind::Html;
|
||||
let mut db = db.detach();
|
||||
let result = query!(
|
||||
r#"INSERT into presentations VALUES($1, $2, $3, $4)"#,
|
||||
id,
|
||||
query!(
|
||||
r#"INSERT INTO presentations (title, file_path, html) VALUES ($1, $2, $3)"#,
|
||||
presentation.title,
|
||||
path,
|
||||
html,
|
||||
|
|
@ -329,13 +327,6 @@ pub async fn add_presentation_to_db(
|
|||
.execute(&mut db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
if result.last_insert_rowid() != id as i64 {
|
||||
let rowid = result.last_insert_rowid();
|
||||
error!(
|
||||
rowid,
|
||||
id, "It appears that rowid and id aren't the same"
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -420,6 +420,51 @@ pub async fn remove_from_db(
|
|||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub async fn add_song_to_db(
|
||||
song: Song,
|
||||
db: PoolConnection<Sqlite>,
|
||||
) -> Result<()> {
|
||||
let mut db = db.detach();
|
||||
|
||||
let verse_order = {
|
||||
if let Some(vo) = song.verse_order {
|
||||
vo.into_iter()
|
||||
.map(|mut s| {
|
||||
s.push(' ');
|
||||
s
|
||||
})
|
||||
.collect::<String>()
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
};
|
||||
|
||||
let audio = song
|
||||
.audio
|
||||
.map(|a| a.to_str().unwrap_or_default().to_string());
|
||||
|
||||
let background = song
|
||||
.background
|
||||
.map(|b| b.path.to_str().unwrap_or_default().to_string());
|
||||
|
||||
query!(
|
||||
r#"INSERT INTO songs (title, lyrics, author, ccli, verse_order, audio, font, font_size, background) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)"#,
|
||||
song.title,
|
||||
song.lyrics,
|
||||
song.author,
|
||||
song.ccli,
|
||||
verse_order,
|
||||
audio,
|
||||
song.font,
|
||||
song.font_size,
|
||||
background
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_song_in_db(
|
||||
item: Song,
|
||||
db: PoolConnection<Sqlite>,
|
||||
|
|
|
|||
|
|
@ -236,6 +236,30 @@ pub async fn remove_from_db(
|
|||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub async fn add_video_to_db(
|
||||
video: Video,
|
||||
db: PoolConnection<Sqlite>,
|
||||
) -> Result<()> {
|
||||
let path = video
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let mut db = db.detach();
|
||||
query!(
|
||||
r#"INSERT INTO videos (title, file_path, start_time, end_time, loop) VALUES ($1, $2, $3, $4, $5)"#,
|
||||
video.title,
|
||||
path,
|
||||
video.start_time,
|
||||
video.end_time,
|
||||
video.looping
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_video_in_db(
|
||||
video: Video,
|
||||
db: PoolConnection<Sqlite>,
|
||||
|
|
@ -246,47 +270,6 @@ pub async fn update_video_in_db(
|
|||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let mut db = db.detach();
|
||||
let id = video.id;
|
||||
if let Err(e) = query!("SELECT id FROM videos where id = $1", id)
|
||||
.fetch_one(&mut db)
|
||||
.await
|
||||
{
|
||||
if let Ok(ids) =
|
||||
query!("SELECT id FROM videos").fetch_all(&mut db).await
|
||||
{
|
||||
let Some(mut max) = ids.iter().map(|r| r.id).max() else {
|
||||
return Err(miette::miette!("cannot find max id"));
|
||||
};
|
||||
debug!(?e, "Video not found");
|
||||
max += 1;
|
||||
let result = query!(
|
||||
r#"INSERT into videos VALUES($1, $2, $3, $4, $5, $6)"#,
|
||||
max,
|
||||
video.title,
|
||||
path,
|
||||
video.start_time,
|
||||
video.end_time,
|
||||
video.looping,
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await
|
||||
.into_diagnostic();
|
||||
|
||||
return match result {
|
||||
Ok(_) => {
|
||||
debug!("should have been updated");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error! {?e};
|
||||
Err(e)
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return Err(miette::miette!("cannot find ids"));
|
||||
}
|
||||
};
|
||||
|
||||
debug!(?video, "should be been updated");
|
||||
let result = query!(
|
||||
r#"UPDATE videos SET title = $2, file_path = $3, start_time = $4, end_time = $5, loop = $6 WHERE id = $1"#,
|
||||
|
|
|
|||
113
src/main.rs
113
src/main.rs
|
|
@ -5,6 +5,7 @@ use core::slide::{
|
|||
};
|
||||
use cosmic::app::context_drawer::ContextDrawer;
|
||||
use cosmic::app::{Core, Settings, Task};
|
||||
use cosmic::dialog::file_chooser::{self, save};
|
||||
use cosmic::iced::alignment::Vertical;
|
||||
use cosmic::iced::keyboard::{Key, Modifiers};
|
||||
use cosmic::iced::window::{Mode, Position};
|
||||
|
|
@ -14,15 +15,14 @@ use cosmic::iced::{
|
|||
};
|
||||
use cosmic::iced_core::text::Wrapping;
|
||||
use cosmic::iced_futures::Subscription;
|
||||
use cosmic::iced_widget::{column, row, stack};
|
||||
use cosmic::theme;
|
||||
use cosmic::iced_widget::{column, horizontal_rule, row, stack};
|
||||
use cosmic::widget::button::Catalog;
|
||||
use cosmic::widget::dnd_destination::dnd_destination;
|
||||
use cosmic::widget::menu::key_bind::Modifier;
|
||||
use cosmic::widget::menu::{ItemWidth, KeyBind};
|
||||
use cosmic::widget::nav_bar::nav_bar_style;
|
||||
use cosmic::widget::tooltip::Position as TPosition;
|
||||
use cosmic::widget::{Container, menu};
|
||||
use cosmic::widget::{Container, divider, menu};
|
||||
use cosmic::widget::{
|
||||
Space, button, context_menu, horizontal_space, mouse_area,
|
||||
nav_bar, nav_bar_toggle, responsive, scrollable, search_input,
|
||||
|
|
@ -30,10 +30,13 @@ use cosmic::widget::{
|
|||
};
|
||||
use cosmic::widget::{container, text};
|
||||
use cosmic::widget::{icon, slider};
|
||||
use cosmic::{Application, ApplicationExt, Element, executor};
|
||||
use cosmic::{
|
||||
Application, ApplicationExt, Element, dialog, executor,
|
||||
};
|
||||
use cosmic::{theme, widget};
|
||||
use crisp::types::Value;
|
||||
use lisp::parse_lisp;
|
||||
use miette::{Result, miette};
|
||||
use miette::{IntoDiagnostic, Result, miette};
|
||||
use rayon::prelude::*;
|
||||
use resvg::usvg::fontdb;
|
||||
use std::collections::HashMap;
|
||||
|
|
@ -49,6 +52,7 @@ use ui::presenter::{self, Presenter};
|
|||
use ui::song_editor::{self, SongEditor};
|
||||
|
||||
use crate::core::content::Content;
|
||||
use crate::core::file;
|
||||
use crate::core::kinds::ServiceItemKind;
|
||||
use crate::core::model::KindWrapper;
|
||||
use crate::ui::image_editor::{self, ImageEditor};
|
||||
|
|
@ -123,6 +127,7 @@ struct App {
|
|||
selected_items: Vec<usize>,
|
||||
current_item: (usize, usize),
|
||||
hovered_item: Option<usize>,
|
||||
hovered_dnd: Option<usize>,
|
||||
presentation_open: bool,
|
||||
cli_mode: bool,
|
||||
library: Option<Library>,
|
||||
|
|
@ -166,6 +171,7 @@ enum Message {
|
|||
SelectServiceItem(usize),
|
||||
AddSelectServiceItem(usize),
|
||||
HoveredServiceItem(Option<usize>),
|
||||
HoveredServiceDrop(Option<usize>),
|
||||
AddServiceItem(usize, KindWrapper),
|
||||
AddServiceItemsFiles(usize, Vec<ServiceItem>),
|
||||
RemoveServiceItem(usize),
|
||||
|
|
@ -183,8 +189,9 @@ enum Message {
|
|||
New,
|
||||
Open,
|
||||
OpenFile(PathBuf),
|
||||
Save(Option<PathBuf>),
|
||||
SaveAs,
|
||||
Save,
|
||||
SaveAsDialog,
|
||||
SaveAs(PathBuf),
|
||||
OpenSettings,
|
||||
ModifiersPressed(Modifiers),
|
||||
}
|
||||
|
|
@ -205,8 +212,8 @@ impl menu::Action for MenuAction {
|
|||
fn message(&self) -> Self::Message {
|
||||
match self {
|
||||
MenuAction::New => Message::New,
|
||||
MenuAction::Save => Message::Save(None),
|
||||
MenuAction::SaveAs => Message::SaveAs,
|
||||
MenuAction::Save => Message::Save,
|
||||
MenuAction::SaveAs => Message::SaveAsDialog,
|
||||
MenuAction::Open => Message::Open,
|
||||
MenuAction::OpenSettings => Message::OpenSettings,
|
||||
MenuAction::DeleteItem(index) => {
|
||||
|
|
@ -352,6 +359,7 @@ impl cosmic::Application for App {
|
|||
fontdb: Arc::clone(&fontdb),
|
||||
menu_keys,
|
||||
hovered_item: None,
|
||||
hovered_dnd: None,
|
||||
context_menu: None,
|
||||
modifiers_pressed: None,
|
||||
};
|
||||
|
|
@ -620,8 +628,8 @@ impl cosmic::Application for App {
|
|||
}
|
||||
iced::Event::Touch(_touch) => None,
|
||||
iced::Event::A11y(_id, _action_request) => None,
|
||||
iced::Event::Dnd(dnd_event) => {
|
||||
debug!(?dnd_event);
|
||||
iced::Event::Dnd(_dnd_event) => {
|
||||
// debug!(?dnd_event);
|
||||
None
|
||||
}
|
||||
iced::Event::PlatformSpecific(_platform_specific) => {
|
||||
|
|
@ -1139,6 +1147,10 @@ impl cosmic::Application for App {
|
|||
self.hovered_item = index;
|
||||
Task::none()
|
||||
}
|
||||
Message::HoveredServiceDrop(index) => {
|
||||
self.hovered_dnd = index;
|
||||
Task::none()
|
||||
}
|
||||
Message::SelectServiceItem(index) => {
|
||||
self.selected_items = vec![index];
|
||||
Task::none()
|
||||
|
|
@ -1234,6 +1246,7 @@ impl cosmic::Application for App {
|
|||
Task::none()
|
||||
}
|
||||
Message::AddServiceItemsFiles(index, items) => {
|
||||
self.hovered_dnd = None;
|
||||
for item in items {
|
||||
self.service.insert(index, item);
|
||||
}
|
||||
|
|
@ -1345,17 +1358,44 @@ impl cosmic::Application for App {
|
|||
debug!(?file, "opening file");
|
||||
Task::none()
|
||||
}
|
||||
Message::Save(file) => {
|
||||
let Some(file) = file else {
|
||||
debug!("saving current");
|
||||
return Task::none();
|
||||
};
|
||||
debug!(?file, "saving new file");
|
||||
Task::none()
|
||||
Message::Save => {
|
||||
let service = self.service.clone();
|
||||
let file = self.file.clone();
|
||||
Task::perform(
|
||||
file::save(service, file.clone()),
|
||||
move |res| match res {
|
||||
Ok(_) => {
|
||||
tracing::info!(
|
||||
"saving file to: {:?}",
|
||||
file
|
||||
);
|
||||
cosmic::Action::None
|
||||
}
|
||||
Err(e) => {
|
||||
error!(?e, "There was a problem saving");
|
||||
cosmic::Action::None
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
Message::SaveAs => {
|
||||
debug!("saving as a file");
|
||||
Task::none()
|
||||
Message::SaveAs(file) => {
|
||||
debug!(?file, "saving as a file");
|
||||
self.file = file;
|
||||
return self.update(Message::Save);
|
||||
}
|
||||
Message::SaveAsDialog => {
|
||||
Task::perform(save_as_dialog(), |file| match file {
|
||||
Ok(file) => {
|
||||
cosmic::Action::App(Message::SaveAs(file))
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
?e,
|
||||
"There was an error during saving"
|
||||
);
|
||||
cosmic::Action::None
|
||||
}
|
||||
})
|
||||
}
|
||||
Message::OpenSettings => {
|
||||
debug!("Opening settings");
|
||||
|
|
@ -1635,7 +1675,7 @@ where
|
|||
}
|
||||
match (key, modifiers) {
|
||||
(Key::Character(k), Modifiers::CTRL) if k == *"s" => {
|
||||
self.update(Message::Save(None))
|
||||
self.update(Message::Save)
|
||||
}
|
||||
(Key::Character(k), Modifiers::CTRL) if k == *"o" => {
|
||||
self.update(Message::Open)
|
||||
|
|
@ -1743,7 +1783,20 @@ where
|
|||
))
|
||||
})
|
||||
.width(Length::Fill);
|
||||
let mouse_area = mouse_area(container)
|
||||
let visual_item = if self.hovered_dnd.is_some_and(|h| h == index) {
|
||||
let divider = divider::horizontal::default().class(theme::Rule::custom(|t| {
|
||||
let color = t.cosmic().accent_color();
|
||||
let style = cosmic::iced_widget::rule::Style {
|
||||
color: color.into(),
|
||||
width: 2,
|
||||
radius: t.cosmic().corner_radii.radius_xs.into(),
|
||||
fill_mode: cosmic::iced_widget::rule::FillMode::Full,
|
||||
};
|
||||
style
|
||||
} ));
|
||||
Container::new(column![divider, container].spacing(theme::spacing().space_s))
|
||||
} else { container };
|
||||
let mouse_area = mouse_area(visual_item)
|
||||
.on_enter(Message::HoveredServiceItem(Some(
|
||||
index,
|
||||
)))
|
||||
|
|
@ -1797,6 +1850,8 @@ where
|
|||
tooltip,
|
||||
vec!["application/service-item".into(), "text/uri-list".into(), "x-special/gnome-copied-files".into()],
|
||||
)
|
||||
.on_enter(move |_, _, _| Message::HoveredServiceDrop(Some(index)))
|
||||
.on_leave(move || Message::HoveredServiceDrop(None))
|
||||
.on_finish(move |mime, data, _, _, _| {
|
||||
|
||||
match mime.as_str() {
|
||||
|
|
@ -1905,3 +1960,15 @@ where
|
|||
container.center(Length::FillPortion(2)).into()
|
||||
}
|
||||
}
|
||||
|
||||
async fn save_as_dialog() -> Result<PathBuf> {
|
||||
let dialog = save::Dialog::new();
|
||||
save::file(dialog).await.into_diagnostic().map(|response| {
|
||||
match response.url() {
|
||||
Some(url) => Ok(url.to_file_path().unwrap()),
|
||||
None => {
|
||||
Err(miette!("Can't convert url of file to a path"))
|
||||
}
|
||||
}
|
||||
})?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,9 +48,7 @@ impl ImageEditor {
|
|||
pub fn update(&mut self, message: Message) -> Action {
|
||||
match message {
|
||||
Message::ChangeImage(image) => {
|
||||
self.image = Some(image.clone());
|
||||
self.title = image.title.clone();
|
||||
return self.update(Message::Update(image));
|
||||
self.update_entire_image(&image);
|
||||
}
|
||||
Message::ChangeTitle(title) => {
|
||||
self.title = title.clone();
|
||||
|
|
@ -66,6 +64,7 @@ impl ImageEditor {
|
|||
}
|
||||
Message::Update(image) => {
|
||||
warn!(?image);
|
||||
self.update_entire_image(&image);
|
||||
return Action::UpdateImage(image);
|
||||
}
|
||||
Message::PickImage => {
|
||||
|
|
@ -80,7 +79,7 @@ impl ImageEditor {
|
|||
if let Ok(image) = image_result {
|
||||
let mut image = Image::from(image);
|
||||
image.id = image_id;
|
||||
Message::ChangeImage(image)
|
||||
Message::Update(image)
|
||||
} else {
|
||||
Message::None
|
||||
}
|
||||
|
|
@ -134,6 +133,11 @@ impl ImageEditor {
|
|||
pub const fn editing(&self) -> bool {
|
||||
self.editing
|
||||
}
|
||||
|
||||
fn update_entire_image(&mut self, image: &Image) {
|
||||
self.image = Some(image.clone());
|
||||
self.title = image.title.clone();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ImageEditor {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ use tracing::{debug, error, warn};
|
|||
|
||||
use crate::core::{
|
||||
content::Content,
|
||||
images::{self, Image, update_image_in_db},
|
||||
images::{self, Image, add_image_to_db, update_image_in_db},
|
||||
kinds::ServiceItemKind,
|
||||
model::{KindWrapper, LibraryKind, Model},
|
||||
presentations::{
|
||||
|
|
@ -32,8 +32,8 @@ use crate::core::{
|
|||
update_presentation_in_db,
|
||||
},
|
||||
service_items::ServiceItem,
|
||||
songs::{self, Song, update_song_in_db},
|
||||
videos::{self, Video, update_video_in_db},
|
||||
songs::{self, Song, add_song_to_db, update_song_in_db},
|
||||
videos::{self, Video, add_video_to_db, update_video_in_db},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -56,7 +56,7 @@ pub struct Library {
|
|||
#[derive(Debug, Clone, Eq, PartialEq, Copy)]
|
||||
enum MenuMessage {
|
||||
Delete,
|
||||
Open((LibraryKind, i32)),
|
||||
Open,
|
||||
}
|
||||
|
||||
impl MenuAction for MenuMessage {
|
||||
|
|
@ -65,9 +65,7 @@ impl MenuAction for MenuMessage {
|
|||
fn message(&self) -> Self::Message {
|
||||
match self {
|
||||
MenuMessage::Delete => Message::DeleteItem,
|
||||
MenuMessage::Open((kind, index)) => {
|
||||
Message::OpenItem(Some((*kind, *index)))
|
||||
}
|
||||
MenuMessage::Open => Message::OpenContextItem,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,6 +82,7 @@ pub enum Message {
|
|||
AddItem,
|
||||
DeleteItem,
|
||||
OpenItem(Option<(LibraryKind, i32)>),
|
||||
OpenContextItem,
|
||||
HoverLibrary(Option<LibraryKind>),
|
||||
OpenLibrary(Option<LibraryKind>),
|
||||
HoverItem(Option<(LibraryKind, i32)>),
|
||||
|
|
@ -180,37 +179,71 @@ impl<'a> Library {
|
|||
Message::AddVideos(videos) => {
|
||||
debug!(?videos);
|
||||
let mut index = self.video_library.items.len();
|
||||
// Check if empty
|
||||
let mut tasks = Vec::new();
|
||||
if let Some(videos) = videos {
|
||||
let len = videos.len();
|
||||
for video in videos {
|
||||
if let Err(e) =
|
||||
self.video_library.add_item(video)
|
||||
self.video_library.add_item(video.clone())
|
||||
{
|
||||
error!(?e);
|
||||
}
|
||||
let task = Task::future(self.db.acquire())
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_video_to_db(
|
||||
video.to_owned(),
|
||||
db,
|
||||
),
|
||||
move |res| {
|
||||
debug!(
|
||||
len,
|
||||
index, "added to db"
|
||||
);
|
||||
if let Err(e) = res {
|
||||
error!(?e);
|
||||
}
|
||||
if len == index {
|
||||
debug!("open the pres");
|
||||
Message::OpenItem(Some((
|
||||
LibraryKind::Video,
|
||||
index as i32,
|
||||
)))
|
||||
} else {
|
||||
Message::None
|
||||
}
|
||||
},
|
||||
)
|
||||
});
|
||||
tasks.push(task);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
return self.update(Message::OpenItem(Some((
|
||||
LibraryKind::Video,
|
||||
self.video_library.items.len() as i32 - 1,
|
||||
))));
|
||||
let after_task =
|
||||
Task::done(Message::OpenItem(Some((
|
||||
LibraryKind::Video,
|
||||
self.video_library.items.len() as i32 - 1,
|
||||
))));
|
||||
return Action::Task(
|
||||
Task::batch(tasks).chain(after_task),
|
||||
);
|
||||
}
|
||||
Message::AddPresentations(presentations) => {
|
||||
debug!(?presentations);
|
||||
let mut index = self.presentation_library.items.len();
|
||||
// Check if empty
|
||||
let mut tasks = Vec::new();
|
||||
if index == 0 {
|
||||
if let Some(presentations) = presentations {
|
||||
let len = presentations.len();
|
||||
for presentation in presentations {
|
||||
if let Err(e) = self
|
||||
.presentation_library
|
||||
.add_item(presentation.clone())
|
||||
{
|
||||
error!(?e);
|
||||
}
|
||||
let task = Task::future(
|
||||
if let Some(presentations) = presentations {
|
||||
let len = presentations.len();
|
||||
for presentation in presentations {
|
||||
if let Err(e) = self
|
||||
.presentation_library
|
||||
.add_item(presentation.clone())
|
||||
{
|
||||
error!(?e);
|
||||
}
|
||||
let task = Task::future(
|
||||
self.db.acquire(),
|
||||
)
|
||||
.and_then(move |db| {
|
||||
|
|
@ -218,7 +251,6 @@ impl<'a> Library {
|
|||
add_presentation_to_db(
|
||||
presentation.to_owned(),
|
||||
db,
|
||||
index as i32,
|
||||
),
|
||||
move |res| {
|
||||
debug!(
|
||||
|
|
@ -240,57 +272,93 @@ impl<'a> Library {
|
|||
},
|
||||
)
|
||||
});
|
||||
tasks.push(task);
|
||||
index += 1;
|
||||
}
|
||||
tasks.push(task);
|
||||
index += 1;
|
||||
}
|
||||
return Action::Task(Task::batch(tasks));
|
||||
} else {
|
||||
if let Some(presentations) = presentations {
|
||||
for presentation in presentations {
|
||||
if let Err(e) = self
|
||||
.presentation_library
|
||||
.add_item(presentation)
|
||||
{
|
||||
error!(?e);
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
return self.update(Message::OpenItem(Some((
|
||||
}
|
||||
let after_task =
|
||||
Task::done(Message::OpenItem(Some((
|
||||
LibraryKind::Presentation,
|
||||
self.presentation_library.items.len() as i32
|
||||
- 1,
|
||||
))));
|
||||
}
|
||||
return Action::Task(
|
||||
Task::batch(tasks).chain(after_task),
|
||||
);
|
||||
}
|
||||
Message::AddImages(images) => {
|
||||
debug!(?images);
|
||||
let mut index = self.image_library.items.len();
|
||||
// Check if empty
|
||||
let mut tasks = Vec::new();
|
||||
if let Some(images) = images {
|
||||
let len = images.len();
|
||||
for image in images {
|
||||
if let Err(e) =
|
||||
self.image_library.add_item(image)
|
||||
self.image_library.add_item(image.clone())
|
||||
{
|
||||
error!(?e);
|
||||
}
|
||||
let task = Task::future(self.db.acquire())
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_image_to_db(
|
||||
image.to_owned(),
|
||||
db,
|
||||
),
|
||||
move |res| {
|
||||
debug!(
|
||||
len,
|
||||
index, "added to db"
|
||||
);
|
||||
if let Err(e) = res {
|
||||
error!(?e);
|
||||
}
|
||||
if len == index {
|
||||
debug!("open the pres");
|
||||
Message::OpenItem(Some((
|
||||
LibraryKind::Image,
|
||||
index as i32,
|
||||
)))
|
||||
} else {
|
||||
Message::None
|
||||
}
|
||||
},
|
||||
)
|
||||
});
|
||||
tasks.push(task);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
return self.update(Message::OpenItem(Some((
|
||||
LibraryKind::Image,
|
||||
self.image_library.items.len() as i32 - 1,
|
||||
))));
|
||||
let after_task =
|
||||
Task::done(Message::OpenItem(Some((
|
||||
LibraryKind::Image,
|
||||
self.image_library.items.len() as i32 - 1,
|
||||
))));
|
||||
return Action::Task(
|
||||
Task::batch(tasks).chain(after_task),
|
||||
);
|
||||
}
|
||||
Message::OpenItem(item) => {
|
||||
debug!(?item);
|
||||
self.editing_item = item;
|
||||
return Action::OpenItem(item);
|
||||
}
|
||||
Message::OpenContextItem => {
|
||||
let Some(kind) = self.library_open else {
|
||||
return Action::None;
|
||||
};
|
||||
let Some(index) = self.context_menu else {
|
||||
return Action::None;
|
||||
};
|
||||
return self
|
||||
.update(Message::OpenItem(Some((kind, index))));
|
||||
}
|
||||
Message::HoverLibrary(library_kind) => {
|
||||
self.library_hovered = library_kind;
|
||||
}
|
||||
Message::OpenLibrary(library_kind) => {
|
||||
self.selected_items = None;
|
||||
self.library_open = library_kind;
|
||||
}
|
||||
Message::HoverItem(item) => {
|
||||
|
|
@ -549,6 +617,7 @@ impl<'a> Library {
|
|||
let Some(kind) = self.library_open else {
|
||||
return Action::None;
|
||||
};
|
||||
debug!(index, "should context");
|
||||
let Some(items) = self.selected_items.as_mut() else {
|
||||
self.selected_items = vec![(kind, index)].into();
|
||||
self.context_menu = Some(index);
|
||||
|
|
@ -556,21 +625,59 @@ impl<'a> Library {
|
|||
};
|
||||
|
||||
if items.contains(&(kind, index)) {
|
||||
debug!(index, "should context contained");
|
||||
self.selected_items = Some(items.to_vec());
|
||||
} else {
|
||||
items.push((kind, index));
|
||||
debug!(index, "should context not contained");
|
||||
self.selected_items = vec![(kind, index)].into();
|
||||
}
|
||||
self.selected_items = Some(items.to_vec());
|
||||
self.context_menu = Some(index);
|
||||
}
|
||||
Message::AddFiles(items) => {
|
||||
let mut tasks = Vec::new();
|
||||
let last_item = &items.last();
|
||||
let after_task = match last_item {
|
||||
Some(ServiceItemKind::Image(image)) => {
|
||||
Task::done(Message::OpenItem(Some((
|
||||
LibraryKind::Image,
|
||||
self.image_library.items.len() as i32 - 1,
|
||||
))))
|
||||
}
|
||||
_ => Task::none(),
|
||||
};
|
||||
for item in items {
|
||||
match item {
|
||||
ServiceItemKind::Song(song) => {
|
||||
let Some(e) = self
|
||||
.song_library
|
||||
.add_item(song)
|
||||
.add_item(song.clone())
|
||||
.err()
|
||||
else {
|
||||
let task = Task::future(
|
||||
self.db.acquire(),
|
||||
)
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_song_to_db(
|
||||
song.clone(),
|
||||
db,
|
||||
),
|
||||
{
|
||||
let song = song.clone();
|
||||
move |res| {
|
||||
debug!(
|
||||
?song,
|
||||
"added to db"
|
||||
);
|
||||
if let Err(e) = res {
|
||||
error!(?e);
|
||||
}
|
||||
Message::None
|
||||
}
|
||||
},
|
||||
)
|
||||
});
|
||||
tasks.push(task);
|
||||
continue;
|
||||
};
|
||||
error!(?e);
|
||||
|
|
@ -578,9 +685,34 @@ impl<'a> Library {
|
|||
ServiceItemKind::Video(video) => {
|
||||
let Some(e) = self
|
||||
.video_library
|
||||
.add_item(video)
|
||||
.add_item(video.clone())
|
||||
.err()
|
||||
else {
|
||||
let task = Task::future(
|
||||
self.db.acquire(),
|
||||
)
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_video_to_db(
|
||||
video.clone(),
|
||||
db,
|
||||
),
|
||||
{
|
||||
let video = video.clone();
|
||||
move |res| {
|
||||
debug!(
|
||||
?video,
|
||||
"added to db"
|
||||
);
|
||||
if let Err(e) = res {
|
||||
error!(?e);
|
||||
}
|
||||
Message::None
|
||||
}
|
||||
},
|
||||
)
|
||||
});
|
||||
tasks.push(task);
|
||||
continue;
|
||||
};
|
||||
error!(?e);
|
||||
|
|
@ -588,9 +720,34 @@ impl<'a> Library {
|
|||
ServiceItemKind::Image(image) => {
|
||||
let Some(e) = self
|
||||
.image_library
|
||||
.add_item(image)
|
||||
.add_item(image.clone())
|
||||
.err()
|
||||
else {
|
||||
let task = Task::future(
|
||||
self.db.acquire(),
|
||||
)
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_image_to_db(
|
||||
image.clone(),
|
||||
db,
|
||||
),
|
||||
{
|
||||
let image = image.clone();
|
||||
move |res| {
|
||||
debug!(
|
||||
?image,
|
||||
"added to db"
|
||||
);
|
||||
if let Err(e) = res {
|
||||
error!(?e);
|
||||
}
|
||||
Message::None
|
||||
}
|
||||
},
|
||||
)
|
||||
});
|
||||
tasks.push(task);
|
||||
continue;
|
||||
};
|
||||
error!(?e);
|
||||
|
|
@ -600,9 +757,35 @@ impl<'a> Library {
|
|||
) => {
|
||||
let Some(e) = self
|
||||
.presentation_library
|
||||
.add_item(presentation)
|
||||
.add_item(presentation.clone())
|
||||
.err()
|
||||
else {
|
||||
let task =
|
||||
Task::future(self.db.acquire())
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_presentation_to_db(
|
||||
presentation.clone(),
|
||||
db,
|
||||
),
|
||||
{
|
||||
let presentation =
|
||||
presentation.clone();
|
||||
move |res| {
|
||||
debug!(
|
||||
?presentation,
|
||||
"added to db"
|
||||
);
|
||||
if let Err(e) = res {
|
||||
error!(?e);
|
||||
}
|
||||
Message::None
|
||||
}
|
||||
},
|
||||
)
|
||||
});
|
||||
tasks.push(task);
|
||||
|
||||
continue;
|
||||
};
|
||||
error!(?e);
|
||||
|
|
@ -610,6 +793,9 @@ impl<'a> Library {
|
|||
ServiceItemKind::Content(slide) => todo!(),
|
||||
}
|
||||
}
|
||||
return Action::Task(
|
||||
Task::batch(tasks).chain(after_task),
|
||||
);
|
||||
}
|
||||
}
|
||||
Action::None
|
||||
|
|
@ -814,28 +1000,8 @@ impl<'a> Library {
|
|||
)),
|
||||
));
|
||||
|
||||
if let Some(context_id) = self.context_menu {
|
||||
if index == context_id as usize {
|
||||
let menu_items = vec![
|
||||
menu::Item::Button("Open", None, MenuMessage::Open((model.kind, index as i32))),
|
||||
menu::Item::Button("Delete", None, MenuMessage::Delete)
|
||||
];
|
||||
let context_menu = context_menu(
|
||||
mouse_area,
|
||||
self.context_menu.map_or_else(|| None, |_| {
|
||||
Some(menu::items(&self.menu_keys,
|
||||
menu_items))
|
||||
})
|
||||
);
|
||||
Element::from(context_menu)
|
||||
} else {
|
||||
Element::from(mouse_area)
|
||||
}
|
||||
} else {
|
||||
Element::from(mouse_area)
|
||||
}
|
||||
}
|
||||
)
|
||||
Element::from(mouse_area)
|
||||
})
|
||||
.action(DndAction::Copy)
|
||||
.drag_icon({
|
||||
let model = model.kind;
|
||||
|
|
@ -874,8 +1040,9 @@ impl<'a> Library {
|
|||
button::icon(icon::from_name("add"))
|
||||
.on_press(Message::AddItem)
|
||||
);
|
||||
let context_menu = self.context_menu(items.into());
|
||||
let library_column =
|
||||
column![library_toolbar, items].spacing(3);
|
||||
column![library_toolbar, context_menu].spacing(3);
|
||||
Container::new(library_column).padding(5)
|
||||
} else {
|
||||
Container::new(Space::new(0, 0))
|
||||
|
|
@ -993,6 +1160,34 @@ impl<'a> Library {
|
|||
.into()
|
||||
}
|
||||
|
||||
fn context_menu<'b>(
|
||||
&self,
|
||||
items: Element<'b, Message>,
|
||||
) -> Element<'b, Message> {
|
||||
if self.context_menu.is_some() {
|
||||
let menu_items = vec![
|
||||
menu::Item::Button("Open", None, MenuMessage::Open),
|
||||
menu::Item::Button(
|
||||
"Delete",
|
||||
None,
|
||||
MenuMessage::Delete,
|
||||
),
|
||||
];
|
||||
let context_menu = context_menu(
|
||||
items,
|
||||
self.context_menu.map_or_else(
|
||||
|| None,
|
||||
|_| {
|
||||
Some(menu::items(&self.menu_keys, menu_items))
|
||||
},
|
||||
),
|
||||
);
|
||||
Element::from(context_menu)
|
||||
} else {
|
||||
items
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_async)]
|
||||
pub async fn search_items(
|
||||
&self,
|
||||
|
|
@ -1079,135 +1274,140 @@ impl<'a> Library {
|
|||
return Action::None;
|
||||
};
|
||||
items.sort_by(|(_, index), (_, other)| index.cmp(other));
|
||||
let tasks: Vec<Task<Message>> =
|
||||
items
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|(kind, index)| match kind {
|
||||
LibraryKind::Song => {
|
||||
if let Some(song) =
|
||||
self.song_library.get_item(*index)
|
||||
let tasks: Vec<Task<Message>> = items
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|(kind, index)| match kind {
|
||||
LibraryKind::Song => {
|
||||
if let Some(song) =
|
||||
self.song_library.get_item(*index)
|
||||
{
|
||||
let song = song.clone();
|
||||
if let Err(e) =
|
||||
self.song_library.remove_item(*index)
|
||||
{
|
||||
let song = song.clone();
|
||||
if let Err(e) =
|
||||
self.song_library.remove_item(*index)
|
||||
{
|
||||
error!(?e);
|
||||
Task::none()
|
||||
} else {
|
||||
Task::future(self.db.acquire())
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
songs::remove_from_db(
|
||||
db, song.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e)
|
||||
}
|
||||
Message::None
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
error!(?e);
|
||||
Task::none()
|
||||
} else {
|
||||
Task::future(self.db.acquire()).and_then(
|
||||
move |db| {
|
||||
Task::perform(
|
||||
songs::remove_from_db(
|
||||
db, song.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e)
|
||||
}
|
||||
Message::None
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
LibraryKind::Video => {
|
||||
if let Some(video) =
|
||||
self.video_library.get_item(*index)
|
||||
}
|
||||
LibraryKind::Video => {
|
||||
if let Some(video) =
|
||||
self.video_library.get_item(*index)
|
||||
{
|
||||
let video = video.clone();
|
||||
if let Err(e) =
|
||||
self.video_library.remove_item(*index)
|
||||
{
|
||||
let video = video.clone();
|
||||
if let Err(e) =
|
||||
self.video_library.remove_item(*index)
|
||||
{
|
||||
error!(?e);
|
||||
Task::none()
|
||||
} else {
|
||||
Task::future(self.db.acquire())
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
videos::remove_from_db(
|
||||
db, video.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e)
|
||||
}
|
||||
Message::None
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
error!(?e);
|
||||
Task::none()
|
||||
} else {
|
||||
Task::future(self.db.acquire()).and_then(
|
||||
move |db| {
|
||||
Task::perform(
|
||||
videos::remove_from_db(
|
||||
db, video.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e)
|
||||
}
|
||||
Message::None
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
LibraryKind::Image => {
|
||||
if let Some(image) =
|
||||
self.image_library.get_item(*index)
|
||||
}
|
||||
LibraryKind::Image => {
|
||||
if let Some(image) =
|
||||
self.image_library.get_item(*index)
|
||||
{
|
||||
let image = image.clone();
|
||||
if let Err(e) =
|
||||
self.image_library.remove_item(*index)
|
||||
{
|
||||
let image = image.clone();
|
||||
if let Err(e) =
|
||||
self.image_library.remove_item(*index)
|
||||
{
|
||||
error!(?e);
|
||||
Task::none()
|
||||
} else {
|
||||
Task::future(self.db.acquire())
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
images::remove_from_db(
|
||||
db, image.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e)
|
||||
}
|
||||
Message::None
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
error!(?e);
|
||||
Task::none()
|
||||
} else {
|
||||
debug!("let's remove {0}", image.id);
|
||||
debug!("let's remove {0}", image.title);
|
||||
Task::future(self.db.acquire()).and_then(
|
||||
move |db| {
|
||||
Task::perform(
|
||||
images::remove_from_db(
|
||||
db, image.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e)
|
||||
}
|
||||
Message::None
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
LibraryKind::Presentation => {
|
||||
if let Some(presentation) =
|
||||
self.presentation_library.get_item(*index)
|
||||
}
|
||||
LibraryKind::Presentation => {
|
||||
if let Some(presentation) =
|
||||
self.presentation_library.get_item(*index)
|
||||
{
|
||||
let presentation = presentation.clone();
|
||||
if let Err(e) = self
|
||||
.presentation_library
|
||||
.remove_item(*index)
|
||||
{
|
||||
let presentation = presentation.clone();
|
||||
if let Err(e) = self
|
||||
.presentation_library
|
||||
.remove_item(*index)
|
||||
{
|
||||
error!(?e);
|
||||
Task::none()
|
||||
} else {
|
||||
Task::future(self.db.acquire())
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
presentations::remove_from_db(
|
||||
db,
|
||||
presentation.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e)
|
||||
}
|
||||
Message::None
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
error!(?e);
|
||||
Task::none()
|
||||
} else {
|
||||
Task::future(self.db.acquire()).and_then(
|
||||
move |db| {
|
||||
Task::perform(
|
||||
presentations::remove_from_db(
|
||||
db,
|
||||
presentation.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e)
|
||||
}
|
||||
Message::None
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if !tasks.is_empty() {
|
||||
self.selected_items = None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ pub enum Message {
|
|||
NextPage,
|
||||
PrevPage,
|
||||
None,
|
||||
ChangePresentationFile(Presentation),
|
||||
}
|
||||
|
||||
impl PresentationEditor {
|
||||
|
|
@ -60,43 +61,7 @@ impl PresentationEditor {
|
|||
pub fn update(&mut self, message: Message) -> Action {
|
||||
match message {
|
||||
Message::ChangePresentation(presentation) => {
|
||||
self.presentation = Some(presentation.clone());
|
||||
self.title = presentation.title.clone();
|
||||
self.document =
|
||||
Document::open(&presentation.path.as_path()).ok();
|
||||
self.page_count = self
|
||||
.document
|
||||
.as_ref()
|
||||
.and_then(|doc| doc.page_count().ok());
|
||||
warn!("changing presentation");
|
||||
self.current_slide =
|
||||
self.document.as_ref().and_then(|doc| {
|
||||
let page = doc.load_page(0).ok()?;
|
||||
let matrix = Matrix::IDENTITY;
|
||||
let colorspace = Colorspace::device_rgb();
|
||||
let Ok(pixmap) = page
|
||||
.to_pixmap(
|
||||
&matrix,
|
||||
&colorspace,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
.into_diagnostic()
|
||||
else {
|
||||
error!(
|
||||
"Can't turn this page into pixmap"
|
||||
);
|
||||
return None;
|
||||
};
|
||||
debug!(?pixmap);
|
||||
Some(Handle::from_rgba(
|
||||
pixmap.width(),
|
||||
pixmap.height(),
|
||||
pixmap.samples().to_vec(),
|
||||
))
|
||||
});
|
||||
self.current_slide_index = Some(0);
|
||||
return self.update(Message::Update(presentation));
|
||||
self.update_entire_presentation(&presentation);
|
||||
}
|
||||
Message::ChangeTitle(title) => {
|
||||
self.title = title.clone();
|
||||
|
|
@ -112,7 +77,7 @@ impl PresentationEditor {
|
|||
self.editing = edit;
|
||||
}
|
||||
Message::Update(presentation) => {
|
||||
warn!(?presentation);
|
||||
warn!(?presentation, "about to update");
|
||||
return Action::UpdatePresentation(presentation);
|
||||
}
|
||||
Message::PickPresentation => {
|
||||
|
|
@ -129,7 +94,9 @@ impl PresentationEditor {
|
|||
let mut presentation =
|
||||
Presentation::from(presentation);
|
||||
presentation.id = presentation_id;
|
||||
Message::ChangePresentation(presentation)
|
||||
Message::ChangePresentationFile(
|
||||
presentation,
|
||||
)
|
||||
} else {
|
||||
Message::None
|
||||
}
|
||||
|
|
@ -137,6 +104,10 @@ impl PresentationEditor {
|
|||
);
|
||||
return Action::Task(task);
|
||||
}
|
||||
Message::ChangePresentationFile(presentation) => {
|
||||
self.update_entire_presentation(&presentation);
|
||||
return self.update(Message::Update(presentation));
|
||||
}
|
||||
Message::None => (),
|
||||
Message::NextPage => {
|
||||
let next_index =
|
||||
|
|
@ -261,6 +232,40 @@ impl PresentationEditor {
|
|||
pub const fn editing(&self) -> bool {
|
||||
self.editing
|
||||
}
|
||||
|
||||
fn update_entire_presentation(
|
||||
&mut self,
|
||||
presentation: &Presentation,
|
||||
) {
|
||||
self.presentation = Some(presentation.clone());
|
||||
self.title = presentation.title.clone();
|
||||
self.document =
|
||||
Document::open(&presentation.path.as_path()).ok();
|
||||
self.page_count = self
|
||||
.document
|
||||
.as_ref()
|
||||
.and_then(|doc| doc.page_count().ok());
|
||||
warn!("changing presentation");
|
||||
self.current_slide = self.document.as_ref().and_then(|doc| {
|
||||
let page = doc.load_page(0).ok()?;
|
||||
let matrix = Matrix::IDENTITY;
|
||||
let colorspace = Colorspace::device_rgb();
|
||||
let Ok(pixmap) = page
|
||||
.to_pixmap(&matrix, &colorspace, true, true)
|
||||
.into_diagnostic()
|
||||
else {
|
||||
error!("Can't turn this page into pixmap");
|
||||
return None;
|
||||
};
|
||||
debug!(?pixmap);
|
||||
Some(Handle::from_rgba(
|
||||
pixmap.width(),
|
||||
pixmap.height(),
|
||||
pixmap.samples().to_vec(),
|
||||
))
|
||||
});
|
||||
self.current_slide_index = Some(0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PresentationEditor {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ pub enum Message {
|
|||
ChangeVerseOrder(String),
|
||||
ChangeLyrics(text_editor::Action),
|
||||
ChangeBackground(Result<PathBuf, SongError>),
|
||||
UpdateSlides(Vec<Slide>),
|
||||
PickBackground,
|
||||
Edit(bool),
|
||||
None,
|
||||
|
|
@ -134,17 +135,7 @@ impl SongEditor {
|
|||
match message {
|
||||
Message::ChangeSong(song) => {
|
||||
self.song = Some(song.clone());
|
||||
self.song_slides = song.to_slides().ok().map(|v| {
|
||||
v.into_par_iter()
|
||||
.map(|mut s| {
|
||||
text_svg::text_svg_generator(
|
||||
&mut s,
|
||||
Arc::clone(&self.font_db),
|
||||
);
|
||||
s
|
||||
})
|
||||
.collect::<Vec<Slide>>()
|
||||
});
|
||||
let song_slides = song.clone().to_slides();
|
||||
self.title = song.title;
|
||||
if let Some(font) = song.font {
|
||||
self.font = font;
|
||||
|
|
@ -175,7 +166,28 @@ impl SongEditor {
|
|||
text_editor::Content::with_text(&lyrics);
|
||||
}
|
||||
self.background_video(&song.background);
|
||||
self.background = song.background;
|
||||
self.background = song.background.clone();
|
||||
let font_db = Arc::clone(&self.font_db);
|
||||
let task = Task::perform(
|
||||
async move {
|
||||
song_slides
|
||||
.ok()
|
||||
.map(move |v| {
|
||||
v.into_par_iter()
|
||||
.map(move |mut s| {
|
||||
text_svg::text_svg_generator(
|
||||
&mut s,
|
||||
Arc::clone(&font_db),
|
||||
);
|
||||
s
|
||||
})
|
||||
.collect::<Vec<Slide>>()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
},
|
||||
|slides| Message::UpdateSlides(slides),
|
||||
);
|
||||
return Action::Task(task);
|
||||
}
|
||||
Message::ChangeFont(font) => {
|
||||
self.font = font.clone();
|
||||
|
|
@ -258,6 +270,13 @@ impl SongEditor {
|
|||
video.set_paused(!paused);
|
||||
};
|
||||
}
|
||||
Message::UpdateSlides(slides) => {
|
||||
self.song_slides = Some(slides);
|
||||
}
|
||||
Message::UpdateSong(song) => {
|
||||
self.song = Some(song.clone());
|
||||
return Action::UpdateSong(song);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Action::None
|
||||
|
|
@ -431,18 +450,30 @@ order",
|
|||
|
||||
fn update_song(&mut self, song: Song) -> Action {
|
||||
self.song = Some(song.clone());
|
||||
self.song_slides = song.to_slides().ok().map(|v| {
|
||||
v.into_par_iter()
|
||||
.map(|mut s| {
|
||||
text_svg::text_svg_generator(
|
||||
&mut s,
|
||||
Arc::clone(&self.font_db),
|
||||
);
|
||||
s
|
||||
})
|
||||
.collect::<Vec<Slide>>()
|
||||
});
|
||||
Action::UpdateSong(song)
|
||||
|
||||
let font_db = Arc::clone(&self.font_db);
|
||||
let update_task =
|
||||
Task::done(Message::UpdateSong(song.clone()));
|
||||
let task = Task::perform(
|
||||
async move {
|
||||
song.to_slides()
|
||||
.ok()
|
||||
.map(move |v| {
|
||||
v.into_par_iter()
|
||||
.map(move |mut s| {
|
||||
text_svg::text_svg_generator(
|
||||
&mut s,
|
||||
Arc::clone(&font_db),
|
||||
);
|
||||
s
|
||||
})
|
||||
.collect::<Vec<Slide>>()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
},
|
||||
|slides| Message::UpdateSlides(slides),
|
||||
);
|
||||
Action::Task(task.chain(update_task))
|
||||
}
|
||||
|
||||
fn background_video(&mut self, background: &Option<Background>) {
|
||||
|
|
|
|||
|
|
@ -15,29 +15,32 @@ use iced_video_player::{Video, VideoPlayer};
|
|||
use tracing::{debug, error, warn};
|
||||
use url::Url;
|
||||
|
||||
use crate::core::videos;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VideoEditor {
|
||||
pub video: Option<Video>,
|
||||
core_video: Option<crate::core::videos::Video>,
|
||||
core_video: Option<videos::Video>,
|
||||
title: String,
|
||||
editing: bool,
|
||||
}
|
||||
|
||||
pub enum Action {
|
||||
Task(Task<Message>),
|
||||
UpdateVideo(crate::core::videos::Video),
|
||||
UpdateVideo(videos::Video),
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message {
|
||||
ChangeVideo(crate::core::videos::Video),
|
||||
Update(crate::core::videos::Video),
|
||||
ChangeVideo(videos::Video),
|
||||
Update(videos::Video),
|
||||
ChangeTitle(String),
|
||||
PickVideo,
|
||||
Edit(bool),
|
||||
None,
|
||||
PauseVideo,
|
||||
UpdateVideoFile(videos::Video),
|
||||
}
|
||||
|
||||
impl VideoEditor {
|
||||
|
|
@ -52,20 +55,7 @@ impl VideoEditor {
|
|||
pub fn update(&mut self, message: Message) -> Action {
|
||||
match message {
|
||||
Message::ChangeVideo(video) => {
|
||||
let Ok(mut player_video) = Url::from_file_path(
|
||||
video.path.clone(),
|
||||
)
|
||||
.map(|url| Video::new(&url).expect("Should be here")) else {
|
||||
self.video = None;
|
||||
self.title = video.title.clone();
|
||||
self.core_video = Some(video);
|
||||
return Action::None;
|
||||
};
|
||||
player_video.set_paused(true);
|
||||
self.video = Some(player_video);
|
||||
self.title = video.title.clone();
|
||||
self.core_video = Some(video.clone());
|
||||
return self.update(Message::Update(video));
|
||||
self.update_entire_video(&video);
|
||||
}
|
||||
Message::ChangeTitle(title) => {
|
||||
self.title = title.clone();
|
||||
|
|
@ -100,11 +90,9 @@ impl VideoEditor {
|
|||
move |video_result| {
|
||||
if let Ok(video) = video_result {
|
||||
let mut video =
|
||||
crate::core::videos::Video::from(
|
||||
video,
|
||||
);
|
||||
videos::Video::from(video);
|
||||
video.id = video_id;
|
||||
Message::ChangeVideo(video)
|
||||
Message::UpdateVideoFile(video)
|
||||
} else {
|
||||
Message::None
|
||||
}
|
||||
|
|
@ -112,6 +100,10 @@ impl VideoEditor {
|
|||
);
|
||||
return Action::Task(task);
|
||||
}
|
||||
Message::UpdateVideoFile(video) => {
|
||||
self.update_entire_video(&video);
|
||||
return Action::UpdateVideo(video);
|
||||
}
|
||||
Message::None => (),
|
||||
}
|
||||
Action::None
|
||||
|
|
@ -185,6 +177,22 @@ impl VideoEditor {
|
|||
pub const fn editing(&self) -> bool {
|
||||
self.editing
|
||||
}
|
||||
|
||||
fn update_entire_video(&mut self, video: &videos::Video) {
|
||||
let Ok(mut player_video) =
|
||||
Url::from_file_path(video.path.clone())
|
||||
.map(|url| Video::new(&url).expect("Should be here"))
|
||||
else {
|
||||
self.video = None;
|
||||
self.title = video.title.clone();
|
||||
self.core_video = Some(video.clone());
|
||||
return;
|
||||
};
|
||||
player_video.set_paused(true);
|
||||
self.video = Some(player_video);
|
||||
self.title = video.title.clone();
|
||||
self.core_video = Some(video.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VideoEditor {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue