diff --git a/Helpers/Searcher.qml b/Helpers/Searcher.qml index d03bc41..23f15e5 100644 --- a/Helpers/Searcher.qml +++ b/Helpers/Searcher.qml @@ -26,7 +26,6 @@ Singleton { function query(search: string): list { search = transformSearch(search); - console.log(!search, search, ...list); if (!search) return [...list]; diff --git a/Plugins/ZShell/Components/carouselview.cpp b/Plugins/ZShell/Components/carouselview.cpp index c1341d5..70776fe 100644 --- a/Plugins/ZShell/Components/carouselview.cpp +++ b/Plugins/ZShell/Components/carouselview.cpp @@ -46,7 +46,7 @@ CarouselView::CarouselView(QQuickItem* parent) : QQuickItem(parent) { }); m_flickAnim = new QVariantAnimation(this); - m_flickAnim->setEasingCurve(QEasingCurve::Linear); + m_flickAnim->setEasingCurve(QEasingCurve::OutQuad); connect( m_flickAnim, @@ -101,9 +101,8 @@ bool CarouselView::childMouseEventFilter(QQuickItem* item, QEvent* event) { m_dragTimer.start(); - m_lastMoveX = pos.x(); - m_lastMoveT = 0; - m_velocity = 0; + m_velocitySamples.clear(); + addVelocitySample(0, pos.x()); return false; } @@ -129,17 +128,7 @@ bool CarouselView::childMouseEventFilter(QQuickItem* item, QEvent* event) { updateCurrentIndexFromContentX(true); relayout(); - const qint64 t = m_dragTimer.elapsed(); - const qint64 dt = t - m_lastMoveT; - - if (dt > 0) { - const qreal instVel = (m_lastMoveX - pos.x()) / (dt / 1000.0); - - m_velocity = m_velocity * 0.7 + instVel * 0.3; - } - - m_lastMoveX = pos.x(); - m_lastMoveT = t; + addVelocitySample(m_dragTimer.elapsed(), pos.x()); mouseEvent->accept(); return true; @@ -1141,10 +1130,8 @@ void CarouselView::mousePressEvent(QMouseEvent* event) { m_dragTimer.start(); - m_lastMoveX = event->position().x(); - - m_lastMoveT = 0; - m_velocity = 0; + m_velocitySamples.clear(); + addVelocitySample(0, event->position().x()); event->accept(); } @@ -1170,32 +1157,43 @@ void CarouselView::mouseMoveEvent(QMouseEvent* event) { updateCurrentIndexFromContentX(true); relayout(); - const qint64 t = m_dragTimer.elapsed(); - - const qint64 dt = t - m_lastMoveT; - - if (dt > 0) { - const qreal instVel = - (m_lastMoveX - event->position().x()) / (dt / 1000.0); - - m_velocity = m_velocity * 0.7 + instVel * 0.3; - } - - m_lastMoveX = event->position().x(); - - m_lastMoveT = t; + addVelocitySample(m_dragTimer.elapsed(), event->position().x()); event->accept(); } +void CarouselView::addVelocitySample(qint64 t, qreal x) { + m_velocitySamples.append({t, x}); + + while (m_velocitySamples.size() > 1 && + t - m_velocitySamples.first().t > kVelocitySampleWindowMs) { + m_velocitySamples.removeFirst(); + } +} + +qreal CarouselView::sampledVelocity() const { + if (m_velocitySamples.size() < 2) return 0; + + const VelocitySample& oldest = m_velocitySamples.first(); + const VelocitySample& newest = m_velocitySamples.last(); + + const qreal dt = newest.t - oldest.t; + + if (dt < 8) return 0; + + return (oldest.x - newest.x) / (dt / 1000.0); +} + void CarouselView::mouseReleaseEvent(QMouseEvent* event) { if (!m_dragging) return; m_dragging = false; + const bool wasDragActive = m_dragActive; + ungrabMouse(); - if (!m_dragActive) { + if (!wasDragActive) { cancelAnimations(); snapToNearest(); @@ -1205,7 +1203,7 @@ void CarouselView::mouseReleaseEvent(QMouseEvent* event) { m_dragActive = false; - qreal v = qBound(-kMaxFlickVelocity, m_velocity, kMaxFlickVelocity); + qreal v = qBound(-kMaxFlickVelocity, sampledVelocity(), kMaxFlickVelocity); if (std::abs(v) < kMinFlickVelocity) { snapToNearest(); @@ -1215,24 +1213,17 @@ void CarouselView::mouseReleaseEvent(QMouseEvent* event) { } const qreal duration = std::abs(v) / (kFlickFriction * 1000.0); - const qreal distance = (v * (duration / 1000.0)) / 2.0; - const qreal rawDest = m_contentX + distance; - const qreal dest = contentXForIndex(indexForContentX(rawDest)); cancelAnimations(); m_flickAnim->setDuration( static_cast(qBound(120, duration, 900))); - - m_flickAnim->setEasingCurve(QEasingCurve::OutCubic); - + m_flickAnim->setEasingCurve(QEasingCurve::OutQuad); m_flickAnim->setStartValue(m_contentX); - m_flickAnim->setEndValue(dest); - m_flickAnim->start(); event->accept(); diff --git a/Plugins/ZShell/Components/carouselview.hpp b/Plugins/ZShell/Components/carouselview.hpp index 14dea74..3f98b35 100644 --- a/Plugins/ZShell/Components/carouselview.hpp +++ b/Plugins/ZShell/Components/carouselview.hpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace ZShell::components { @@ -150,6 +152,11 @@ class CarouselView : public QQuickItem { bool active = false; }; + struct VelocitySample { + qint64 t; + qreal x; + }; + void rebuildArrangement(); void relayout(); @@ -190,6 +197,9 @@ class CarouselView : public QQuickItem { QQuickItem* acquireItem(); void releaseAllItems(); + void addVelocitySample(qint64 t, qreal x); + qreal sampledVelocity() const; + QQmlComponent* m_delegate = nullptr; QVariantList m_model; QVariantMap m_delegateProperties; @@ -226,9 +236,9 @@ class CarouselView : public QQuickItem { qreal m_pressContentX = 0; QElapsedTimer m_dragTimer; - qreal m_lastMoveX = 0; - qint64 m_lastMoveT = 0; - qreal m_velocity = 0; + + QVector m_velocitySamples; + static constexpr qint64 kVelocitySampleWindowMs = 80; QVariantAnimation* m_flickAnim = nullptr;