[Feature] Presentatie-import (Keiko) als Uitbreidingen-module + Integraties-tab #772

Closed
opened 2026-07-23 18:00:32 +00:00 by brenno · 4 comments
Owner

Het losse project Keiko (https://pawprint.vigilis.online/brenno/Keiko) importeert PowerPoint (.pptx), LibreOffice Impress (.odp) en Apple Keynote (.key) en zet ze om naar OciDeck-decks (Marp Markdown + assets). Deze issue brengt die functionaliteit in OciDeck, onder de kwaliteits- en look-and-feel-eisen van deze repo, als optionele module onder Uitbreidingen, met een Integraties-tab in de instellingen voor de OpenKAT-rapportagelocatie.

Grote, samenhangende brok: veel commits, weinig PR's (fasegewijs, §8). Op basis van dit stappenplan moet direct gestart kunnen worden — elke integratieplek staat met bestand:regel benoemd (uit codeverkenning tegen huidige main, 66cbb473).

Vastgelegde besluiten (23-07-2026)

  • B1 — Eén "Importeren"-module. De Uitbreidingen-module dekt zowel presentatie-import (Keiko) als het OpenKAT-invoerpunt van #767. Eén plek voor de gebruiker; vergt afstemming met de nog niet-gepushte tak feat/openkat-invoerpunt-767.
  • B2 — Keynote meteen volledig mee. .key vanaf het begin; de enige nieuwe dependency protobuf (IWA-parsing) komt er meteen bij, met SBOM/licentie/security-poort.
  • B3 — Keiko-wachtrij overnemen. Bulk-import met een wachtrij-overzicht (toevoegen/verwijderen/herordenen vóór start), geport uit Keiko's queued_files_provider.

1. Scheidslijn met #767 — geen dubbeling

Twee verschillende importsoorten; ze mogen niet door elkaar lopen.

#767 (bestaat al) Deze issue (Keiko)
Bron OpenKAT-rapportages (JSON in een map) Presentaties (.pptx/.odp/.key)
Doel Managementdeck genereren Zo getrouw mogelijke conversie naar OciDeck
Servicelaag OpenkatImportService c.s. (wip/openkat-services-672, geadopteerd op feat/openkat-invoerpunt-767) uit Keiko geport

Afspraak: deze issue herbouwt de OpenKAT-parser niet. Wél levert deze issue (a) de Integraties → OpenKAT-tab met de vaste rapportagelocatie (§3), en (b) — per besluit B1 — de gedeelde "Importeren"-module die #767's menu-actie herbergt. Coördineer met feat/openkat-invoerpunt-767: die tak levert OpenkatImportService + de menu-actie; deze issue plaatst dat invoerpunt onder de module en achter de reveal-regel. Beide importsoorten landen in de bestaande menusectie "Pakket en import" (lib/widgets/app_shell_menu.dart:127) en het commandopalet (lib/widgets/shell/command_palette_actions.dart:95).

2. Keiko is gebouwd tegen een oudere OciDeck — herijk tegen huidige main

Keiko dateert van vóór de wijzigingen van vandaag. Bij het overzetten expliciet herijken:

  • Herijk de classifier op de HUIDIGE SlideType-enum. De geldige set (lib/models/slide.dart:19-48) telt 24 waarden: title, section, bullets, twoBullets, bulletsImage, twoImages, image, video, quote, table, freeMarkdown, code, chart, cockpit, question, timeline, scorecard, assets, discoveries, finding, findingsSummary, checklist, scopeMatrix, signOff. Keiko kent scorecard, assets, discoveries nog niet — heroverweeg de salvage-doelen daarop.
  • Niet-destructieve weergavelimieten i.p.v. lossy truncatie. #672 (vandaag geland) gaf OciDeck weergavelimieten die de onderliggende data nooit verwijderen; #767's generator is er al op voorbereid. Keiko's aanpak (data weggooien om een leesbare slide te maken) is achterhaald: de import behoudt de volledige dataset en zet een weergavelimiet (top-N bullets, laatste-N tijdreeksen), niet een definitieve snoei.
  • Geen eigen FILE_FORMAT-emitter. Keiko's lib/ocideck/ (writer + markdown_emitter + eigen SlideType + style_profile) dupliceert een contract dat OciDeck al heeft — én dat sindsdien is veranderd (themeProfile, chirurgische front-matter, sidecars). Vervangen door het echte model (§ hieronder).

3. Porteergrens — wat overkomt en wat wordt vervangen

Keiko is ~9.500 regels niet-gegenereerde Dart, Riverpod (net als OciDeck). De importers/pipeline hebben géén Flutter-imports (unit-testbaar).

Overnemen (format-neutraal, de kernwaarde):

  • lib/importers/ — pptx, odp, keynote (IWA: snappy, protobuf-wire, object-graph, table/chart/media-reconstructie). Het zware, waardevolle deel.
  • lib/models/SourceSlide en vrienden (het format-neutrale tussenmodel).
  • lib/pipeline/format_detector, slide_classifier (herijkt, §2), importer_registry, unconverted_tracker, problem_slide.
  • lib/utils/archive_utils, xml_utils, safe_extensions.

Vervangen door OciDeck-equivalenten (niet dupliceren) — de API die de importer hoort aan te roepen (uit opslagverkenning):

  1. Per dia: Slide.create(SlideType.x) (lib/models/slide.dart:619) + copyWith(...) — nooit een eigen dia-serialiser.
  2. Deck bouwen: Deck(title:, theme: 'ocideck', slides:, themeProfile:) (lib/models/deck.dart:155); styling gaat níét in de .md (dat legt de app als stijlprofiel eroverheen).
  3. Doelmap: Settings.homeDirectory (lib/models/settings.dart:551) met terugval getApplicationDocumentsDirectory() (patroon lib/state/tabs_provider_import.dart:21); elk deck krijgt een eigen submap.
  4. Wegschrijven: FileService.saveDeck(deck, '<submap>/<naam>.md') (lib/services/file_service.dart:741) → _writeProject (lib/services/file/file_service_project.dart:8) regelt images/media/logos/themes/data, asset-kopie + inhoud-dedupe, projectrelatieve herschrijving, thema-CSS, atomische .md via MarkdownService.generateDeck (lib/services/markdown_service.dart:60), en sidecars.
  5. In-app tonen: TabsNotifier.newDeckInNewTab(...) (lib/state/tabs_provider.dart:357) / DeckNotifier.loadDeck(...) (lib/state/deck_provider.dart:269).
  6. Losse bytes-afbeeldingen: resolveAssetDestinationForBytes(destDir, filename, bytes) (lib/utils/asset_destination.dart:57) — leesbare namen mét inhoud-dedupe. Dit vervangt Keiko's gedeelde images/<sha256>-hack, die botst met de containment-garantie (lib/utils/project_path.dart:90) en met _discardImportArtifacts (tabs_provider_import.dart:11, ruimt een mislukte import op door de submap te verwijderen).

Verder vervangen: lib/state/ → module-providers (§5); lib/ui/ → OciDeck-dialogen/look-and-feel (§7); lib/l10n/ (ARB) → l10n.d('…')-keten (§6); core/theme.dart/core/result.dart → OciDeck-equivalenten.

4. Integraties-tab (req 2)

Nieuwe instellingen-tab Integraties, onderverdeeld per systeem, OpenKAT eerst. Eén aanwijsbare map voor OpenKAT-rapportages volstaat. Gebruik het OpenKAT-kattenlogo (de string 'Mascotte van OpenKAT.' en het asset-gebruik in lib/widgets/dialogs/parts/settings_dialog_about.dart:274 bestaan al — hergebruiken).

Integratieplekken (uit UI-verkenning):

  1. lib/widgets/dialogs/parts/settings_dialog_sections.dart:21-33 — enum-waarde integrations(Icons.hub_outlined) (positie = zijbalkpositie, vóór documentation/about).
  2. settings_dialog_sections.dart:43-56integrations => l10n.d('Integraties') in de label-switch.
  3. lib/widgets/dialogs/settings_dialog.dart:757-773SettingsSection.integrations => _integrationsTab() in de bodies-switch (verplicht; test/settings_search_test.dart:144 eist een body per enum-waarde in volgorde).
  4. Nieuw part parts/settings_dialog_integrations.dart (part-regel bij settings_dialog.dart:71-89); per systeem een _sectionTitle(...)-kop (OpenKAT eerst) — die kop is meteen het zoekanker.
  5. Zoekingangen in parts/settings_dialog_search_index.dart (section: exact gelijk aan de _sectionTitle-tekst; keywords: "openkat", "integratie", "rapportage", "map"). Getoetst door settings_search_test.dart:233/314.

De OpenKAT-locatie is een nieuwe persistente instelling (SharedPreferences, eigen unieke sleutel). #767's importactie leest deze als standaardmap.

5. Uitbreidingen-module (req 1) — "Importeren", standaard uit

Vierde module in het register. Standaard uit; reveal houdt bestaand werk bereikbaar. Checklist (uit UI-verkenning):

  1. lib/state/module_registry.dart:26ModuleId.import (volgorde = kaartvolgorde).
  2. module_registry.dart:75-91 — vierde ModuleEntry(enabled:, revealed:).
  3. Providers: nieuw statebestand naar model van lib/state/online_storage_provider.dart (notifier + enabledProvider + revealProvider; unieke prefs-sleutel die nooit hernoemt — zie info_safety_provider.dart:55). Harde default-uit (?? false).
  4. Kaart-widget naar model van lib/widgets/dialogs/settings/online_storage_module_card.dart.
  5. parts/settings_dialog_modules.dart:27-34 — arm ModuleId.import => const ImportModuleCard() in switch (entry.id) (verplicht, compileert anders niet).
  6. Reveal-regel: revealed = enabled || heeftImportInhoud (tonen zodra de inhoud er is; uitzetten mag geïmporteerd werk of het OpenKAT-invoerpunt nooit onbereikbaar maken).

Tests: test/online_storage_module_test.dart:115 (registervolgorde, harde lijst → naar vier), :215 (moduletelling = SwitchListTile per kaart), test/module_surface_leak_test.dart (modulescheiding + reveal-regel).

6. Bulk-import, menu & doelmap (req 4) — logisch landen, niet 1-op-1

  • Menu: "Importeren → Presentaties…" haakt aan in "Pakket en import" (app_shell_menu.dart:127) en het commandopalet (command_palette_actions.dart:95); naast (niet los van) #767's OpenKAT-actie. Ook via drag-drop (app_shell.dart:439/411 desktop/web) en bestandskiezer (FileService.pickMarkdownFile/pickDeckFileBytes).
  • Bulk (B3): port Keiko's wachtrij (queued_files_provider) — meerdere bestanden toevoegen/verwijderen/herordenen vóór start, voortgang per bestand.
  • Aparte doelmap suggereren: bij het starten van een import de gebruiker expliciet wijzen op het aanwijzen van een andere map dan de standaardmap, omdat de conversiekwaliteit per bron verschilt — geïmporteerd materiaal apart houden van origineel werk.
  • Glashelder: geen 1-op-1-kopie. Herimplementeer Keiko's eenmalige waarschuwing als OciDeck-dialoog ("kan niet elke presentatie perfect importeren; conversie is best-effort en moet daarna worden gecontroleerd", met "niet meer tonen"). Boven op wat niet overkomt: per bronslide een "niet overgenomen"-notitieslide (Keiko's ConversionIssue) — niets verdwijnt stil. Plus de per-slide-beslisdialoog (best-effort + notitie / rasteriseren / overslaan / annuleren).

