From 6d51ee528a7fa689bf978eaa78b77cc2487e2b1e Mon Sep 17 00:00:00 2001 From: Halit Can Date: Wed, 15 Jul 2026 17:27:08 +0300 Subject: [PATCH] fix(iced): add viewer keyboard navigation and wire lazy loading --- hcie-iced-app/crates/hcie-iced-gui/src/app.rs | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/hcie-iced-app/crates/hcie-iced-gui/src/app.rs b/hcie-iced-app/crates/hcie-iced-gui/src/app.rs index 794c5ab..2b46ce9 100644 --- a/hcie-iced-app/crates/hcie-iced-gui/src/app.rs +++ b/hcie-iced-app/crates/hcie-iced-gui/src/app.rs @@ -519,6 +519,9 @@ pub enum Message { ViewerOpenFile(std::path::PathBuf), ViewerRefresh, ViewerFullscreen(bool), + ViewerPrev, + ViewerNext, + ViewerEnter, } /// Convert a FilterType enum to the engine's string filter ID. @@ -3350,10 +3353,36 @@ impl HcieIcedApp { } } } + Message::ViewerPrev => { + if self.viewer_active { + self.viewer_state.prev_image(); + self.viewer_state.load_preview(); + } + } + Message::ViewerNext => { + if self.viewer_active { + self.viewer_state.next_image(); + self.viewer_state.load_preview(); + } + } + Message::ViewerEnter => { + if self.viewer_active && !self.viewer_state.images.is_empty() { + let path = self.viewer_state.images[self.viewer_state.active_image_idx].clone(); + return Task::perform(async move {}, move |_| Message::ViewerOpenFile(path.clone())); + } + } Message::NoOp => {} } + // Lazy-load thumbnails when viewer is active (max LAZY_LOAD_BUDGET per frame) + if self.viewer_active { + let batch = crate::viewer::thumbnail_grid::next_load_batch(&self.viewer_state); + for path in batch { + self.viewer_state.load_thumbnail(&path); + } + } + Task::none() } @@ -3584,13 +3613,20 @@ impl HcieIcedApp { iced::keyboard::Key::Character(ref c) if c.as_str() == "i" && ctrl && shift => { Some(Message::SelectInverse) } - // Escape = close menu, cancel dialog, deselect, or cancel crop - iced::keyboard::Key::Named(iced::keyboard::key::Named::Escape) => { - Some(Message::MenuClose) // Crop cancel handled in update() + // Arrow keys — viewer navigation or no-op + iced::keyboard::Key::Named(iced::keyboard::key::Named::ArrowLeft) => { + Some(Message::ViewerPrev) } - // Enter = confirm crop + iced::keyboard::Key::Named(iced::keyboard::key::Named::ArrowRight) => { + Some(Message::ViewerNext) + } + // Escape = exit viewer, close menu, cancel dialog, deselect, or cancel crop + iced::keyboard::Key::Named(iced::keyboard::key::Named::Escape) => { + Some(Message::ViewerToggle) + } + // Enter = open file in viewer, or confirm crop iced::keyboard::Key::Named(iced::keyboard::key::Named::Enter) => { - Some(Message::CropConfirm) // Crop confirm handled in update() + Some(Message::ViewerEnter) } _ => None, }