mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-06-05 14:59:27 -05:00
make media control seekable (closes #1615)
This commit is contained in:
@@ -72,8 +72,8 @@ RippleButton {
|
||||
Layout.bottomMargin: 5
|
||||
Layout.fillWidth: true
|
||||
value: 0.7
|
||||
sperm: true
|
||||
animateSperm: lightDarkButtonRoot.toggled
|
||||
wavy: true
|
||||
animateWave: lightDarkButtonRoot.toggled
|
||||
highlightColor: lightDarkButtonRoot.toggled ? Appearance.m3colors.m3primary : lightDarkButtonRoot.previewFg
|
||||
trackColor: ColorUtils.mix(lightDarkButtonRoot.previewBg, lightDarkButtonRoot.previewFg, 0.5)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import qs.services
|
||||
pragma ComponentBehavior: Bound
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
|
||||
/**
|
||||
* Material 3 progress bar. See https://m3.material.io/components/progress-indicators/overview
|
||||
@@ -18,13 +15,13 @@ ProgressBar {
|
||||
property real valueBarGap: 4
|
||||
property color highlightColor: Appearance?.colors.colPrimary ?? "#685496"
|
||||
property color trackColor: Appearance?.m3colors.m3secondaryContainer ?? "#F1D3F9"
|
||||
property bool sperm: false // If true, the progress bar will have a wavy fill effect
|
||||
property bool animateSperm: true
|
||||
property real spermAmplitudeMultiplier: sperm ? 0.5 : 0
|
||||
property real spermFrequency: 6
|
||||
property real spermFps: 60
|
||||
property bool wavy: false // If true, the progress bar will have a wavy fill effect
|
||||
property bool animateWave: true
|
||||
property real waveAmplitudeMultiplier: wavy ? 0.5 : 0
|
||||
property real waveFrequency: 6
|
||||
property real waveFps: 60
|
||||
|
||||
Behavior on spermAmplitudeMultiplier {
|
||||
Behavior on waveAmplitudeMultiplier {
|
||||
animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
@@ -38,64 +35,62 @@ ProgressBar {
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
id: contentItem
|
||||
anchors.fill: parent
|
||||
|
||||
Canvas {
|
||||
id: wavyFill
|
||||
Loader {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
height: parent.height * 6
|
||||
onPaint: {
|
||||
var ctx = getContext("2d");
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
var progress = root.visualPosition;
|
||||
var fillWidth = progress * width;
|
||||
var amplitude = parent.height * root.spermAmplitudeMultiplier;
|
||||
var frequency = root.spermFrequency;
|
||||
var phase = Date.now() / 400.0;
|
||||
var centerY = height / 2;
|
||||
|
||||
ctx.strokeStyle = root.highlightColor;
|
||||
ctx.lineWidth = parent.height;
|
||||
ctx.lineCap = "round";
|
||||
ctx.beginPath();
|
||||
for (var x = ctx.lineWidth / 2; x <= fillWidth; x += 1) {
|
||||
var waveY = centerY + amplitude * Math.sin(frequency * 2 * Math.PI * x / width + phase);
|
||||
if (x === 0)
|
||||
ctx.moveTo(x, waveY);
|
||||
else
|
||||
ctx.lineTo(x, waveY);
|
||||
active: root.wavy
|
||||
sourceComponent: WavyLine {
|
||||
id: wavyFill
|
||||
frequency: root.waveFrequency
|
||||
color: root.highlightColor
|
||||
amplitudeMultiplier: root.wavy ? 0.5 : 0
|
||||
height: contentItem.height * 6
|
||||
width: contentItem.width * root.visualPosition
|
||||
lineWidth: contentItem.height
|
||||
fullLength: root.width
|
||||
Connections {
|
||||
target: root
|
||||
function onValueChanged() { wavyFill.requestPaint(); }
|
||||
function onHighlightColorChanged() { wavyFill.requestPaint(); }
|
||||
}
|
||||
FrameAnimation {
|
||||
running: root.animateWave
|
||||
onTriggered: {
|
||||
wavyFill.requestPaint()
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
Connections {
|
||||
target: root
|
||||
function onValueChanged() { wavyFill.requestPaint(); }
|
||||
function onHighlightColorChanged() { wavyFill.requestPaint(); }
|
||||
}
|
||||
Timer {
|
||||
interval: 1000 / root.spermFps
|
||||
running: root.animateSperm
|
||||
repeat: root.sperm
|
||||
onTriggered: wavyFill.requestPaint()
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: !root.wavy
|
||||
sourceComponent: Rectangle {
|
||||
anchors.left: parent.left
|
||||
width: contentItem.width * root.visualPosition
|
||||
height: contentItem.height
|
||||
radius: height / 2
|
||||
color: root.highlightColor
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { // Right remaining part fill
|
||||
anchors.right: parent.right
|
||||
width: (1 - root.visualPosition) * parent.width - valueBarGap
|
||||
height: parent.height
|
||||
radius: Appearance?.rounding.full ?? 9999
|
||||
radius: height / 2
|
||||
color: root.trackColor
|
||||
}
|
||||
|
||||
Rectangle { // Stop point
|
||||
anchors.right: parent.right
|
||||
width: valueBarGap
|
||||
height: valueBarGap
|
||||
radius: Appearance?.rounding.full ?? 9999
|
||||
radius: height / 2
|
||||
color: root.highlightColor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.services
|
||||
@@ -17,6 +18,7 @@ Slider {
|
||||
|
||||
property list<real> stopIndicatorValues: [1]
|
||||
enum Configuration {
|
||||
Wavy = 4,
|
||||
XS = 12,
|
||||
S = 18,
|
||||
M = 30,
|
||||
@@ -28,10 +30,9 @@ Slider {
|
||||
|
||||
property real handleDefaultWidth: 3
|
||||
property real handlePressedWidth: 1.5
|
||||
|
||||
property color highlightColor: Appearance.colors.colPrimary
|
||||
property color trackColor: Appearance.colors.colSecondaryContainer
|
||||
property color handleColor: Appearance.m3colors.m3onSecondaryContainer
|
||||
property color handleColor: Appearance.colors.colPrimary
|
||||
property color dotColor: Appearance.m3colors.m3onSecondaryContainer
|
||||
property color dotColorHighlighted: Appearance.m3colors.m3onPrimary
|
||||
property real unsharpenRadius: Appearance.rounding.unsharpen
|
||||
@@ -39,15 +40,18 @@ Slider {
|
||||
property real trackRadius: trackWidth >= StyledSlider.Configuration.XL ? 21
|
||||
: trackWidth >= StyledSlider.Configuration.L ? 12
|
||||
: trackWidth >= StyledSlider.Configuration.M ? 9
|
||||
: 6
|
||||
property real handleHeight: Math.max(33, trackWidth + 9)
|
||||
: trackWidth >= StyledSlider.Configuration.S ? 6
|
||||
: height / 2
|
||||
property real handleHeight: (configuration === StyledSlider.Configuration.Wavy) ? 24 : Math.max(33, trackWidth + 9)
|
||||
property real handleWidth: root.pressed ? handlePressedWidth : handleDefaultWidth
|
||||
property real handleMargins: 4
|
||||
onHandleMarginsChanged: {
|
||||
console.log("Handle margins changed to", handleMargins);
|
||||
}
|
||||
property real trackDotSize: 3
|
||||
property string tooltipContent: `${Math.round(value * 100)}%`
|
||||
property bool wavy: configuration === StyledSlider.Configuration.Wavy // If true, the progress bar will have a wavy fill effect
|
||||
property bool animateWave: true
|
||||
property real waveAmplitudeMultiplier: wavy ? 0.5 : 0
|
||||
property real waveFrequency: 6
|
||||
property real waveFps: 60
|
||||
|
||||
leftPadding: handleMargins
|
||||
rightPadding: handleMargins
|
||||
@@ -93,18 +97,51 @@ Slider {
|
||||
implicitHeight: trackWidth
|
||||
|
||||
// Fill left
|
||||
Rectangle {
|
||||
Loader {
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
}
|
||||
width: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins)
|
||||
height: trackWidth
|
||||
color: root.highlightColor
|
||||
topLeftRadius: root.trackRadius
|
||||
bottomLeftRadius: root.trackRadius
|
||||
topRightRadius: root.unsharpenRadius
|
||||
bottomRightRadius: root.unsharpenRadius
|
||||
height: root.trackWidth
|
||||
active: !root.wavy
|
||||
sourceComponent: Rectangle {
|
||||
color: root.highlightColor
|
||||
topLeftRadius: root.trackRadius
|
||||
bottomLeftRadius: root.trackRadius
|
||||
topRightRadius: root.unsharpenRadius
|
||||
bottomRightRadius: root.unsharpenRadius
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
}
|
||||
width: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins)
|
||||
height: root.height
|
||||
active: root.wavy
|
||||
sourceComponent: WavyLine {
|
||||
id: wavyFill
|
||||
frequency: root.waveFrequency
|
||||
fullLength: root.width
|
||||
color: root.highlightColor
|
||||
amplitudeMultiplier: root.wavy ? 0.5 : 0
|
||||
width: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins)
|
||||
height: root.trackWidth
|
||||
Connections {
|
||||
target: root
|
||||
function onValueChanged() { wavyFill.requestPaint(); }
|
||||
function onHighlightColorChanged() { wavyFill.requestPaint(); }
|
||||
}
|
||||
FrameAnimation {
|
||||
running: root.animateWave
|
||||
onTriggered: {
|
||||
wavyFill.requestPaint()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill right
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import qs.modules.common
|
||||
import QtQuick
|
||||
|
||||
Canvas {
|
||||
id: root
|
||||
property real amplitudeMultiplier: 0.5
|
||||
property real frequency: 6
|
||||
property color color: Appearance?.colors.colPrimary ?? "#685496"
|
||||
property real lineWidth: 4
|
||||
property real fullLength: width
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d");
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
var amplitude = root.lineWidth * root.amplitudeMultiplier;
|
||||
var frequency = root.frequency;
|
||||
var phase = Date.now() / 400.0;
|
||||
var centerY = height / 2;
|
||||
|
||||
ctx.strokeStyle = root.color;
|
||||
ctx.lineWidth = root.lineWidth;
|
||||
ctx.lineCap = "round";
|
||||
ctx.beginPath();
|
||||
for (var x = ctx.lineWidth / 2; x <= root.width - ctx.lineWidth / 2; x += 1) {
|
||||
var waveY = centerY + amplitude * Math.sin(frequency * 2 * Math.PI * x / root.fullLength + phase);
|
||||
if (x === 0)
|
||||
ctx.moveTo(x, waveY);
|
||||
else
|
||||
ctx.lineTo(x, waveY);
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import qs.modules.common
|
||||
import qs.modules.common.models
|
||||
import qs.modules.common.widgets
|
||||
@@ -233,16 +234,41 @@ Item { // Player instance
|
||||
Item {
|
||||
id: progressBarContainer
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: progressBar.implicitHeight
|
||||
implicitHeight: Math.max(sliderLoader.implicitHeight, progressBarLoader.implicitHeight)
|
||||
|
||||
StyledProgressBar {
|
||||
id: progressBar
|
||||
Loader {
|
||||
id: sliderLoader
|
||||
anchors.fill: parent
|
||||
highlightColor: blendedColors.colPrimary
|
||||
trackColor: blendedColors.colSecondaryContainer
|
||||
value: playerController.player?.position / playerController.player?.length
|
||||
sperm: playerController.player?.isPlaying
|
||||
active: playerController.player?.canSeek ?? false
|
||||
sourceComponent: StyledSlider {
|
||||
configuration: StyledSlider.Configuration.Wavy
|
||||
highlightColor: blendedColors.colPrimary
|
||||
trackColor: blendedColors.colSecondaryContainer
|
||||
handleColor: blendedColors.colPrimary
|
||||
value: playerController.player?.position / playerController.player?.length
|
||||
onMoved: {
|
||||
playerController.player.position = value * playerController.player.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: progressBarLoader
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
active: !(playerController.player?.canSeek ?? false)
|
||||
sourceComponent: StyledProgressBar {
|
||||
wavy: playerController.player?.isPlaying
|
||||
highlightColor: blendedColors.colPrimary
|
||||
trackColor: blendedColors.colSecondaryContainer
|
||||
value: playerController.player?.position / playerController.player?.length
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
TrackChangeButton {
|
||||
iconName: "skip_next"
|
||||
|
||||
@@ -56,7 +56,7 @@ Item {
|
||||
StyledSlider {
|
||||
id: slider
|
||||
value: root.node.audio.volume
|
||||
onValueChanged: root.node.audio.volume = value
|
||||
onMoved: root.node.audio.volume = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user