7. Look-and-feel (req 6)

Keiko's eigen shell/home/settings/convert-pagina's + thema vervallen. Herimplementeer met OciDeck-patronen: modulekaart, instellingen-tab, AlertDialog/FilledButton in OciDeck-stijl, voortgang (0..1 + statusmelding) en de per-slide-beslisdialoog met OciDeck-widgets.

8. Eisen van deze repo (req 5) — poorten waar geport werk doorheen moet

  • Geen hardgecodeerde tekst: elke zichtbare string via l10n.d('…'); Keiko's ~56 ARB-sleutels → make add-l10n SPEC=… (alle 31 talen ingevuld, anders valt l10n-check).
  • Bestandsgrootte-ratchet (1000 regels/lib-bestand): grote importers opsplitsen in part-extensies.
  • Methodelengte 150 · UI-imports in services · dode code · dekking: elk nieuw lib-bestand dat in geen test voorkomt valt de dekkingspoort — port de relevante Keiko-tests (33 testbestanden + fixtures) en pas ze aan OciDeck-API's aan.
  • SBOM-poort (B2): protobuf is de enige nieuwe dependency → make sbom + licentiecontrole + security-blik. file_selector niet overnemen (OciDeck gebruikt file_picker). Al aanwezig: archive, xml, crypto, path, path_provider, shared_preferences, desktop_drop, window_manager, image.
  • Docs-registratie: CHANGELOG + USER_GUIDE + SOURCE_MAP + FILE_FORMAT waar geraakt; een nieuw docsbestand registreren (assets + reader-tegel + 30-taal-titel).
  • Bewaker/security: de import léést extern gegenereerde bestanden → invoerpoortregels (begrenzen, niets uitvoeren; grootte-limieten zoals Keiko's maxArchiveInputSize, sluit aan bij openDeck's maxDeckMarkdownBytes). Marp-Markdown-output = maximaal uitwisselbaar (past bij de kern); protobuf is het enige "specifieke buiten de kern" — bewust gewogen bij B2.

9. Fasering (weinig PR's, veel commits)

  • F1 — Fundament + omhulsel (1 PR). Integraties-tab met OpenKAT-locatie, "Importeren"-module (standaard uit, reveal), menu-/palet-inhaak, waarschuwingsdialoog, doelmap-suggestie. Deckbouw via het echte model; nog geen parser. protobuf + SBOM erbij (B2). Acceptatie: module verschijnt/verdwijnt correct, tab + zoekingangen groen, make check groen.
  • F2 — PPTX-import end-to-end (1 PR). Importer + classifier (herijkt) → Deck/Slide.createFileService.saveDeck. Acceptatie: een echte .pptx → deck met assets in eigen projectmap; notitieslides voor verlies; round-trip via MarkdownService stabiel; tests groen.
  • F3 — ODP-import (1 PR). Hergebruikt de pipeline.
  • F4 — Keynote-import (1 PR). IWA/protobuf-pad; .key end-to-end.
  • F5 — Bulk/wachtrij + per-slide-beslisdialoog + weergavelimieten + docs (1 PR). Wachtrij-UI (B3), niet-destructieve weergavelimieten (§2), USER_GUIDE/SOURCE_MAP.

10. Herkomst

Afgesplitst van de OpenKAT-integratie (#672 weergavelimieten geland, #767 OpenKAT-invoerpunt lopend). De importfunctionaliteit komt uit het losse project Keiko en wordt tegen de huidige main geherijkt en aan de repo-eisen onderworpen.

Het losse project **Keiko** (`https://pawprint.vigilis.online/brenno/Keiko`) importeert PowerPoint (`.pptx`), LibreOffice Impress (`.odp`) en Apple Keynote (`.key`) en zet ze om naar OciDeck-decks (Marp Markdown + assets). Deze issue brengt die functionaliteit **in** OciDeck, onder de kwaliteits- en look-and-feel-eisen van deze repo, als **optionele module** onder Uitbreidingen, met een **Integraties**-tab in de instellingen voor de OpenKAT-rapportagelocatie. Grote, samenhangende brok: **veel commits, weinig PR's** (fasegewijs, §8). Op basis van dit stappenplan moet direct gestart kunnen worden — elke integratieplek staat met bestand:regel benoemd (uit codeverkenning tegen huidige main, 66cbb473). ## Vastgelegde besluiten (23-07-2026) - **B1 — Eén "Importeren"-module.** De Uitbreidingen-module dekt zowel presentatie-import (Keiko) als het OpenKAT-invoerpunt van #767. Eén plek voor de gebruiker; vergt afstemming met de nog niet-gepushte tak `feat/openkat-invoerpunt-767`. - **B2 — Keynote meteen volledig mee.** `.key` vanaf het begin; de enige nieuwe dependency `protobuf` (IWA-parsing) komt er meteen bij, met SBOM/licentie/security-poort. - **B3 — Keiko-wachtrij overnemen.** Bulk-import met een wachtrij-overzicht (toevoegen/verwijderen/herordenen vóór start), geport uit Keiko's `queued_files_provider`. ## 1. Scheidslijn met #767 — geen dubbeling Twee verschillende importsoorten; ze mogen niet door elkaar lopen. | | #767 (bestaat al) | Deze issue (Keiko) | | --- | --- | --- | | Bron | OpenKAT-**rapportages** (JSON in een map) | **Presentaties** (.pptx/.odp/.key) | | Doel | Managementdeck genereren | Zo getrouw mogelijke conversie naar OciDeck | | Servicelaag | `OpenkatImportService` c.s. (`wip/openkat-services-672`, geadopteerd op `feat/openkat-invoerpunt-767`) | uit Keiko geport | **Afspraak:** deze issue herbouwt de OpenKAT-parser **niet**. Wél levert deze issue (a) de Integraties → OpenKAT-tab met de vaste rapportagelocatie (§3), en (b) — per besluit B1 — de gedeelde "Importeren"-module die #767's menu-actie herbergt. Coördineer met `feat/openkat-invoerpunt-767`: die tak levert `OpenkatImportService` + de menu-actie; deze issue plaatst dat invoerpunt onder de module en achter de reveal-regel. Beide importsoorten landen in de bestaande menusectie "Pakket en import" (`lib/widgets/app_shell_menu.dart:127`) en het commandopalet (`lib/widgets/shell/command_palette_actions.dart:95`). ## 2. Keiko is gebouwd tegen een oudere OciDeck — herijk tegen huidige main Keiko dateert van vóór de wijzigingen van vandaag. Bij het overzetten expliciet herijken: - **Herijk de classifier op de HUIDIGE `SlideType`-enum.** De geldige set (`lib/models/slide.dart:19-48`) telt 24 waarden: `title, section, bullets, twoBullets, bulletsImage, twoImages, image, video, quote, table, freeMarkdown, code, chart, cockpit, question, timeline, scorecard, assets, discoveries, finding, findingsSummary, checklist, scopeMatrix, signOff`. Keiko kent **`scorecard`, `assets`, `discoveries` nog niet** — heroverweeg de salvage-doelen daarop. - **Niet-destructieve weergavelimieten i.p.v. lossy truncatie.** #672 (vandaag geland) gaf OciDeck weergavelimieten die de onderliggende data nooit verwijderen; #767's generator is er al op voorbereid. Keiko's aanpak (data weggooien om een leesbare slide te maken) is achterhaald: de import behoudt de **volledige** dataset en zet een weergavelimiet (top-N bullets, laatste-N tijdreeksen), niet een definitieve snoei. - **Geen eigen FILE_FORMAT-emitter.** Keiko's `lib/ocideck/` (writer + `markdown_emitter` + eigen `SlideType` + `style_profile`) dupliceert een contract dat OciDeck al heeft — én dat sindsdien is veranderd (`themeProfile`, chirurgische front-matter, sidecars). Vervangen door het echte model (§ hieronder). ## 3. Porteergrens — wat overkomt en wat wordt vervangen Keiko is ~9.500 regels niet-gegenereerde Dart, Riverpod (net als OciDeck). De importers/pipeline hebben géén Flutter-imports (unit-testbaar). **Overnemen (format-neutraal, de kernwaarde):** - `lib/importers/` — pptx, odp, keynote (IWA: snappy, protobuf-wire, object-graph, table/chart/media-reconstructie). Het zware, waardevolle deel. - `lib/models/` — `SourceSlide` en vrienden (het format-neutrale tussenmodel). - `lib/pipeline/` — `format_detector`, `slide_classifier` (herijkt, §2), `importer_registry`, `unconverted_tracker`, `problem_slide`. - `lib/utils/` — `archive_utils`, `xml_utils`, `safe_extensions`. **Vervangen door OciDeck-equivalenten (niet dupliceren) — de API die de importer hoort aan te roepen (uit opslagverkenning):** 1. Per dia: **`Slide.create(SlideType.x)`** (`lib/models/slide.dart:619`) + `copyWith(...)` — nooit een eigen dia-serialiser. 2. Deck bouwen: **`Deck(title:, theme: 'ocideck', slides:, themeProfile:)`** (`lib/models/deck.dart:155`); styling gaat níét in de `.md` (dat legt de app als stijlprofiel eroverheen). 3. Doelmap: **`Settings.homeDirectory`** (`lib/models/settings.dart:551`) met terugval `getApplicationDocumentsDirectory()` (patroon `lib/state/tabs_provider_import.dart:21`); elk deck krijgt een **eigen** submap. 4. Wegschrijven: **`FileService.saveDeck(deck, '<submap>/<naam>.md')`** (`lib/services/file_service.dart:741`) → `_writeProject` (`lib/services/file/file_service_project.dart:8`) regelt `images/media/logos/themes/data`, asset-kopie + inhoud-dedupe, projectrelatieve herschrijving, thema-CSS, atomische `.md` via `MarkdownService.generateDeck` (`lib/services/markdown_service.dart:60`), en sidecars. 5. In-app tonen: **`TabsNotifier.newDeckInNewTab(...)`** (`lib/state/tabs_provider.dart:357`) / `DeckNotifier.loadDeck(...)` (`lib/state/deck_provider.dart:269`). 6. Losse bytes-afbeeldingen: **`resolveAssetDestinationForBytes(destDir, filename, bytes)`** (`lib/utils/asset_destination.dart:57`) — leesbare namen mét inhoud-dedupe. Dit vervangt Keiko's gedeelde `images/<sha256>`-hack, die botst met de containment-garantie (`lib/utils/project_path.dart:90`) en met `_discardImportArtifacts` (`tabs_provider_import.dart:11`, ruimt een mislukte import op door de submap te verwijderen). Verder vervangen: `lib/state/` → module-providers (§5); `lib/ui/` → OciDeck-dialogen/look-and-feel (§7); `lib/l10n/` (ARB) → `l10n.d('…')`-keten (§6); `core/theme.dart`/`core/result.dart` → OciDeck-equivalenten. ## 4. Integraties-tab (req 2) Nieuwe instellingen-tab **Integraties**, onderverdeeld per systeem, **OpenKAT eerst**. Eén aanwijsbare **map** voor OpenKAT-rapportages volstaat. Gebruik het OpenKAT-kattenlogo (de string `'Mascotte van OpenKAT.'` en het asset-gebruik in `lib/widgets/dialogs/parts/settings_dialog_about.dart:274` bestaan al — hergebruiken). Integratieplekken (uit UI-verkenning): 1. `lib/widgets/dialogs/parts/settings_dialog_sections.dart:21-33` — enum-waarde `integrations(Icons.hub_outlined)` (positie = zijbalkpositie, vóór `documentation`/`about`). 2. `settings_dialog_sections.dart:43-56` — `integrations => l10n.d('Integraties')` in de `label`-switch. 3. `lib/widgets/dialogs/settings_dialog.dart:757-773` — `SettingsSection.integrations => _integrationsTab()` in de `bodies`-switch (**verplicht**; `test/settings_search_test.dart:144` eist een body per enum-waarde in volgorde). 4. Nieuw part `parts/settings_dialog_integrations.dart` (`part`-regel bij `settings_dialog.dart:71-89`); per systeem een `_sectionTitle(...)`-kop (OpenKAT eerst) — die kop is meteen het zoekanker. 5. Zoekingangen in `parts/settings_dialog_search_index.dart` (`section:` exact gelijk aan de `_sectionTitle`-tekst; `keywords`: "openkat", "integratie", "rapportage", "map"). Getoetst door `settings_search_test.dart:233/314`. De OpenKAT-locatie is een nieuwe persistente instelling (SharedPreferences, eigen unieke sleutel). #767's importactie leest deze als standaardmap. ## 5. Uitbreidingen-module (req 1) — "Importeren", standaard uit Vierde module in het register. Standaard uit; reveal houdt bestaand werk bereikbaar. Checklist (uit UI-verkenning): 1. `lib/state/module_registry.dart:26` — `ModuleId.import` (volgorde = kaartvolgorde). 2. `module_registry.dart:75-91` — vierde `ModuleEntry(enabled:, revealed:)`. 3. Providers: nieuw statebestand naar model van `lib/state/online_storage_provider.dart` (notifier + `enabledProvider` + `revealProvider`; unieke prefs-sleutel die nooit hernoemt — zie `info_safety_provider.dart:55`). Harde default-uit (`?? false`). 4. Kaart-widget naar model van `lib/widgets/dialogs/settings/online_storage_module_card.dart`. 5. `parts/settings_dialog_modules.dart:27-34` — arm `ModuleId.import => const ImportModuleCard()` in `switch (entry.id)` (verplicht, compileert anders niet). 6. **Reveal-regel:** `revealed = enabled || heeftImportInhoud` (tonen zodra de inhoud er is; uitzetten mag geïmporteerd werk of het OpenKAT-invoerpunt nooit onbereikbaar maken). Tests: `test/online_storage_module_test.dart:115` (registervolgorde, harde lijst → naar vier), `:215` (moduletelling = `SwitchListTile` per kaart), `test/module_surface_leak_test.dart` (modulescheiding + reveal-regel). ## 6. Bulk-import, menu & doelmap (req 4) — logisch landen, niet 1-op-1 - **Menu:** "Importeren → Presentaties…" haakt aan in "Pakket en import" (`app_shell_menu.dart:127`) en het commandopalet (`command_palette_actions.dart:95`); naast (niet los van) #767's OpenKAT-actie. Ook via drag-drop (`app_shell.dart:439/411` desktop/web) en bestandskiezer (`FileService.pickMarkdownFile`/`pickDeckFileBytes`). - **Bulk (B3):** port Keiko's wachtrij (`queued_files_provider`) — meerdere bestanden toevoegen/verwijderen/herordenen vóór start, voortgang per bestand. - **Aparte doelmap suggereren:** bij het starten van een import de gebruiker expliciet wijzen op het aanwijzen van een **andere map dan de standaardmap**, omdat de conversiekwaliteit per bron verschilt — geïmporteerd materiaal apart houden van origineel werk. - **Glashelder: geen 1-op-1-kopie.** Herimplementeer Keiko's eenmalige waarschuwing als OciDeck-dialoog ("kan niet elke presentatie perfect importeren; conversie is best-effort en moet daarna worden gecontroleerd", met "niet meer tonen"). Boven op wat niet overkomt: per bronslide een **"niet overgenomen"-notitieslide** (Keiko's `ConversionIssue`) — niets verdwijnt stil. Plus de per-slide-beslisdialoog (best-effort + notitie / rasteriseren / overslaan / annuleren). ## 7. Look-and-feel (req 6) Keiko's eigen shell/home/settings/convert-pagina's + thema vervallen. Herimplementeer met OciDeck-patronen: modulekaart, instellingen-tab, `AlertDialog`/`FilledButton` in OciDeck-stijl, voortgang (0..1 + statusmelding) en de per-slide-beslisdialoog met OciDeck-widgets. ## 8. Eisen van deze repo (req 5) — poorten waar geport werk doorheen moet - **Geen hardgecodeerde tekst:** elke zichtbare string via `l10n.d('…')`; Keiko's ~56 ARB-sleutels → `make add-l10n SPEC=…` (alle 31 talen ingevuld, anders valt `l10n-check`). - **Bestandsgrootte-ratchet (1000 regels/`lib`-bestand):** grote importers opsplitsen in `part`-extensies. - **Methodelengte 150 · UI-imports in services · dode code · dekking:** elk nieuw `lib`-bestand dat in geen test voorkomt valt de dekkingspoort — port de relevante Keiko-tests (33 testbestanden + fixtures) en pas ze aan OciDeck-API's aan. - **SBOM-poort (B2):** **`protobuf`** is de enige nieuwe dependency → `make sbom` + licentiecontrole + security-blik. `file_selector` niet overnemen (OciDeck gebruikt `file_picker`). Al aanwezig: archive, xml, crypto, path, path_provider, shared_preferences, desktop_drop, window_manager, image. - **Docs-registratie:** CHANGELOG + USER_GUIDE + SOURCE_MAP + FILE_FORMAT waar geraakt; een nieuw docsbestand registreren (assets + reader-tegel + 30-taal-titel). - **Bewaker/security:** de import léést extern gegenereerde bestanden → invoerpoortregels (begrenzen, niets uitvoeren; grootte-limieten zoals Keiko's `maxArchiveInputSize`, sluit aan bij `openDeck`'s `maxDeckMarkdownBytes`). Marp-Markdown-output = maximaal uitwisselbaar (past bij de kern); `protobuf` is het enige "specifieke buiten de kern" — bewust gewogen bij B2. ## 9. Fasering (weinig PR's, veel commits) - **F1 — Fundament + omhulsel (1 PR).** Integraties-tab met OpenKAT-locatie, "Importeren"-module (standaard uit, reveal), menu-/palet-inhaak, waarschuwingsdialoog, doelmap-suggestie. Deckbouw via het echte model; nog geen parser. `protobuf` + SBOM erbij (B2). Acceptatie: module verschijnt/verdwijnt correct, tab + zoekingangen groen, `make check` groen. - **F2 — PPTX-import end-to-end (1 PR).** Importer + classifier (herijkt) → `Deck`/`Slide.create` → `FileService.saveDeck`. Acceptatie: een echte `.pptx` → deck met assets in eigen projectmap; notitieslides voor verlies; round-trip via `MarkdownService` stabiel; tests groen. - **F3 — ODP-import (1 PR).** Hergebruikt de pipeline. - **F4 — Keynote-import (1 PR).** IWA/protobuf-pad; `.key` end-to-end. - **F5 — Bulk/wachtrij + per-slide-beslisdialoog + weergavelimieten + docs (1 PR).** Wachtrij-UI (B3), niet-destructieve weergavelimieten (§2), USER_GUIDE/SOURCE_MAP. ## 10. Herkomst Afgesplitst van de OpenKAT-integratie (#672 weergavelimieten geland, #767 OpenKAT-invoerpunt lopend). De importfunctionaliteit komt uit het losse project Keiko en wordt tegen de huidige main geherijkt en aan de repo-eisen onderworpen.
Author
Owner

Opgepakt. Tak: feat/keiko-import-772 (vanaf verse main, incl. #771 weergavelimieten). Verwachte reikwijdte F1: nieuwe Uitbreidingen-module 'Importeren' (module_registry + eigen state/provider + module-card), Integraties-tab (settings_dialog_sections + settings_dialog + nieuw part + search-index), l10n via add-l10n, en de deckbouw-seam naar het echte Deck-model. Raakt #767's bestanden bewust niet (app_shell_menu/command_palette) tot dat op main staat; dan bedraad ik B1 (module herbergt het OpenKAT-invoerpunt).

Opgepakt. Tak: feat/keiko-import-772 (vanaf verse main, incl. #771 weergavelimieten). Verwachte reikwijdte F1: nieuwe Uitbreidingen-module 'Importeren' (module_registry + eigen state/provider + module-card), Integraties-tab (settings_dialog_sections + settings_dialog + nieuw part + search-index), l10n via add-l10n, en de deckbouw-seam naar het echte Deck-model. Raakt #767's bestanden bewust niet (app_shell_menu/command_palette) tot dat op main staat; dan bedraad ik B1 (module herbergt het OpenKAT-invoerpunt).
Author
Owner

Voortgang op tak feat/keiko-import-772 (vanaf main met #767 erin).

F1 + B1 — af, make check groen. Module "Importeren" (4e Uitbreiding, standaard uit) en het nieuwe tabblad Integraties met de OpenKAT-rapportagemap. Het OpenKAT-invoerpunt van #767 valt nu onder de module (reveal = module aan óf map aangewezen) en gebruikt die map rechtstreeks in plaats van elke keer de mapkiezer. OpenKAT-logo staat erin.

F2 (PowerPoint) — af, make check groen (6206 tests, dekking 85,9%). De format-neutrale laag en de PPTX-parser zijn geport en web-veilig gemaakt (alles via bytes, geen dart:io). Keiko's eigen writer is NIET meegekomen: er is een deck-builder die op het échte Deck-model bouwt (Slide.create + copyWith) en afbeeldingsbytes als mem:-pad neerzet, zodat FileService.saveDeck ze met inhoud-dedupe in de per-deck images/ materialiseert. Menu-actie + waarschuwing ("best-effort, geen één-op-één-kopie", met de tip om een aparte importmap te gebruiken), 31 talen l10n.

F3 (LibreOffice Impress) — af. ODP-importer geport, deelt de hele pipeline met PPTX; 10 geporte tests die hun ODP inline bouwen.

F4 (Keynote) — onderhanden.

Besluit B2 wordt goedkoper dan gedacht. De aanname was dat Keynote protobuf als nieuwe dependency nodig heeft, met SBOM- en licentiegang. Dat blijkt niet zo: Keiko's pubspec noemt protobuf wel, maar package:protobuf wordt nergens geïmporteerd — iwa/proto_wire.dart is een eigen, schema-vrije wire-decoder (zoals protoc --decode_raw). De hele import komt er dus zonder één nieuwe afhankelijkheid. Geen extra toeleveringsketen, geen SBOM-ronde.

Twee dingen die onderweg zijn opgelost en geen poort zag: de zip-bom-melding interpoleerde $bytes.length en drukte daarmee de hele bytelijst af (nu gefixt én voor het eerst toetsbaar door de grenzen injecteerbaar te maken), en de meegekomen safe_extensions/importer_logger waren dode respectievelijk dubbele code.

Nog te doen: F4 afronden, F5 (bulk-wachtrij, de niet-destructieve weergavelimieten uit #672 toepassen, USER_GUIDE/CHANGELOG).

Voortgang op tak `feat/keiko-import-772` (vanaf main met #767 erin). **F1 + B1 — af, `make check` groen.** Module "Importeren" (4e Uitbreiding, standaard uit) en het nieuwe tabblad Integraties met de OpenKAT-rapportagemap. Het OpenKAT-invoerpunt van #767 valt nu onder de module (reveal = module aan óf map aangewezen) en gebruikt die map rechtstreeks in plaats van elke keer de mapkiezer. OpenKAT-logo staat erin. **F2 (PowerPoint) — af, `make check` groen** (6206 tests, dekking 85,9%). De format-neutrale laag en de PPTX-parser zijn geport en web-veilig gemaakt (alles via bytes, geen `dart:io`). Keiko's eigen writer is NIET meegekomen: er is een deck-builder die op het échte Deck-model bouwt (`Slide.create` + copyWith) en afbeeldingsbytes als `mem:`-pad neerzet, zodat `FileService.saveDeck` ze met inhoud-dedupe in de per-deck `images/` materialiseert. Menu-actie + waarschuwing ("best-effort, geen één-op-één-kopie", met de tip om een aparte importmap te gebruiken), 31 talen l10n. **F3 (LibreOffice Impress) — af.** ODP-importer geport, deelt de hele pipeline met PPTX; 10 geporte tests die hun ODP inline bouwen. **F4 (Keynote) — onderhanden.** **Besluit B2 wordt goedkoper dan gedacht.** De aanname was dat Keynote `protobuf` als nieuwe dependency nodig heeft, met SBOM- en licentiegang. Dat blijkt niet zo: Keiko's pubspec noemt `protobuf` wel, maar `package:protobuf` wordt nergens geïmporteerd — `iwa/proto_wire.dart` is een eigen, schema-vrije wire-decoder (zoals `protoc --decode_raw`). **De hele import komt er dus zonder één nieuwe afhankelijkheid.** Geen extra toeleveringsketen, geen SBOM-ronde. Twee dingen die onderweg zijn opgelost en geen poort zag: de zip-bom-melding interpoleerde `$bytes.length` en drukte daarmee de hele bytelijst af (nu gefixt én voor het eerst toetsbaar door de grenzen injecteerbaar te maken), en de meegekomen `safe_extensions`/`importer_logger` waren dode respectievelijk dubbele code. Nog te doen: F4 afronden, F5 (bulk-wachtrij, de niet-destructieve weergavelimieten uit #672 toepassen, USER_GUIDE/CHANGELOG).
Author
Owner

PR staat klaar: #807 (tak feat/keiko-presentatie-import-772, gerebased op de huidige main).

Belangrijk voor de beoordeling: dit is een herbouw. Terwijl ik bouwde landde #789 met de module Importeren, het Integraties-tabblad, de vaste OpenKAT-map en 31 talen — exact wat mijn eerste zeven commits ook deden, tot dezelfde bestandsnamen toe. Die zijn dus vervallen; de oude tak is verwijderd zodat niemand hem per ongeluk mergt. Wat er nu ligt is uitsluitend wat main níét heeft: de parsers, de deck-builder, de weergavelimieten en de bulk-wachtrij, aangehaakt op main's bestaande importModuleRevealProvider.

Besluit B2 blijkt goedkoper dan gedacht: er komt géén enkele nieuwe afhankelijkheid bij. Keiko's pubspec noemde protobuf, maar dat pakket wordt nergens geïmporteerd — de IWA-laag heeft een eigen, schema-vrije wire-decoder.

De bewaker keurde de eerste versie af, en dat heeft de PR beter gemaakt. De belofte 'niets verdwijnt stil' werd op zes plekken niet waargemaakt en 'video komt over' was aantoonbaar onwaar: de bytes werden weggegooid en het deck hield een dood pad over. Dat is allemaal gerepareerd, elk met een test, en de rondgangstest die daarbij hoorde legde nog een echte datalek-bug bloot (een zachte regelafbreking uit PowerPoint at tekst op bij opslaan-en-heropenen).

Twee dingen zitten er bewust niet in en staan apart: #806 (import-meldingen en notitiedia's zijn Nederlands ongeacht de taal — vraagt reden-codes en een vertaalnaad) en #803 (sneltoetsteksten ontsnappen aan de vertaalpoort, bestond al).

Eerlijk over de beproeving: alle fixtures bouwen hun archief zélf, er staat geen door PowerPoint/Impress/Keynote weggeschreven bestand in de repo. Dat staat als punt 11 in VERIFICATION.md.

make check groen, 6500 tests, dekking 86,5%, geen basislijn verhoogd.

PR staat klaar: #807 (tak `feat/keiko-presentatie-import-772`, gerebased op de huidige main). **Belangrijk voor de beoordeling: dit is een herbouw.** Terwijl ik bouwde landde #789 met de module Importeren, het Integraties-tabblad, de vaste OpenKAT-map en 31 talen — exact wat mijn eerste zeven commits ook deden, tot dezelfde bestandsnamen toe. Die zijn dus vervallen; de oude tak is verwijderd zodat niemand hem per ongeluk mergt. Wat er nu ligt is uitsluitend wat main níét heeft: de parsers, de deck-builder, de weergavelimieten en de bulk-wachtrij, aangehaakt op main's bestaande `importModuleRevealProvider`. **Besluit B2 blijkt goedkoper dan gedacht:** er komt géén enkele nieuwe afhankelijkheid bij. Keiko's pubspec noemde `protobuf`, maar dat pakket wordt nergens geïmporteerd — de IWA-laag heeft een eigen, schema-vrije wire-decoder. **De bewaker keurde de eerste versie af**, en dat heeft de PR beter gemaakt. De belofte 'niets verdwijnt stil' werd op zes plekken niet waargemaakt en 'video komt over' was aantoonbaar onwaar: de bytes werden weggegooid en het deck hield een dood pad over. Dat is allemaal gerepareerd, elk met een test, en de rondgangstest die daarbij hoorde legde nog een echte datalek-bug bloot (een zachte regelafbreking uit PowerPoint at tekst op bij opslaan-en-heropenen). Twee dingen zitten er bewust niet in en staan apart: #806 (import-meldingen en notitiedia's zijn Nederlands ongeacht de taal — vraagt reden-codes en een vertaalnaad) en #803 (sneltoetsteksten ontsnappen aan de vertaalpoort, bestond al). Eerlijk over de beproeving: alle fixtures bouwen hun archief zélf, er staat geen door PowerPoint/Impress/Keynote weggeschreven bestand in de repo. Dat staat als punt 11 in VERIFICATION.md. `make check` groen, 6500 tests, dekking 86,5%, geen basislijn verhoogd.
Author
Owner

Geland op main met merge-commit e3e3c29b (PR #807, zes commits). Geverifieerd op main, niet op de tak: 53 lib-bestanden onder lib/services/import/ en 30 testbestanden staan er.

Wat erin zit: import van .pptx, .odp en .key naar echte OciDeck-decks, achter de bestaande module Importeren; deck-builder op het echte Deck-model (Keiko's eigen writer is bewust niet meegekomen); niet-destructieve weergavelimieten in plaats van snoeien; bulk-wachtrij met eigen doelmap; en een waarschuwing die vooraf zegt dat het best-effort is en geen één-op-één-kopie. Zonder één nieuwe afhankelijkheid — B2 bleek goedkoper dan gedacht.

Wat er níét in zit, met opzet en apart vastgelegd:

  • #806 — importmeldingen en notitiedia's zijn Nederlands ongeacht de ingestelde taal. De notitietekst wordt permanent ín het .md van de gebruiker gebakken, dus dit is meer dan cosmetisch.
  • #803 — sneltoetsteksten ontsnappen aan de vertaalpoort (bestond al, kwam hier boven).
  • Themakleuren komen niet over: de parsers leveren een SourceTheme die vervolgens door niemand gelezen wordt. Zo staat het ook in de gids. Geparste data die nergens landt is een losse draad; wie hem oppakt heeft het parswerk al klaar.

De belangrijkste beperking, en die staat als punt 11 in VERIFICATION.md: alle testfixtures bouwen hun archief zélf. Er staat geen enkel bestand in de repo dat PowerPoint, Impress of Keynote werkelijk heeft weggeschreven. De parsers zijn dus tegen nagebouwde invoer beproefd, niet tegen de echte wereld — een paar echte presentaties erdoorheen halen is de meest waardevolle volgende toets.

Hiermee is de reikwijdte van dit issue af; ik sluit het.

Geland op main met merge-commit `e3e3c29b` (PR #807, zes commits). Geverifieerd op main, niet op de tak: 53 lib-bestanden onder `lib/services/import/` en 30 testbestanden staan er. **Wat erin zit:** import van .pptx, .odp en .key naar echte OciDeck-decks, achter de bestaande module Importeren; deck-builder op het echte Deck-model (Keiko's eigen writer is bewust niet meegekomen); niet-destructieve weergavelimieten in plaats van snoeien; bulk-wachtrij met eigen doelmap; en een waarschuwing die vooraf zegt dat het best-effort is en geen één-op-één-kopie. **Zonder één nieuwe afhankelijkheid** — B2 bleek goedkoper dan gedacht. **Wat er níét in zit**, met opzet en apart vastgelegd: - #806 — importmeldingen en notitiedia's zijn Nederlands ongeacht de ingestelde taal. De notitietekst wordt permanent ín het .md van de gebruiker gebakken, dus dit is meer dan cosmetisch. - #803 — sneltoetsteksten ontsnappen aan de vertaalpoort (bestond al, kwam hier boven). - **Themakleuren komen niet over**: de parsers leveren een `SourceTheme` die vervolgens door niemand gelezen wordt. Zo staat het ook in de gids. Geparste data die nergens landt is een losse draad; wie hem oppakt heeft het parswerk al klaar. **De belangrijkste beperking, en die staat als punt 11 in VERIFICATION.md:** alle testfixtures bouwen hun archief zélf. Er staat geen enkel bestand in de repo dat PowerPoint, Impress of Keynote werkelijk heeft weggeschreven. De parsers zijn dus tegen nagebouwde invoer beproefd, niet tegen de echte wereld — een paar echte presentaties erdoorheen halen is de meest waardevolle volgende toets. Hiermee is de reikwijdte van dit issue af; ik sluit het.
brenno 2026-07-24 16:35:54 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#772
No description provided.