diff --git a/src/main.rs b/src/main.rs index de838c7..3513145 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ use std::ffi::OsStr; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; use std::process::Command; +use std::time::Duration; #[derive(Parser, Debug)] #[command( @@ -115,9 +116,17 @@ enum Message { PrintTask { result: Result<(), String>, }, + ClearPrintStatus, KeyChar(Key), } +#[derive(Clone, Debug, PartialEq, Eq)] +enum PrintStatus { + Sending, + Sent, + Failed(String), +} + struct NoctuaApp { core: Core, documents: Vec, @@ -125,6 +134,7 @@ struct NoctuaApp { zoom: f32, modifiers: keyboard::Modifiers, printing: bool, + print_status: Option, } fn main() -> cosmic::iced::Result { @@ -188,6 +198,7 @@ impl Application for NoctuaApp { zoom: 1.0, modifiers: keyboard::Modifiers::default(), printing: false, + print_status: None, }; app.refresh_title(); @@ -284,71 +295,35 @@ impl Application for NoctuaApp { } } // Print handling - Message::Print => { - if self.printing { - return Task::none(); - } - - let document = match self.current_document() { - Some(doc) => doc, - None => return Task::none(), - }; - let path = document.path.clone(); - let kind = document.kind; - - self.printing = true; - - return Task::perform( - tokio::task::spawn_blocking(move || print_document_sync(&path, kind)), - |result| { - let inner = result - .map_err(|e| format!("Spawn error: {e}")) - .and_then(|r| r); - cosmic::Action::App(Message::PrintTask { result: inner }) - }, - ); - } + Message::Print => return self.start_print(), Message::KeyChar(key) => { // Handle Ctrl+P shortcut for printing if self.modifiers.control() && key == Key::Character("p".into()) { - if self.printing { - return Task::none(); - } - - let document = match self.current_document() { - Some(doc) => doc, - None => return Task::none(), - }; - let path = document.path.clone(); - let kind = document.kind; - - self.printing = true; - - return Task::perform( - tokio::task::spawn_blocking(move || print_document_sync(&path, kind)), - |result| { - let inner = result - .map_err(|e| format!("Spawn error: {e}")) - .and_then(|r| r); - cosmic::Action::App(Message::PrintTask { result: inner }) - }, - ); + return self.start_print(); } } Message::PrintTask { result } => { self.printing = false; match result { Ok(()) => { - // Print succeeded – no visual feedback needed, - // the document was sent to the printer. + self.print_status = Some(PrintStatus::Sent); + return Task::perform( + tokio::task::spawn_blocking(|| { + std::thread::sleep(Duration::from_secs(4)); + }), + |_| cosmic::Action::App(Message::ClearPrintStatus), + ); } Err(err) => { - if let Some(document) = self.current_document_mut() { - document.error = Some(err); - } + self.print_status = Some(PrintStatus::Failed(err)); } } } + Message::ClearPrintStatus => { + if matches!(self.print_status, Some(PrintStatus::Sent)) { + self.print_status = None; + } + } } self.refresh_title(); @@ -447,8 +422,9 @@ impl Application for NoctuaApp { .push(widget::space::horizontal().width(Length::Fill)) .push( widget::button::standard("Print") - .on_press(Message::Print), + .on_press_maybe((!self.printing).then_some(Message::Print)), ) + .push(print_status_view(self.print_status.as_ref())) .push(widget::text::body(page_label)) .push( widget::button::standard("Prev page") @@ -511,6 +487,32 @@ impl NoctuaApp { self.core.set_header_title(title); } + fn start_print(&mut self) -> Task { + if self.printing { + return Task::none(); + } + + let document = match self.current_document() { + Some(doc) => doc, + None => return Task::none(), + }; + let path = document.path.clone(); + let kind = document.kind; + + self.printing = true; + self.print_status = Some(PrintStatus::Sending); + + Task::perform( + tokio::task::spawn_blocking(move || print_document_sync(&path, kind)), + |result| { + let inner = result + .map_err(|e| format!("Spawn error: {e}")) + .and_then(|r| r); + cosmic::Action::App(Message::PrintTask { result: inner }) + }, + ) + } + fn ensure_current_rendered(&mut self) -> Task { let render_task = { let Some(document) = self.current_document_mut() else { @@ -634,6 +636,25 @@ fn empty_view<'a>(message: impl Into) -> Element<'a, Message> { .into() } +fn print_status_view(status: Option<&PrintStatus>) -> Element<'_, Message> { + match status { + Some(PrintStatus::Sending) => widget::progress_bar::indeterminate_circular() + .size(16.0) + .bar_height(2.0) + .into(), + Some(PrintStatus::Sent) => widget::text::body("Sent to printer") + .class(theme::Text::Accent) + .into(), + Some(PrintStatus::Failed(err)) => widget::text::body(format!("Print failed: {err}")) + .class(theme::Text::Custom(|t| cosmic::iced_widget::text::Style { + color: Some(t.cosmic().destructive_color().into()), + ..Default::default() + })) + .into(), + None => widget::space::horizontal().width(Length::Fixed(0.0)).into(), + } +} + fn scroll_delta_y(delta: mouse::ScrollDelta) -> Option { let y = match delta { mouse::ScrollDelta::Lines { y, .. } => y,