fix: harden classroom presentations

This commit is contained in:
ekklesia
2026-09-23 00:02:25 -05:00
parent ec1e0d1cd7
commit 6f2d169355
16 changed files with 709 additions and 215 deletions
+28 -20
View File
@@ -52,6 +52,8 @@ hash.
This is not a new renderer. LibreOffice does exactly the rendering
Impress would have done live — it is the same engine — and poppler does
what every PDF viewer does. The classroom's own code displays a PNG.
Because playback is made from static page images, PowerPoint animations,
video, audio and other interactive content are not supported.
What it buys:
* **A teacher can never reach an editor**, because no editor ever runs
@@ -74,14 +76,15 @@ interactive runs, so no UI integration package is needed.
## Where things are
```
~/Downloads/ the teacher's own download. NEVER touched.
~/Downloads/ completed presentations move from here
~/Downloads/Wonder Ink/ Wonder Ink's worksheets. NEVER touched.
~/.local/share/ekklesia-classroom/presentations/
imported.json which downloads have been dealt with
<id>/
presentation.json title, pages, thumbnail slide, timers
Session 7 - Romans.pptx the managed copy, original name kept
original/
Session 7 - Romans.pptx the one original, name kept
slides.pdf what everything is rendered from
pages/page-001.png ... one per slide, 1920px wide
thumbnail.png the card picture, from the chosen slide
@@ -108,20 +111,22 @@ A file is imported when **all** of these hold:
* its fingerprint — path, size, modification time — is not already in
`imported.json`.
Two downloads of the same name are two presentations. The second gets
`(2)` after its title; neither overwrites the other.
Two downloads of the same name are two presentations in separate id
directories. The second gets `(2)` after its title; neither overwrites the
other.
**Crash safety.** The metadata is written saying `importing` *before* any
work, and the fingerprint is recorded at the same moment so a file that
crashes the converter cannot be retried forever. On startup the importer
sweeps every directory still saying `importing`, deletes it and forgets
its fingerprint, so an import interrupted by a reboot simply happens
again. A presentation becomes visible to a teacher only once every file
**Move and crash safety.** On one filesystem the completed download is
renamed atomically. Across filesystems it is copied to a hidden temporary,
flushed, published atomically, and only then removed from Downloads. The
metadata and transaction fingerprint are written first. On startup, an
interruption before the source was removed discards the partial destination
and retries; an interruption after the move resumes conversion from the
managed original. A presentation becomes ready only once every derived file
it needs is on disk.
A file that cannot be converted gets a card saying so, offering only
**Remove**. The teacher's download is untouched, which is what the card
says.
**Remove**. Its managed original remains recoverable even when PDF or page
generation fails.
## The three things kept apart
@@ -129,7 +134,7 @@ This is the part most worth not breaking.
| | Changed by | Never changed by |
| --- | --- | --- |
| **Library thumbnail** | *Use this slide as the picture* in Quick Look | presenting, importing |
| **Library cover** | *Use as cover* in Quick Look | presenting, importing |
| **Starting slide** | nothing — always slide 1 | choosing a thumbnail |
| **Retention** | a slide actually reaching the screen | Quick Look, opening the library, choosing a thumbnail, preview generation, a viewer that failed to start |
@@ -159,8 +164,9 @@ The cleanup runs hourly in the importer and:
directory so a crash cannot make a presentation permanently
un-removable;
* only ever removes a directory under the library root;
* never touches `~/Downloads`, and therefore never a Wonder Ink
worksheet;
* removes the managed original and all derived assets together;
* never touches unrelated files in `~/Downloads`, and therefore never a
Wonder Ink worksheet;
* tolerates a directory that is already half gone.
## The presenter
@@ -181,11 +187,13 @@ Page Up and Page Down are what the clicker in the cupboard sends.
Going past the last slide finishes, rather than showing a black "click to
exit" slide.
**Fullscreen is re-asserted, not assumed.** Measured in the lab: focusing
another window on the same workspace dropped the slideshow to half the
screen with the library beside it. `window-state-event` puts it back for
as long as the presentation is running, and stops the moment Escape is
pressed so it can never fight the teacher's way out.
**Fullscreen is re-asserted, not assumed.** The presenter requests
fullscreen after its Wayland surface is mapped, and its stable `Presenting`
title lets a presenter-only KWin rule apply fullscreen and remove the border
without affecting the library or Quick Look. `window-state-event` reasserts
the state for as long as the presentation is running and stops the moment
Escape is pressed. The library is hidden during playback and restored on
exit; the Plasma panel itself is never hidden or reconfigured.
## Fonts