From ce2a92ec2716aaa079d18bf1357aa9c1e75f15bd Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Thu, 2 Apr 2026 20:26:36 +0100 Subject: [PATCH] feat: rewind to track start on previous when past 8 seconds (#2136) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: rewind to track start on previous when past 8 seconds Adds MprisController.previousOrRewind() which rewinds the current track to position 0 if more than 8 seconds in (with canSeek check), and falls back to previous() otherwise — matching traditional media player behaviour. All previous() call sites across Media.qml, MediaPlayerTab.qml, MediaOverviewCard.qml, LockScreenContent.qml and DMSShellIPC.qml are updated to use the new shared function. Co-Authored-By: Claude Sonnet 4.6 * fix: poll position in MprisController for previousOrRewind accuracy Without a polling timer, activePlayer.position is never updated in contexts that don't display a seekbar (e.g. the DankBar widget), causing the position > 8 check in previousOrRewind() to always see 0 and fall through to previous() instead of rewinding. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- quickshell/DMSShellIPC.qml | 4 +--- quickshell/Modules/DankBar/Widgets/Media.qml | 12 ++++-------- quickshell/Modules/DankDash/MediaPlayerTab.qml | 12 +----------- .../DankDash/Overview/MediaOverviewCard.qml | 9 +-------- quickshell/Modules/Lock/LockScreenContent.qml | 2 +- quickshell/Services/MprisController.qml | 16 ++++++++++++++++ 6 files changed, 24 insertions(+), 31 deletions(-) diff --git a/quickshell/DMSShellIPC.qml b/quickshell/DMSShellIPC.qml index 85dcf82d..4a111c50 100644 --- a/quickshell/DMSShellIPC.qml +++ b/quickshell/DMSShellIPC.qml @@ -369,9 +369,7 @@ Item { } function previous(): void { - if (MprisController.activePlayer && MprisController.activePlayer.canGoPrevious) { - MprisController.activePlayer.previous(); - } + MprisController.previousOrRewind(); } function next(): void { diff --git a/quickshell/Modules/DankBar/Widgets/Media.qml b/quickshell/Modules/DankBar/Widgets/Media.qml index ae1f2ad7..453e2096 100644 --- a/quickshell/Modules/DankBar/Widgets/Media.qml +++ b/quickshell/Modules/DankBar/Widgets/Media.qml @@ -99,7 +99,7 @@ BasePill { if (isMouseWheelY) { if (deltaY > 0) { - activePlayer.previous(); + MprisController.previousOrRewind(); } else { activePlayer.next(); } @@ -107,7 +107,7 @@ BasePill { scrollAccumulatorY += deltaY; if (Math.abs(scrollAccumulatorY) >= touchpadThreshold) { if (scrollAccumulatorY > 0) { - activePlayer.previous(); + MprisController.previousOrRewind(); } else { activePlayer.next(); } @@ -214,7 +214,7 @@ BasePill { if (mouse.button === Qt.LeftButton) { activePlayer.togglePlaying(); } else if (mouse.button === Qt.MiddleButton) { - activePlayer.previous(); + MprisController.previousOrRewind(); } else if (mouse.button === Qt.RightButton) { activePlayer.next(); } @@ -370,11 +370,7 @@ BasePill { anchors.fill: parent enabled: root.playerAvailable cursorShape: Qt.PointingHandCursor - onClicked: { - if (activePlayer) { - activePlayer.previous(); - } - } + onClicked: MprisController.previousOrRewind() } } diff --git a/quickshell/Modules/DankDash/MediaPlayerTab.qml b/quickshell/Modules/DankDash/MediaPlayerTab.qml index c8efdaa3..c6d7bfce 100644 --- a/quickshell/Modules/DankDash/MediaPlayerTab.qml +++ b/quickshell/Modules/DankDash/MediaPlayerTab.qml @@ -487,17 +487,7 @@ Item { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: { - if (!activePlayer) { - return; - } - - if (activePlayer.position > 8 && activePlayer.canSeek) { - activePlayer.position = 0; - } else { - activePlayer.previous(); - } - } + onClicked: MprisController.previousOrRewind() } } } diff --git a/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml b/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml index d55b87c8..35f4f47e 100644 --- a/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml +++ b/quickshell/Modules/DankDash/Overview/MediaOverviewCard.qml @@ -145,14 +145,7 @@ Card { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: { - if (!activePlayer) return - if (activePlayer.position > 8 && activePlayer.canSeek) { - activePlayer.position = 0 - } else { - activePlayer.previous() - } - } + onClicked: MprisController.previousOrRewind() } } diff --git a/quickshell/Modules/Lock/LockScreenContent.qml b/quickshell/Modules/Lock/LockScreenContent.qml index c96affa9..b296e98d 100644 --- a/quickshell/Modules/Lock/LockScreenContent.qml +++ b/quickshell/Modules/Lock/LockScreenContent.qml @@ -1338,7 +1338,7 @@ Item { enabled: MprisController.activePlayer?.canGoPrevious ?? false hoverEnabled: enabled cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: MprisController.activePlayer?.previous() + onClicked: MprisController.previousOrRewind() } } diff --git a/quickshell/Services/MprisController.qml b/quickshell/Services/MprisController.qml index d0962b54..48b99461 100644 --- a/quickshell/Services/MprisController.qml +++ b/quickshell/Services/MprisController.qml @@ -10,4 +10,20 @@ Singleton { readonly property list availablePlayers: Mpris.players.values property MprisPlayer activePlayer: availablePlayers.find(p => p.isPlaying) ?? availablePlayers.find(p => p.canControl && p.canPlay) ?? null + + Timer { + interval: 1000 + running: root.activePlayer?.playbackState === MprisPlaybackState.Playing + repeat: true + onTriggered: root.activePlayer?.positionChanged() + } + + function previousOrRewind(): void { + if (!activePlayer) + return; + if (activePlayer.position > 8 && activePlayer.canSeek) + activePlayer.position = 0; + else if (activePlayer.canGoPrevious) + activePlayer.previous(); + } }