A minimal, deterministic DankMaterialShell plugin that demonstrates the DankListView
zero-duration ViewTransition bug and the proposed fix, side by side.
The popout has two panes over the same static 240-row ScriptModel, the same
delegate, and the same DankListView - differing only in the four ListView
transitions (add / remove / displaced / move):
- Base - ships today leaves them at the shipped
ListViewTransitions.*defaults. - Proposed fix nulls them when the effective duration truncates to 0ms.
A readout line shows the current animation base, the derived remove/add duration, and
whether the fix gate runs or nulls the transition.
When a transition's duration is 0ms it still engages ListView's ViewTransition
machinery but resolves within the same frame, so removed delegates are never released and
displaced items are never repositioned. On a model that re-filters per keystroke this
leaves stale rows and empty gaps behind.
It happens at two animation settings:
- None (base duration 0), and
- a Custom duration of 1-2ms, because the shortest sub-duration
(
remove/add=Theme.expressiveDurations.fast/expressiveEffects=base * 0.4) is coerced to anint, which truncates:1*0.4=0.4 -> 0,2*0.4=0.8 -> 0, and only3*0.4=1.2 -> 1survives. So the cliff is base < 3.
| animation base | remove/add = floor(base*0.4) | result |
|---|---|---|
| 0 (None) | 0 | broken |
| 1 | 0 | broken |
| 2 | 0 | broken |
| 3 | 1 | ok |
- Copy this folder to
~/.config/DankMaterialShell/plugins/listviewRepro/. - Enable ListView Repro in Settings -> Plugins, and add its widget to a bar section.
- Click the Repro pill to open the popout.
- Set animation speed to None, or a Custom duration of 1 / 2 / 3 ms (Settings -> the animation speed control).
- Type a filter (
systemd,gvfs,brave,zsh) or hit Auto-stress.
At 0/1/2ms the Base pane shows stale rows and gaps while the Proposed fix pane stays clean. At >= 3ms both animate and both are fine.
The fix gates the transitions in quickshell/Common/ListViewTransitions.qml:
readonly property bool enabled: Math.floor(Theme.currentAnimationBaseDuration * 0.4) >= 1
readonly property Transition add: enabled ? _add : null
// ...remove / displaced / move likewiseA view transition is then never a 0ms Transition object - it is either null (instant,
correct) or >= 1ms (runs correctly).