feat: Presentation editor now shows all pages made asynchronously
Some checks are pending
/ test (push) Waiting to run
Some checks are pending
/ test (push) Waiting to run
Still needs some work to make sure that they are clickable to go to the correct page and a right click menu to enable extra editing of the presentation. Eventually we can add splitting the presentation or removing/skipping pages when actually presenting.
This commit is contained in:
parent
67a984a761
commit
d1ec3a8585
1 changed files with 60 additions and 8 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{io, path::PathBuf};
|
use std::{io, path::Path, path::PathBuf};
|
||||||
|
|
||||||
use crate::core::presentations::Presentation;
|
use crate::core::presentations::Presentation;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
|
|
@ -9,7 +9,7 @@ use cosmic::{
|
||||||
theme,
|
theme,
|
||||||
widget::{
|
widget::{
|
||||||
self, Space, button, container, horizontal_space, icon,
|
self, Space, button, container, horizontal_space, icon,
|
||||||
image::Handle, text, text_input,
|
image::Handle, scrollable, text, text_input,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use miette::IntoDiagnostic;
|
use miette::IntoDiagnostic;
|
||||||
|
|
@ -45,6 +45,7 @@ pub enum Message {
|
||||||
PrevPage,
|
PrevPage,
|
||||||
None,
|
None,
|
||||||
ChangePresentationFile(Presentation),
|
ChangePresentationFile(Presentation),
|
||||||
|
AddSlides(Option<Vec<Handle>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PresentationEditor {
|
impl PresentationEditor {
|
||||||
|
|
@ -64,6 +65,14 @@ impl PresentationEditor {
|
||||||
match message {
|
match message {
|
||||||
Message::ChangePresentation(presentation) => {
|
Message::ChangePresentation(presentation) => {
|
||||||
self.update_entire_presentation(&presentation);
|
self.update_entire_presentation(&presentation);
|
||||||
|
if let Some(presentation) = self.presentation.clone()
|
||||||
|
{
|
||||||
|
let task = Task::perform(
|
||||||
|
get_all_pages(presentation.path.clone()),
|
||||||
|
|pages| Message::AddSlides(pages),
|
||||||
|
);
|
||||||
|
return Action::Task(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Message::ChangeTitle(title) => {
|
Message::ChangeTitle(title) => {
|
||||||
self.title = title.clone();
|
self.title = title.clone();
|
||||||
|
|
@ -108,7 +117,20 @@ impl PresentationEditor {
|
||||||
}
|
}
|
||||||
Message::ChangePresentationFile(presentation) => {
|
Message::ChangePresentationFile(presentation) => {
|
||||||
self.update_entire_presentation(&presentation);
|
self.update_entire_presentation(&presentation);
|
||||||
return self.update(Message::Update(presentation));
|
if let Some(presentation) = self.presentation.clone()
|
||||||
|
{
|
||||||
|
let task = Task::perform(
|
||||||
|
get_all_pages(presentation.path.clone()),
|
||||||
|
|pages| Message::AddSlides(pages),
|
||||||
|
)
|
||||||
|
.chain(Task::done(Message::Update(
|
||||||
|
presentation.clone(),
|
||||||
|
)));
|
||||||
|
return Action::Task(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::AddSlides(slides) => {
|
||||||
|
self.slides = slides;
|
||||||
}
|
}
|
||||||
Message::None => (),
|
Message::None => (),
|
||||||
Message::NextPage => {
|
Message::NextPage => {
|
||||||
|
|
@ -199,6 +221,7 @@ impl PresentationEditor {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|page| {
|
.map(|page| {
|
||||||
let image = widget::image(page)
|
let image = widget::image(page)
|
||||||
|
.height(theme::spacing().space_xxxl * 3)
|
||||||
.content_fit(ContentFit::ScaleDown);
|
.content_fit(ContentFit::ScaleDown);
|
||||||
container(image).into()
|
container(image).into()
|
||||||
})
|
})
|
||||||
|
|
@ -206,14 +229,14 @@ impl PresentationEditor {
|
||||||
} else {
|
} else {
|
||||||
vec![horizontal_space().into()]
|
vec![horizontal_space().into()]
|
||||||
};
|
};
|
||||||
let pages_column = container(
|
let pages_column = container(scrollable(
|
||||||
column(pdf_pages)
|
column(pdf_pages)
|
||||||
.spacing(theme::active().cosmic().space_xs())
|
.spacing(theme::active().cosmic().space_xs())
|
||||||
.padding(theme::spacing().space_l),
|
.padding(theme::spacing().space_l),
|
||||||
)
|
))
|
||||||
.class(theme::Container::Card);
|
.class(theme::Container::Card);
|
||||||
let main_row = row![
|
let main_row = row![
|
||||||
pages_column.width(Length::FillPortion(1)),
|
pages_column,
|
||||||
presentation.center(Length::FillPortion(2))
|
presentation.center(Length::FillPortion(2))
|
||||||
]
|
]
|
||||||
.spacing(theme::spacing().space_xxl);
|
.spacing(theme::spacing().space_xxl);
|
||||||
|
|
@ -282,8 +305,8 @@ impl PresentationEditor {
|
||||||
};
|
};
|
||||||
debug!(?pixmap);
|
debug!(?pixmap);
|
||||||
Some(Handle::from_rgba(
|
Some(Handle::from_rgba(
|
||||||
pixmap.width(),
|
pixmap.width() / 3,
|
||||||
pixmap.height(),
|
pixmap.height() / 3,
|
||||||
pixmap.samples().to_vec(),
|
pixmap.samples().to_vec(),
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
|
@ -297,6 +320,35 @@ impl Default for PresentationEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_all_pages(
|
||||||
|
presentation_path: impl AsRef<Path>,
|
||||||
|
) -> Option<Vec<Handle>> {
|
||||||
|
let document = Document::open(presentation_path.as_ref()).ok()?;
|
||||||
|
let pages = document.pages().ok()?;
|
||||||
|
Some(
|
||||||
|
pages
|
||||||
|
.filter_map(|page| {
|
||||||
|
let page = page.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;
|
||||||
|
};
|
||||||
|
Some(Handle::from_rgba(
|
||||||
|
pixmap.width(),
|
||||||
|
pixmap.height(),
|
||||||
|
pixmap.samples().to_vec(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async fn pick_presentation() -> Result<PathBuf, PresentationError> {
|
async fn pick_presentation() -> Result<PathBuf, PresentationError> {
|
||||||
let dialog = Dialog::new().title("Choose a presentation...");
|
let dialog = Dialog::new().title("Choose a presentation...");
|
||||||
let bg_filter = FileFilter::new("Presentations")
|
let bg_filter = FileFilter::new("Presentations")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue