fix(video): stel afspeelpunt-clear uit buiten de gelockte widgettree (#1114) #1120

Merged
brenno merged 1 commit from fix/video-playhead-clear-locked-tree-1114 into main 2026-08-02 09:59:29 +00:00
Owner

Wat & waarom

Bij het verlaten van een dia met (afspelende) video kon Flutter crashen met:

setState() or markNeedsBuild() called when widget tree was locked.
This ValueListenableBuilder<VideoPlayhead?> widget cannot be marked as needing to build
because the framework is locked.

VideoPlayheadBus.clearFor wiste het gepubliceerde afspeelpunt synchroon in
dispose(). Dispose draait tijdens BuildOwner.finalizeTree — de element-tree
is dan gelockt. De video-editor luistert live mee via de "Knip hier"-knop
(ValueListenableBuilder<VideoPlayhead?>); diens setState valt onder de lock
en gooit de assertie. Beide dispose-paden raken het (_VideoPreviewState en
_VideoEmbedPreviewState), dus de fix zit centraal in de bus.

Aanpak

  • Draait er een frame (SchedulerBinding.schedulerPhase == persistentCallbacks),
    dan stelt clearFor de clear uit tot ná het frame (addPostFrameCallback).
  • Anders (idle) wist hij synchroon, zoals voorheen.
  • De bestaande slideId-guard maakt de uitgestelde clear een no-op als een
    andere dia intussen zelf een afspeelpunt heeft gepubliceerd — er wordt dus
    nooit een vers afspeelpunt weggegooid.

Test

test/video_playhead_bus_test.dart reproduceert de exacte assertie zónder de fix
(rood) en is groen mét de fix: een live ValueListenableBuilder op de bus plus
een widget die in dispose() clearFor aanroept, verwijderd tijdens een pump
(zodat dispose onder de tree-lock draait).

Closes #1114

## Wat & waarom Bij het verlaten van een dia met (afspelende) video kon Flutter crashen met: ``` setState() or markNeedsBuild() called when widget tree was locked. This ValueListenableBuilder<VideoPlayhead?> widget cannot be marked as needing to build because the framework is locked. ``` `VideoPlayheadBus.clearFor` wiste het gepubliceerde afspeelpunt **synchroon** in `dispose()`. Dispose draait tijdens `BuildOwner.finalizeTree` — de element-tree is dan gelockt. De video-editor luistert live mee via de "Knip hier"-knop (`ValueListenableBuilder<VideoPlayhead?>`); diens `setState` valt onder de lock en gooit de assertie. Beide dispose-paden raken het (`_VideoPreviewState` en `_VideoEmbedPreviewState`), dus de fix zit centraal in de bus. ## Aanpak - Draait er een frame (`SchedulerBinding.schedulerPhase == persistentCallbacks`), dan stelt `clearFor` de clear uit tot ná het frame (`addPostFrameCallback`). - Anders (idle) wist hij synchroon, zoals voorheen. - De bestaande `slideId`-guard maakt de uitgestelde clear een no-op als een andere dia intussen zelf een afspeelpunt heeft gepubliceerd — er wordt dus nooit een vers afspeelpunt weggegooid. ## Test `test/video_playhead_bus_test.dart` reproduceert de exacte assertie zónder de fix (rood) en is groen mét de fix: een live `ValueListenableBuilder` op de bus plus een widget die in `dispose()` `clearFor` aanroept, verwijderd tijdens een pump (zodat dispose onder de tree-lock draait). Closes #1114
fix(video): stel afspeelpunt-clear uit buiten de gelockte widgettree (#1114)
All checks were successful
scans / scans (pull_request) Successful in 3m42s
67d56bf6fb
VideoPlayheadBus.clearFor wiste het gepubliceerde afspeelpunt synchroon vanuit
dispose(). Dispose draait tijdens BuildOwner.finalizeTree — de element-tree is
dan gelockt. De live meeluisterende "Knip hier"-ValueListenableBuilder in de
video-editor herbouwde daardoor onder de lock en gooide
"setState() ... called when widget tree was locked". Beide dispose-paden
(_VideoPreviewState en _VideoEmbedPreviewState) raken het, dus centraal in de
bus opgelost: bij een lopend frame (schedulerPhase == persistentCallbacks) de
clear uitstellen tot post-frame, anders synchroon wissen. De slideId-guard
beschermt een intussen door een andere dia gepubliceerd afspeelpunt.

Regressietest test/video_playhead_bus_test.dart reproduceert de assertie zonder
de fix en is groen met de fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brenno merged commit 07a35186d9 into main 2026-08-02 09:59:29 +00:00
brenno deleted branch fix/video-playhead-clear-locked-tree-1114 2026-08-02 09:59:30 +00:00
Sign in to join this conversation.
No description provided.