From 3d60f3568354c12f020ed9447fdef70cc2d0c7fa Mon Sep 17 00:00:00 2001 From: 14Do <138010054+14Do@users.noreply.github.com> Date: Fri, 10 Jul 2026 00:47:26 +0200 Subject: [PATCH] fix(ListViewTransitions): null transitions when duration truncates to 0ms (#2791) A zero-duration ViewTransition still engages ListView's transition machinery but resolves within the same frame, so removed delegates are never released and displaced items are never repositioned. On a filtered ScriptModel that re-filters on every keystroke this leaves stale rows and empty gaps behind, visible in any DankListView-backed list. The shortest sub-duration (remove/add = expressiveDurations.fast = base * 0.4) is coerced to an int, so it truncates to 0ms for any animation base duration below 3: animation speed None (0), or a Custom duration of 1-2ms (1*0.4=0.4->0, 2*0.4=0.8->0, only 3*0.4=1.2->1 survives). Presets (250/500/750) are unaffected, which is why this only reproduces with animations disabled or a very small custom value. Gate the four transitions to null whenever that shortest sub-duration would truncate to 0, so the view takes the correct instant path instead of a broken 0ms transition. Base >= 3 is unchanged. (cherry picked from commit ce1595d62ddc987bfdaba5f3ea9c0a187b099069) --- quickshell/Common/ListViewTransitions.qml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/quickshell/Common/ListViewTransitions.qml b/quickshell/Common/ListViewTransitions.qml index 2ccefc806..57e8f1192 100644 --- a/quickshell/Common/ListViewTransitions.qml +++ b/quickshell/Common/ListViewTransitions.qml @@ -9,7 +9,16 @@ import qs.Common Singleton { id: root - readonly property Transition add: Transition { + // 0ms ViewTransitions break ListView delegate cleanup, so null the set when the shortest + // duration truncates to 0. Keep this gate - don't inline these back into add/remove/etc. + readonly property bool enabled: Math.floor(Theme.currentAnimationBaseDuration * 0.4) >= 1 + + readonly property Transition add: enabled ? _add : null + readonly property Transition remove: enabled ? _remove : null + readonly property Transition displaced: enabled ? _displaced : null + readonly property Transition move: enabled ? _move : null + + readonly property Transition _add: Transition { DankAnim { property: "opacity" from: 0 @@ -19,7 +28,7 @@ Singleton { } } - readonly property Transition remove: Transition { + readonly property Transition _remove: Transition { DankAnim { property: "opacity" to: 0 @@ -28,7 +37,7 @@ Singleton { } } - readonly property Transition displaced: Transition { + readonly property Transition _displaced: Transition { DankAnim { property: "y" duration: Theme.expressiveDurations.normal @@ -36,7 +45,7 @@ Singleton { } } - readonly property Transition move: Transition { + readonly property Transition _move: Transition { DankAnim { property: "y" duration: Theme.expressiveDurations.normal