diff --git a/apps/ely-show/src/deck.rs b/apps/ely-show/src/deck.rs index 2a41547..b8355b3 100644 --- a/apps/ely-show/src/deck.rs +++ b/apps/ely-show/src/deck.rs @@ -1,16 +1,15 @@ //! ElyShow's window: decks over one LOK worker (§10.1). use std::{ - collections::{HashMap, HashSet}, + collections::HashSet, path::PathBuf, sync::{Arc, Mutex}, }; use ely_gpui_component::{feedback::EmptyState, primitives::IconName, shell::StatusBar}; use ely_lok::{ - LokView, Sheets, Worker, - history::Step, - show::{Design, Objects}, + LokView, Worker, + show::Design, }; use ely_office::{Core, Kind, prelude::*}; use ely_platform::AppId; @@ -18,61 +17,13 @@ use ely_ui::{Root, Shell, commands}; use gpui::prelude::FluentBuilder as _; use gpui::{ AnyElement, App, AppContext as _, Context, Entity, InteractiveElement as _, IntoElement, - ParentElement as _, Render, RenderImage, SharedString, Styled as _, Window, div, + ParentElement as _, Render, SharedString, Styled as _, Window, div, }; use crate::design::Panel; use crate::slides::Strip; -/// Parts, edits, caret and selected frame. -pub type Seen = (u64, u64, bool, Option); - -/// What ElyShow keeps per deck. -#[derive(Default)] -pub struct Extra { - pub slides: Sheets, - /// The document as the last read saw it. - pub read_at: Option, - /// What the view showed at the last read. - pub read: Option, - pub reading: bool, - pub design: Option, - pub objects: Option, - pub notes: Option, - pub remarks: Vec, - /// The shown slide's transition and effects; none on a master. - pub motion: Option<(ely_lok::show::Transition, Vec)>, - pub media: Vec, - /// Counts completed reads. - pub reads: u64, - /// The slide size in twips. - pub size: (i64, i64), - /// Undo and redo lists at the last read. - pub history: Option<(Vec, Vec)>, - /// A size sent, in 1/100 mm, until read back. - pub size_asked: Option<(i64, i64)>, - /// A transition sent for a slide, until read back. - pub transition_asked: Option<(String, ely_lok::show::Transition, u64)>, - /// Pictures by slide name; stale ones show until repainted. - pub thumbs: HashMap>, - pub retired: ely_gpui_component::primitives::Retired, - pub stale: HashSet, - /// Pictures that failed; retried after the next read. - pub failed: HashSet, - pub painting: bool, - /// The parts are masters. - pub masters: bool, - /// The scheme the pictures were painted with. - pub dark: Option, -} - -impl Extra { - /// The size to show, in 1/100 mm: asked, else read. - pub fn shown_size(&self) -> (i64, i64) { - self.size_asked - .unwrap_or_else(|| crate::design::mm100(self.size)) - } -} +pub use crate::extra::Extra; pub struct Deck { pub core: Core, @@ -137,7 +88,13 @@ impl Host for Deck { } fn observed(&mut self, id: u64, view: &Entity, cx: &mut Context) { - view.update(cx, |view, cx| view.fit_page(cx)); + // A new deck fits once; a zoom then stays. + if let Some(tab) = self.tab_mut(id) + && !tab.extra.fitted + { + tab.extra.fitted = true; + view.update(cx, |view, cx| view.fit_page(cx)); + } // Pictures follow the kernel's light or dark scheme. let dark = view.read(cx).dark(); if let Some(tab) = self.tab_mut(id) diff --git a/apps/ely-show/src/extra.rs b/apps/ely-show/src/extra.rs new file mode 100644 index 0000000..1836c7b --- /dev/null +++ b/apps/ely-show/src/extra.rs @@ -0,0 +1,65 @@ +//! What ElyShow keeps per deck. + +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; + +use ely_lok::{ + Sheets, + history::Step, + show::{Design, Objects}, +}; +use gpui::RenderImage; + +/// Parts, edits, caret and selected frame. +pub type Seen = (u64, u64, bool, Option); + +/// What ElyShow keeps per deck. +#[derive(Default)] +pub struct Extra { + pub slides: Sheets, + /// The document as the last read saw it. + pub read_at: Option, + /// What the view showed at the last read. + pub read: Option, + pub reading: bool, + pub design: Option, + pub objects: Option, + pub notes: Option, + pub remarks: Vec, + /// The shown slide's transition and effects; none on a master. + pub motion: Option<(ely_lok::show::Transition, Vec)>, + pub media: Vec, + /// Counts completed reads. + pub reads: u64, + /// The slide size in twips. + pub size: (i64, i64), + /// Undo and redo lists at the last read. + pub history: Option<(Vec, Vec)>, + /// A size sent, in 1/100 mm, until read back. + pub size_asked: Option<(i64, i64)>, + /// A transition sent for a slide, until read back. + pub transition_asked: Option<(String, ely_lok::show::Transition, u64)>, + /// Pictures by slide name; stale ones show until repainted. + pub thumbs: HashMap>, + pub retired: ely_gpui_component::primitives::Retired, + pub stale: HashSet, + /// Pictures that failed; retried after the next read. + pub failed: HashSet, + pub painting: bool, + /// The parts are masters. + pub masters: bool, + /// The scheme the pictures were painted with. + pub dark: Option, + /// The view was fitted to the slide once. + pub fitted: bool, +} + +impl Extra { + /// The size to show, in 1/100 mm: asked, else read. + pub fn shown_size(&self) -> (i64, i64) { + self.size_asked + .unwrap_or_else(|| crate::design::mm100(self.size)) + } +} diff --git a/apps/ely-show/src/main.rs b/apps/ely-show/src/main.rs index 8ab6928..072595b 100644 --- a/apps/ely-show/src/main.rs +++ b/apps/ely-show/src/main.rs @@ -3,6 +3,7 @@ mod check; mod deck; mod design; mod dialog; +mod extra; mod guides; mod insert; mod list; diff --git a/apps/ely-show/src/tests/slides.rs b/apps/ely-show/src/tests/slides.rs index e55e481..9f51870 100644 --- a/apps/ely-show/src/tests/slides.rs +++ b/apps/ely-show/src/tests/slides.rs @@ -384,3 +384,27 @@ fn a_comment_picked_on_another_slide_shows_its_slide_again() { settle(&cx, |app| current(app) == Some(0)); assert_eq!(cx.update(|app| deck.read(app).shown_remark()), Some(key)); } + +#[test] +fn a_zoom_stays_through_later_reports() { + use ely_gpui_component::shell::ZoomStep; + let dir = tempfile::tempdir().expect("a temp dir"); + let mut cx = TestAppContext::single(); + let Some(deck) = blank(&mut cx, dir.path()) else { + eprintln!("SKIP: no LOK build"); + return; + }; + let view = |app: &gpui::App| deck.read(app).active_tab().expect("a tab").view.clone(); + settle(&cx, |app| view(app).read(app).fitting()); + update(&mut cx, &deck, |deck, cx| deck.zoom(ZoomStep::In, cx)); + let zoom = cx.update(|app| view(app).read(app).zoom()); + update(&mut cx, &deck, |deck, cx| { + let (id, view) = deck.active_tab().map(|tab| (tab.id, tab.view.clone())).expect("a tab"); + deck.observed(id, &view, cx); + }); + cx.update(|app| { + let view = view(app); + assert!(!view.read(app).fitting(), "a report does not fit the slide again"); + assert_eq!(view.read(app).zoom(), zoom, "the zoom stays"); + }); +} diff --git a/tasks/BUGS.md b/tasks/BUGS.md index a8f645d..ed45409 100644 --- a/tasks/BUGS.md +++ b/tasks/BUGS.md @@ -24,8 +24,8 @@ - [ ] T-14 导入扫描把整个文件的每个字段都建成字符串 - [ ] T-15 非 UTF-8 文本的默认编码跟系统区域而不是界面语言 - [ ] S-01 切换幻灯片后主画布不重画 -- [ ] S-02 `deck.rs` 超过 500 行 -- [ ] S-03 ElyShow 的缩放一两帧后弹回“适合幻灯片”,缩放功能不可用 +- [x] S-02 `deck.rs` 超过 500 行 — 随 S-03 把 Extra 移到 extra.rs,deck.rs 463 行 +- [x] S-03 ElyShow 的缩放一两帧后弹回“适合幻灯片”,缩放功能不可用 — 只在标签首次观察时适合一次;R1 PASS - [ ] S-04 选屏对话框被别的对话框顶掉后,`show_starting` 卡住、放映副本泄漏 - [ ] S-05 一条批注的时间恰为午夜或只有日期,整个批注栏不显示 - [ ] S-06 导出或打印的“从–到”填 0 时导出全部幻灯片 diff --git a/tasks/reviews/S-03-r1.md b/tasks/reviews/S-03-r1.md new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/tasks/reviews/S-03-r1.md @@ -0,0 +1 @@ +PASS