From 1ca71474a2c264d5b25a568d9ae9f5d2ddd0522d Mon Sep 17 00:00:00 2001 From: Zach Berry <1112351+zberry@users.noreply.github.com> Date: Mon, 19 Oct 2026 00:01:48 -0500 Subject: [PATCH] [JJ3] show.presenter answers {on, window} The answer was null. Presenter view is its own window beside the show window, so window is true; the doc says where it appears. PowerPoint: Presenter View opens in a separate window on the second display when the show starts (the Use Presenter View option); same here. Co-Authored-By: Claude Sonnet 5.5 --- crates/ui-egui/src/app/commands.rs | 6 +++++- crates/ui-egui/src/lib.rs | 9 ++++++++- crates/ui-egui/src/presenter_tests.rs | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 crates/ui-egui/src/presenter_tests.rs diff --git a/crates/ui-egui/src/app/commands.rs b/crates/ui-egui/src/app/commands.rs index 8f0e462f..6b35b7e7 100644 --- a/crates/ui-egui/src/app/commands.rs +++ b/crates/ui-egui/src/app/commands.rs @@ -162,7 +162,11 @@ impl SlideApp { self.start_show(from, false); } } - "show.presenter" => self.ui.presenter_view = self.flag(p, self.ui.presenter_view), + "show.presenter" => { + self.ui.presenter_view = self.flag(p, self.ui.presenter_view); + // The browser build has one viewport: presenter view is drawn inside the page. + return Ok(json!({"on": self.ui.presenter_view, "window": !cfg!(target_arch = "wasm32")})); + } "show.end" => { self.show = None; self.media.stop_owned(media::Owner::Show); diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 30b5a0cd..f6eb0ad5 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -109,7 +109,12 @@ pub const UI_COMMANDS: &[(&str, &str, Option<&str>, &str)] = &[ ("view.grayscale", "Grayscale", None, "{on?: bool}"), ("view.newWindow", "New Window", None, "{on?: bool, slide?: index, delta?: int}"), ("show.start", "Slide Show", Some("F5"), "{from?: index, custom?: name}"), - ("show.presenter", "Presenter View", None, "{on?: bool}"), + ( + "show.presenter", + "Presenter View", + None, + "{on?: bool} → {on, window} (presenter view, with notes, a clock and the next slide, appears in its own separate window beside the show window when the show starts; window is false in the browser build, which draws it inside the page)", + ), ("show.end", "End Show", None, "{}"), ("animation.preview", "Preview Animations", None, "{on?: bool, from?: effect index}"), ("app.home", "Home", None, "{on?}"), @@ -445,6 +450,8 @@ mod ime_tests; #[cfg(test)] mod last_color_tests; #[cfg(test)] +mod presenter_tests; +#[cfg(test)] mod replacefonts_tests; #[cfg(test)] mod reuse_picker_tests; diff --git a/crates/ui-egui/src/presenter_tests.rs b/crates/ui-egui/src/presenter_tests.rs new file mode 100644 index 00000000..c422ad18 --- /dev/null +++ b/crates/ui-egui/src/presenter_tests.rs @@ -0,0 +1,18 @@ +//! JJ3: `show.presenter` answers the setting and where presenter view appears. +#![allow(clippy::unwrap_used, clippy::expect_used)] + +use serde_json::json; + +use crate::{Services, SlideApp}; +use deckcraft_engine::Session; + +#[test] +fn show_presenter_answers_on_and_window() { + let mut app = SlideApp::new(Session::with_new(), Services::default()); + let v = app.run("show.presenter", json!({"on": true})).unwrap(); + assert_eq!(v, json!({"on": true, "window": true})); + let v = app.run("show.presenter", json!({})).unwrap(); + assert_eq!(v["on"], false, "no `on` toggles: {v}"); + let doc = crate::UI_COMMANDS.iter().find(|c| c.0 == "show.presenter").unwrap().3; + assert!(doc.contains("separate window"), "{doc}"); +}