1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-13 09:12:08 -04:00

Improve seek and scrub indicator/ animations in the media controls widget. (#2181)

This commit is contained in:
Ron Harel
2026-04-09 17:35:56 +03:00
committed by GitHub
parent 32c063aab8
commit 0eabda3164
2 changed files with 236 additions and 86 deletions

View File

@@ -6,6 +6,8 @@ Item {
id: root
property real value: 0
property real actualValue: value
property bool showActualPlaybackState: false
property real lineWidth: 2
property real wavelength: 20
property real amp: 1.6
@@ -15,6 +17,7 @@ Item {
property color trackColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.40)
property color fillColor: Theme.primary
property color playheadColor: Theme.primary
property color actualProgressColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.45)
property real dpr: (root.window ? root.window.devicePixelRatio : 1)
function snap(v) {
@@ -22,7 +25,12 @@ Item {
}
readonly property real playX: snap(root.width * root.value)
readonly property real actualX: snap(root.width * root.actualValue)
readonly property real midY: snap(height / 2)
readonly property bool previewAhead: root.showActualPlaybackState && root.value > root.actualValue
readonly property bool previewBehind: root.showActualPlaybackState && root.value < root.actualValue
readonly property real previewGapStartX: Math.min(root.playX, root.actualX)
readonly property real previewGapEndX: Math.max(root.playX, root.actualX)
Behavior on currentAmp {
NumberAnimation {
@@ -65,7 +73,9 @@ Item {
readonly property real startX: snap(root.lineWidth / 2)
readonly property real aaBias: (0.25 / root.dpr)
readonly property real endX: Math.max(startX, Math.min(root.playX - startX - aaBias, width))
readonly property real endX: root.previewAhead ? Math.max(startX, Math.min(root.actualX - aaBias, width)) : Math.max(startX, Math.min(root.playX - startX - aaBias, width))
readonly property real gapStartX: root.previewAhead ? Math.max(startX, Math.min(root.actualX + aaBias, width)) : Math.max(startX, Math.min(root.playX + playhead.width / 2, width))
readonly property real gapEndX: root.previewAhead ? Math.max(gapStartX, Math.min(root.playX - playhead.width / 2 - aaBias, width)) : Math.max(gapStartX, Math.min(root.actualX - aaBias, width))
Rectangle {
id: mask
@@ -100,6 +110,37 @@ Item {
}
}
Rectangle {
id: actualMask
anchors.top: parent.top
anchors.bottom: parent.bottom
x: waveClip.gapStartX
width: Math.max(0, waveClip.gapEndX - waveClip.gapStartX)
color: "transparent"
clip: true
visible: (root.previewBehind || root.previewAhead) && width > 0
Shape {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: root.width + 4 * root.wavelength
antialiasing: true
preferredRendererType: Shape.CurveRenderer
x: waveOffsetX
ShapePath {
strokeColor: root.actualProgressColor
strokeWidth: snap(root.lineWidth)
capStyle: ShapePath.RoundCap
joinStyle: ShapePath.RoundJoin
fillColor: "transparent"
PathSvg {
path: waveSvg.path
}
}
}
}
Rectangle {
id: startCap
width: snap(root.lineWidth)
@@ -107,7 +148,7 @@ Item {
radius: width / 2
color: root.fillColor
x: waveClip.startX - width / 2
y: root.midY - height / 2 + root.currentAmp * Math.sin((waveClip.startX / root.wavelength) * 2 * Math.PI + root.phase)
y: waveY(waveClip.startX) - height / 2
visible: waveClip.endX > waveClip.startX
z: 2
}
@@ -119,10 +160,34 @@ Item {
radius: width / 2
color: root.fillColor
x: waveClip.endX - width / 2
y: root.midY - height / 2 + root.currentAmp * Math.sin((waveClip.endX / root.wavelength) * 2 * Math.PI + root.phase)
y: waveY(waveClip.endX) - height / 2
visible: waveClip.endX > waveClip.startX
z: 2
}
Rectangle {
id: actualEndCap
width: snap(root.lineWidth)
height: snap(root.lineWidth)
radius: width / 2
color: root.actualProgressColor
x: waveClip.gapEndX - width / 2
y: waveY(waveClip.gapEndX) - height / 2
visible: (root.previewBehind || root.previewAhead) && actualMask.width > 0
z: 2
}
Rectangle {
id: actualMarker
width: 2
height: Math.max(root.lineWidth + 4, 10)
radius: width / 2
color: root.actualProgressColor
x: root.actualX - width / 2
y: root.midY - height / 2
visible: root.showActualPlaybackState
z: 2
}
}
Rectangle {
@@ -141,6 +206,10 @@ Item {
let r = a % m;
return r < 0 ? r + m : r;
}
function waveY(x, amplitude = root.currentAmp, phaseOffset = root.phase) {
return root.midY + amplitude * Math.sin((x / root.wavelength) * 2 * Math.PI + phaseOffset);
}
readonly property real waveOffsetX: -wrapMod(phase / k, wavelength)
FrameAnimation {
@@ -148,8 +217,9 @@ Item {
onTriggered: {
if (root.isPlaying)
root.phase += 0.03 * frameTime * 60;
startCap.y = root.midY - startCap.height / 2 + root.currentAmp * Math.sin((waveClip.startX / root.wavelength) * 2 * Math.PI + root.phase);
endCap.y = root.midY - endCap.height / 2 + root.currentAmp * Math.sin((waveClip.endX / root.wavelength) * 2 * Math.PI + root.phase);
startCap.y = waveY(waveClip.startX) - startCap.height / 2;
endCap.y = waveY(waveClip.endX) - endCap.height / 2;
actualEndCap.y = waveY(waveClip.gapEndX) - actualEndCap.height / 2;
}
}