Tabelwerkbalk op desktop: rij toevoegen laat de werkbalk onder de cursor verdwijnen — focus en soms de actie gaan verloren #2140
Labels
No labels
accepted
bug
declined
docs
duplicate
enhancement
good first issue
in-progress
needs-info
privacy
release-blocker
security
triage
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
LibreKAT/Ocideck#2140
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptoom
In de documenteditor springt de focus weg zodra je via de tabelwerkbalk een rij toevoegt ("Rij eronder"/"Rij erboven"; dezelfde race zit in de kolomknoppen). Op desktop (macOS) komt bij een normale muisklik de rij vaak niet eens aan: de werkbalk verdwijnt onder de cursor vóór pointer-up, waardoor
onPressednooit vuurt. Bij een snelle klik kan de actie nét binnenkomen — dan komt de rij er wél maar landt de focus nergens, want de retentie is dan al opgeruimd. Beide varianten lezen als "de focus springt weg van waar ik stond".Oorzaak — een frame-race in de actieve-cel-retentie
TableEditScaffoldtoont de werkbalk alleen alseditor.activeCell != null(table_edit_scaffold.dart~L112). De verdediging tegen werkbalk-taps bestaat uit twee post-frame-callbacks wiens volgorde ongunstig uitpakt:Listener.onPointerDown→holdActiveCell()(table_edit_controller.dart~L92): zet_holdActiveCell = trueen plant de reset als post-frame-callback.EditableText.onTapOutsidedat (mobiel niet!).setActiveCell(focused: false)(~L99-120) plant zijn eigen uitgestelde check._holdActiveCell = false), dan de blur-check — die ziet nu_holdActiveCell == false,_pendingFocus == null,_focusScheduled == false, geen cel-focus →_activeCell = null.onPressedvuurt niet → niets gebeurt, focus staat op de FocusScope.En zelfs als
onPressednog meekomt:insertRowAt(~L429) leest_activeCell— is die al gewist, dan slaat_retainActiveAfterStructureover en wordt er geen_focusAfterRebuildgepland → geen refocus → focus weg.Waarom Visueel en Enter/Tab niet stuk zijn: in de visuele stand valt de werkbalk binnen Quill's
EditableText-TapRegion, dus geldt de tap als "inside" en blurt de cel niet (gemeten: celFocus blijfttruena pointer-down). Enter/Tab op de laatste rij roepen_focusAfterRebuildonvoorwaardelijk aan, zonder_activeCellnodig te hebben — die werken. Het Bron-preview-/documentoppervlak enTableEditor(dia's) hebben geen omhullende EditableText en zijn wél kwetsbaar.Waarom de tests dit niet vingen: widget-tests draaien als Android, waar
onTapOutsidenooit unfocust — het blurpad wordt dus nooit betreden. De bestaande retentietests roepenfocusNode.unfocus()en daarna synchroon de actie aan; de echte race zit tussen de frames van één muisklik.Reproductie
Widget-test op
DocumentEditorScreenin Bron-stand, metdebugDefaultTargetPlatformOverride = TargetPlatform.macOSen echte pointer-timing:Oplossingsrichting
Maak de retentie niet afhankelijk van post-frame-volgorde, maar van de interactie zelf:
holdActiveCellmoet de hold vasthouden tot de pointer-interactie eindigt, niet één frame:onPointerUp/onPointerCancel(ofonTapCancel) op deListenerlaten de reset pas náonPressedlopen. Dan staat_activeCellgegarandeerd nog bijonPressed, eninsertRowAt→_retainActiveAfterStructure→_focusAfterRebuild→ de bestaande refocusketen (_pendingFocus→takePendingFocus→focusCell) werkt zoals ontworpen._heldCell-veld dat bij pointer-down deactiveCellvastlegt en pas bij pointer-up opruimt, en de blur-check laat_heldCellmeewegen.TargetPlatform.macOSenstartGesturemet frames tussen down en up — dat is de enige as die deze race zichtbaar maakt. Ideaal als één test die beweert: na "Rij eronder" staat er een rij meer in de bron én heeft een tabelcel de focus.Betreffende plekken:
lib/widgets/reader/table_edit_controller.dart(holdActiveCell,setActiveCell,insertRowAt,_retainActiveAfterStructure),lib/widgets/reader/table_edit_scaffold.dart(toolbar-Listener,active == null→ werkbalk weg).