Kostenmodus, diaformaat en lijsten bij kopiëren (#2433–#2439) #2446

Merged
brenno merged 11 commits from feat/issues-2433-2439 into main 2026-10-15 18:43:47 +00:00
Owner

Wat dit landt

Eén PR voor het werk dat een eerdere (Devin-)sessie half afliet, plus de reparaties die de poort en een eigen controle opleverden.

Issue Inhoud
#2433 Staand of liggend diaformaat (papersize: / geometry:), door editor, presentatie en alle exports
#2434 Dubbele exportknop rechtsonder uit de statusbalk
#2435 Kostenmodus: instellingen en sessieberekening (BigInt, monotone klok)
#2436 Privé-startscherm voor tarieven per aanwezige, salaris → uurtarief
#2437 Lopend bedrag rechtsonder (ook op het publieksvenster) en kosten in het eindoverzicht
#2438 Meerdere valuta en controleerbare EUR-omrekening op één koers per sessie
#2439 Lijsten verdwijnen bij kopiëren vanaf het midden van een regel in de visuele editor

#2440–#2443 (documentdossier) waren al gemerged (#2441, #2442, #2445) en staan hier niet in.

Wat ik zelf heb gedaan bovenop de vier commits van de eerdere sessie

  • De niet-gecommitte stand uit de hoofdcheckout (overlay, eindoverzicht, wisselkoersen) overgenomen en afgemaakt. Dat deel had geen tests, vertalingen of documentatie en liep over bij twee valuta op een laag venster (nu scrolt de dialoog).
  • #2439: oorzaak was visualClipboardPayload; een selectie die niet exact op een regelbegin start viel terug op platte tekst voor de héle selectie. Nu: gedeeltelijke eerste regel is tekst, de rest gaat met eigen blokopmaak mee. Een lijst die in een geneste structuur begint krijgt niveau 0 (vier spaties las Markdown als codeblok). Het contextmenu kopieert, knipt en plakt nu via dezelfde route als Cmd/Ctrl+C/X/V.
  • Startflow van de kostenmodus uit FullscreenPresenter gehaald (bestandsplafond) en apart getest.
  • Documentatie: FILE_FORMAT (en/nl), USER_GUIDE (en/nl), PRIVACY, SOURCE_MAP, CHANGELOG. De rij voor ocideck_show_rehearsal_summary in FILE_FORMAT klopte niet met de code (de sleutel is opt-in) en is rechtgezet.
  • 420 vertaalde interfaceteksten (14 nieuwe strings × 30 talen) via make add-l10n.

Bewaker: botsingen en afwegingen

  • Nieuwe uitgaande verbinding (#2438), waarde 3 tegenover gemak. Eén verzoek per valuta naar api.frankfurter.dev, alleen na een klik op Koers ophalen, met alleen de valutacode. De dienst ziet het IP-adres; dat staat in de dialoog, in PRIVACY en in de gebruikersgids. Altijd een uitweg: zelf invullen (label handmatig) of zonder koers doorgaan (koers ontbreekt, nooit een verzonnen bedrag).
  • Waarom Frankfurter en niet de ECB-feed zelf. De ECB-feed is de primaire bron, maar stuurt geen CORS-headers (gecontroleerd), dus de webbouw kon nooit een koers ophalen, en levert koersen per euro die omgekeerd moeten worden. Frankfurter is open source en serveert dezelfde reeks met CORS. Ik laat de primaire bron daarmee los voor webbereik. Ik zou van gedachten veranderen als Frankfurter ophoudt, een sleutel of betaalmuur krijgt, of de ECB CORS toevoegt: dit is de ene plek die verhuist (exchange_rate_service.dart).
  • Let op: de v1-API van Frankfurter meldt een successor-version (v2). v1 kan verdwijnen; dan valt de knop terug op Ophalen mislukt en blijft handmatig werken. Niet opgelost hier.
  • Formaat. Nieuwe sleutels papersize:/geometry: (Pandoc-vocabulaire; afwezig = 16:9 zoals elke Marp-lezer) en vier platte ocideck_cost_*-sleutels. Een vreemde lezer negeert ze zonder schade. Salarissen, individuele tarieven, aannames en koersgegevens staan nooit in het bestand, een export of het klembord.
  • De egress-allowlist (network_sink_guard_test) is uitgebreid met een onderbouwing: vaste host, geen redirects, antwoord op 8 KB afgekapt.

Gecontroleerd

  • make check: groen (volledige suite, dekking, goldens). Eén golden bewust bijgewerkt (presentatie-eigenschappen kreeg twee keuzes erbij); geen andere.
  • make check-secrets en make sast: 0 bevindingen.
  • Rood-eerst voor #2439: acht van de nieuwe tests faalden tegen de onherstelde code, en de twee contextmenu-tests zonder de builder.
  • Visueel (echte lettertypen, macOS): koersdialoog, eindoverzicht en overlay in licht en donker.

Niet gedaan / bekend

  • DAST (ZAP) niet gedraaid (geen colima in deze sessie).
  • Het eindoverzicht heet nog Oefenrun, ook na een echte presentatie met kostenmodus. Bestaande naamgeving; een eigen vervolg waard.
  • Volgnummers van een genummerde lijst herstarten bij 1 na plakken (Quill kent geen beginnummer).
  • Het contextmenu van het visuele veld is nu onze eigen builder; wat Quill zelf nog in dat menu had (opzoeken/delen) komt uit dezelfde itemlijst en blijft behouden.

Closes #2433, #2434, #2435, #2436, #2437, #2438, #2439

🤖 Generated with Claude Code

## Wat dit landt Eén PR voor het werk dat een eerdere (Devin-)sessie half afliet, plus de reparaties die de poort en een eigen controle opleverden. | Issue | Inhoud | |---|---| | #2433 | Staand of liggend diaformaat (`papersize:` / `geometry:`), door editor, presentatie en alle exports | | #2434 | Dubbele exportknop rechtsonder uit de statusbalk | | #2435 | Kostenmodus: instellingen en sessieberekening (BigInt, monotone klok) | | #2436 | Privé-startscherm voor tarieven per aanwezige, salaris → uurtarief | | #2437 | Lopend bedrag rechtsonder (ook op het publieksvenster) en kosten in het eindoverzicht | | #2438 | Meerdere valuta en controleerbare EUR-omrekening op één koers per sessie | | #2439 | Lijsten verdwijnen bij kopiëren vanaf het midden van een regel in de visuele editor | #2440–#2443 (documentdossier) waren al gemerged (#2441, #2442, #2445) en staan hier niet in. ## Wat ik zelf heb gedaan bovenop de vier commits van de eerdere sessie - De niet-gecommitte stand uit de hoofdcheckout (overlay, eindoverzicht, wisselkoersen) overgenomen en afgemaakt. Dat deel had geen tests, vertalingen of documentatie en liep over bij twee valuta op een laag venster (nu scrolt de dialoog). - #2439: oorzaak was `visualClipboardPayload`; een selectie die niet exact op een regelbegin start viel terug op platte tekst voor de héle selectie. Nu: gedeeltelijke eerste regel is tekst, de rest gaat met eigen blokopmaak mee. Een lijst die in een geneste structuur begint krijgt niveau 0 (vier spaties las Markdown als codeblok). Het contextmenu kopieert, knipt en plakt nu via dezelfde route als Cmd/Ctrl+C/X/V. - Startflow van de kostenmodus uit `FullscreenPresenter` gehaald (bestandsplafond) en apart getest. - Documentatie: FILE_FORMAT (en/nl), USER_GUIDE (en/nl), PRIVACY, SOURCE_MAP, CHANGELOG. De rij voor `ocideck_show_rehearsal_summary` in FILE_FORMAT klopte niet met de code (de sleutel is opt-in) en is rechtgezet. - 420 vertaalde interfaceteksten (14 nieuwe strings × 30 talen) via `make add-l10n`. ## Bewaker: botsingen en afwegingen - **Nieuwe uitgaande verbinding (#2438), waarde 3 tegenover gemak.** Eén verzoek per valuta naar `api.frankfurter.dev`, alleen na een klik op *Koers ophalen*, met alleen de valutacode. De dienst ziet het IP-adres; dat staat in de dialoog, in PRIVACY en in de gebruikersgids. Altijd een uitweg: zelf invullen (label *handmatig*) of zonder koers doorgaan (*koers ontbreekt*, nooit een verzonnen bedrag). - **Waarom Frankfurter en niet de ECB-feed zelf.** De ECB-feed is de primaire bron, maar stuurt geen CORS-headers (gecontroleerd), dus de webbouw kon nooit een koers ophalen, en levert koersen per euro die omgekeerd moeten worden. Frankfurter is open source en serveert dezelfde reeks met CORS. Ik laat de primaire bron daarmee los voor webbereik. **Ik zou van gedachten veranderen** als Frankfurter ophoudt, een sleutel of betaalmuur krijgt, of de ECB CORS toevoegt: dit is de ene plek die verhuist (`exchange_rate_service.dart`). - **Let op:** de v1-API van Frankfurter meldt een `successor-version` (v2). v1 kan verdwijnen; dan valt de knop terug op *Ophalen mislukt* en blijft handmatig werken. Niet opgelost hier. - **Formaat.** Nieuwe sleutels `papersize:`/`geometry:` (Pandoc-vocabulaire; afwezig = 16:9 zoals elke Marp-lezer) en vier platte `ocideck_cost_*`-sleutels. Een vreemde lezer negeert ze zonder schade. Salarissen, individuele tarieven, aannames en koersgegevens staan nooit in het bestand, een export of het klembord. - De egress-allowlist (`network_sink_guard_test`) is uitgebreid met een onderbouwing: vaste host, geen redirects, antwoord op 8 KB afgekapt. ## Gecontroleerd - `make check`: groen (volledige suite, dekking, goldens). Eén golden bewust bijgewerkt (presentatie-eigenschappen kreeg twee keuzes erbij); geen andere. - `make check-secrets` en `make sast`: 0 bevindingen. - Rood-eerst voor #2439: acht van de nieuwe tests faalden tegen de onherstelde code, en de twee contextmenu-tests zonder de builder. - Visueel (echte lettertypen, macOS): koersdialoog, eindoverzicht en overlay in licht en donker. ## Niet gedaan / bekend - **DAST (ZAP) niet gedraaid** (geen colima in deze sessie). - Het eindoverzicht heet nog *Oefenrun*, ook na een echte presentatie met kostenmodus. Bestaande naamgeving; een eigen vervolg waard. - Volgnummers van een genummerde lijst herstarten bij 1 na plakken (Quill kent geen beginnummer). - Het contextmenu van het visuele veld is nu onze eigen builder; wat Quill zelf nog in dat menu had (opzoeken/delen) komt uit dezelfde itemlijst en blijft behouden. Closes #2433, #2434, #2435, #2436, #2437, #2438, #2439 🤖 Generated with [Claude Code](https://claude.com/claude-code)
De statusbalk had twee ingangen naar dezelfde exportdialoog: de knop
'Exporteren' en de exportgereedheid-chip. De chip blijft — hij toont de
staat en springt naar de eerste openstaande bevinding; de losse knop
voegde alleen visuele drukte toe. Export zelf blijft via het hoofdmenu
bereikbaar, dus ook met toetsenbord en schermlezer.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Een deck kan nu een ISO-papierformaat kiezen naast de schermstandaard
16:9. De keuze reist mee in het Pandoc-vocabulaire — papersize voor
staand, geometry met alleen het vel voor liggend — zodat elke andere
lezer een logische paginamaat ziet in plaats van een OciDeck-sleutel.
Een handgeschreven geometry met marges blijft van de gebruiker.

De verhouding loopt via Deck.slideSize door renderer, metrieken,
presentatie, publieksscherm en alle exports (PDF/PPTX/ODP/Beamer/HTML).
Decks zonder aanduiding blijven 16:9.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Deck-voorkeur in vier platte ocideck_cost_* sleutels (modus, invoerroute,
groepstarief, valuta); individuele tarieven horen bij de sessie en staan
nooit in het bestand. De sessie rekent op een monotone klok in kleinste
valutaeenheden met BigInt — geen floats, geen overflow — en volgt de
grenzen van de oefenklok: start na de invoer, onverstoorbaar door
diawissels, doorlopend bij pauze, terug bij nul op reset.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Bij 'tarieven per aanwezige' opent vóór de route een invoerscherm op het
presentatorscherm — het publieksvenster bestaat dan nog niet, dus de
invoer kan er nooit op belanden. Per aanwezige uur-, maand- of jaarbedrag
plus valuta, zonder namen; de omrekenaannames (betaalde uren, weken,
opslag werkgeverslasten) staan er zichtbaar en aanpasbaar bij, bruto/netto
wordt benoemd in plaats van geraden. Validatie weigert rotte invoer en
een misleidende nulprijs; annuleren start de presentatie niet.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Expliciete modus toont een oplopend sessietotaal rechtsonder, ook op het
publieksscherm (via een 'costTick' met runvolgnummer, zodat een vertraagd
bericht na een reset de teller niet terugzet). In beide modi voegt het
eindoverzicht totale tijd, totale kosten en kosten per dia toe, ook als de
oefenschakelaar uitstaat.

Vreemde valuta rekenen via EUR als spil, op één bij de start vastgelegde
koers per sessie. De koers komt van Frankfurter (ECB) op expliciete knop,
handmatig of niet; zonder koers staat er "koers ontbreekt" in plaats van een
verzonnen bedrag. Bron en peildatum staan bij de berekeningsbasis.

Het koersdialoog scrolt nu (liep over bij twee valuta op een laag venster),
noemt de echte host en dat de dienst het IP-adres ziet, en de
handmatig-aanduiding komt uit de vertaling in plaats van een vaste tekst.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
visualClipboardPayload kiest alleen Markdown (met lijstopmaak) als de
selectie exact op een regelbegin start. Begon ze één teken verder, dan werd
de platte tekst van de hele selectie gekopieerd en verloren ook de volledig
geselecteerde volgende items hun bullet, nummering of vinkje.

Een gedeeltelijke eerste regel is nu een tekstfragment; alles vanaf de
volgende regel gaat met zijn eigen blokopmaak mee. Een lijst die midden in
een geneste structuur begint, krijgt niveau 0 in plaats van vier spaties
(dat las Markdown als codeblok). Het contextmenu van het visuele veld
kopieert, knipt en plakt nu langs dezelfde route als Cmd/Ctrl+C, X en V;
Quills eigen menu zette alleen platte tekst op het klembord.

Rood-eerst bewezen tegen de onherstelde code: acht van de nieuwe tests
faalden daar, plus de twee contextmenu-tests zonder de builder.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
De startschermen (aanwezigentarieven en wisselkoers) staan nu in
cost_session_start.dart met één uitkomst, zodat FullscreenPresenter onder zijn
bestandsplafond blijft en de flow zonder presentatieroute te toetsen is. De
koersdienst vangt typed uitzonderingen op en logt, in plaats van een kale
catch (_).

Documentatie: FILE_FORMAT (en/nl) krijgt de papersize/geometry- en
ocideck_cost_*-sleutels en zegt wat de kostenmodus nooit bewaart;
USER_GUIDE (en/nl) beschrijft kostenmodus en diaformaat; PRIVACY noemt het ene
verzoek naar api.frankfurter.dev; SOURCE_MAP registreert de nieuwe bestanden;
CHANGELOG meldt de wijzigingen. De rij voor ocideck_show_rehearsal_summary
klopte niet met de code (de sleutel is opt-in) en is rechtgezet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
De volledige poort vond twee dingen. Kale Colors.grey/red/orange als tekstkleur
in koersdialoog en eindoverzicht zijn vervangen door themakleuren, zodat ze
meebewegen met licht/donker. De koersdienst staat nu op de egress-allowlist met
de reden erbij: een vaste host, geen door de gebruiker aangeleverde URL, geen
redirects, antwoord afgekapt op 8 KB en alleen na een klik. Het eindoverzicht
haalt zijn kostenblok uit build() om onder de methodelengte te blijven.

De keuze voor Frankfurter boven de ECB-feed zelf staat als afweging in de
code: die feed heeft geen CORS, dus de webbouw zou nooit een koers kunnen
ophalen.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
De dialoog kreeg het diaformaat en de kostenmodus erbij, dus de lay-out
verschuift: de nieuwe keuzes staan boven de bestaande velden en de dialoog
scrolt. Bewust bijgewerkt; geen andere golden is gewijzigd.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
brenno merged commit 5fa2584504 into main 2026-10-15 18:43:47 +00:00
Sign in to join this conversation.
No description provided.