From fb53ddf02f739b1a0b6e648b8c0a9486b32d2158 Mon Sep 17 00:00:00 2001 From: mtlcl410 <2368091+mtlcl410@users.noreply.github.com> Date: Thu, 22 Oct 2026 17:04:06 +0800 Subject: [PATCH] M3: full screen neither is remembered as the last view nor hides it (#1767) CodeRabbit on #2195: a file opened while full screen was on entered the presentation first, and the remembered view then replaced its one fitted page, while leaving full screen went back to the display from before the restore; and a tab closed (or settings saved) in full screen remembered full screen's temporary fit and display. The remembered view is now applied before the presentation starts, and the view remembered is the normal display (DocView::normal_display: the one presenting replaced) at the page reached. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/canvas.rs | 11 ++++++++++ crates/ui-egui/src/last_view.rs | 10 +++++---- crates/ui-egui/src/lib.rs | 6 +++--- crates/ui-egui/tests/it/ui.rs | 37 +++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 1af2a6a4f..38913a943 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -1514,6 +1514,17 @@ impl DocView { self.goto = Some((self.current, 0.0)); } + /// The display shown outside full screen: the one presenting replaced, or the current one. + pub fn normal_display(&self) -> SavedDisplay { + self.presentation.unwrap_or(SavedDisplay { + layout: self.layout, + continuous: self.continuous, + cover: self.cover, + fit: self.fit, + zoom: self.zoom, + }) + } + /// Whether the view is in full screen's one-page-at-a-time display. pub fn presenting(&self) -> bool { self.presentation.is_some() diff --git a/crates/ui-egui/src/last_view.rs b/crates/ui-egui/src/last_view.rs index b575d4a39..691be7107 100644 --- a/crates/ui-egui/src/last_view.rs +++ b/crates/ui-egui/src/last_view.rs @@ -38,17 +38,19 @@ fn absolute(path: &str) -> String { } impl PdfCraftApp { - /// How view `index` shows its document now; `None` for a document without a file. + /// How view `index` shows its document now; `None` for a document without a file. In full + /// screen, the display it will go back to, at the page reached. fn view_to_remember(&self, index: usize) -> Option { let view = self.views.get(index)?; let path = self.session.get(view.id)?.path.as_deref()?; - let zoom = ViewDefaults { fit: view.fit, zoom: view.zoom, ..ViewDefaults::default() }.zoom_name(); + let shown = view.normal_display(); + let zoom = ViewDefaults { fit: shown.fit, zoom: shown.zoom, ..ViewDefaults::default() }.zoom_name(); Some(LastView { path: absolute(path), page: view.current, zoom, - display: canvas::display_token(view.layout, view.continuous).to_string(), - cover: view.cover, + display: canvas::display_token(shown.layout, shown.continuous).to_string(), + cover: shown.cover, }) } diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 386a778cd..33375c5d9 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -1412,7 +1412,9 @@ impl PdfCraftApp { self.active = Some(self.views.len() - 1); } self.apply_initial_view(self.views.len() - 1, &initial); - // After the document's own initial view, so leaving full screen comes back to it. + // Where the reader left off wins over the file's own initial view (#1767). + self.apply_last_view(self.views.len() - 1); + // After both, so full screen shows one fitted page and leaving it comes back to them. if self.full_screen && let Some(view) = self.views.last_mut() { @@ -1423,8 +1425,6 @@ impl PdfCraftApp { if activate && initial.full_screen { self.pending_full_screen = Some(id); } - // Where the reader left off wins over the file's own initial view (#1767). - self.apply_last_view(self.views.len() - 1); if activate && self.left_open && self.left == LeftPanel::Tool("organize") diff --git a/crates/ui-egui/tests/it/ui.rs b/crates/ui-egui/tests/it/ui.rs index 03db16ce7..5675de66c 100644 --- a/crates/ui-egui/tests/it/ui.rs +++ b/crates/ui-egui/tests/it/ui.rs @@ -1651,3 +1651,40 @@ fn a_file_opened_again_shows_its_last_view() { assert_eq!(app.last_views.len(), 1); assert_eq!((app.last_views[0].page, app.last_views[0].zoom.as_str()), (1, "fit-page")); } + +/// #1767 with full screen: the view remembered while presenting is the one full screen will go +/// back to, and a file reopened in full screen presents one fitted page, then leaves full +/// screen for the remembered view. +#[test] +fn full_screen_neither_is_remembered_nor_hides_the_last_view() { + use pdfcraft_ui_egui::canvas::{Fit, PageLayout}; + let path = std::env::temp_dir().join(format!("pdfcraft-last-view-fs-{}.pdf", std::process::id())).to_string_lossy().into_owned(); + let p = path.clone(); + let mut h = harness(move |app| app.open_bytes("doc.pdf", Some(p), pages_fixture(3)).expect("opens")); + { + let app = h.state_mut(); + app.set_option("zoom", "50").unwrap(); + let view = &mut app.views[0]; + view.set_display(PageLayout::TwoUp, false); + view.go_to_page(2); + view.enter_presentation(); + assert!(view.presenting() && view.fit == Fit::Page); + } + h.run_steps(3); + let saved = h.state().persist(); + h.state_mut().close_tab(0); + let remembered = h.state().last_views[0].clone(); + assert_eq!((remembered.page, remembered.zoom.as_str()), (2, "50%"), "not full screen's fitted page"); + let p = path.clone(); + let mut h = harness(move |app| { + app.restore(&saved); + app.full_screen = true; + app.open_bytes("doc.pdf", Some(p), pages_fixture(3)).expect("opens"); + }); + let v = &h.state().views[0]; + assert!(v.presenting(), "opened in full screen"); + assert_eq!((v.fit, v.continuous, v.current), (Fit::Page, false, 2), "one fitted page, where the reader left off"); + let view = &mut h.state_mut().views[0]; + view.leave_presentation(); + assert_eq!((view.fit, view.zoom, view.layout, view.continuous), (Fit::None, 0.5, PageLayout::TwoUp, false), "the remembered view"); +}