From c524c9611f8605a431592892e3a0efbdc4b998af Mon Sep 17 00:00:00 2001 From: tibssy Date: Thu, 26 Mar 2026 02:17:31 +0000 Subject: [PATCH] feat(view): add smooth scroll animation for keyboard navigation in NListView and NGridView --- Widgets/NGridView.qml | 32 ++++++++++++++++++++++++++++++++ Widgets/NListView.qml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/Widgets/NGridView.qml b/Widgets/NGridView.qml index 17dc2d276..b43628107 100644 --- a/Widgets/NGridView.qml +++ b/Widgets/NGridView.qml @@ -112,6 +112,20 @@ Item { wheelScrollAnimation.restart(); } + function animateToContentY(targetY) { + const clampedY = root.clampScrollY(targetY); + + if (!Settings.data.general.smoothScrollEnabled || Settings.data.general.animationDisabled || gridView.dragging || gridView.flicking) { + gridView.contentY = clampedY; + root._wheelTargetY = clampedY; + return; + } + + root._wheelTargetY = clampedY; + wheelScrollAnimation.to = clampedY; + wheelScrollAnimation.restart(); + } + // Track selection index for gradient visibility (set externally) property int trackedSelectionIndex: -1 @@ -155,7 +169,25 @@ Item { // Forward GridView methods function positionViewAtIndex(index, mode) { + const shouldAnimate = mode === GridView.Contain; + if (!shouldAnimate) { + gridView.positionViewAtIndex(index, mode); + root._wheelTargetY = gridView.contentY; + return; + } + + const previousY = gridView.contentY; gridView.positionViewAtIndex(index, mode); + const targetY = root.clampScrollY(gridView.contentY); + + if (Math.abs(targetY - previousY) < 0.5) { + root._wheelTargetY = targetY; + return; + } + + gridView.contentY = previousY; + root._wheelTargetY = previousY; + root.animateToContentY(targetY); } function positionViewAtBeginning() { diff --git a/Widgets/NListView.qml b/Widgets/NListView.qml index e6bf0344a..4ea376cc2 100644 --- a/Widgets/NListView.qml +++ b/Widgets/NListView.qml @@ -100,9 +100,41 @@ Item { wheelScrollAnimation.restart(); } + function animateToContentY(targetY) { + const clampedY = root.clampScrollY(targetY); + + if (!Settings.data.general.smoothScrollEnabled || Settings.data.general.animationDisabled || listView.dragging || listView.flicking) { + listView.contentY = clampedY; + root._wheelTargetY = clampedY; + return; + } + + root._wheelTargetY = clampedY; + wheelScrollAnimation.to = clampedY; + wheelScrollAnimation.restart(); + } + // Forward ListView methods function positionViewAtIndex(index, mode) { + const shouldAnimate = mode === ListView.Contain; + if (!shouldAnimate) { + listView.positionViewAtIndex(index, mode); + root._wheelTargetY = listView.contentY; + return; + } + + const previousY = listView.contentY; listView.positionViewAtIndex(index, mode); + const targetY = root.clampScrollY(listView.contentY); + + if (Math.abs(targetY - previousY) < 0.5) { + root._wheelTargetY = targetY; + return; + } + + listView.contentY = previousY; + root._wheelTargetY = previousY; + root.animateToContentY(targetY); } function positionViewAtBeginning() {