summaryrefslogtreecommitdiff
path: root/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml')
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml264
1 files changed, 264 insertions, 0 deletions
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml
new file mode 100644
index 0000000..147d81e
--- /dev/null
+++ b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/OSD/MediaVolumeOSD.qml
@@ -0,0 +1,264 @@
+import QtQuick
+import qs.Common
+import qs.Services
+import qs.Widgets
+
+DankOSD {
+ id: root
+
+ readonly property bool useVertical: isVerticalLayout
+ readonly property var player: MprisController.activePlayer
+ readonly property bool volumeSupported: player?.volumeSupported ?? false
+ property bool _suppressNewPlayer: false
+ property int _displayVolume: 0
+
+ function _syncVolume() {
+ if (!player)
+ return;
+ _displayVolume = Math.min(100, Math.round(player.volume * 100));
+ }
+
+ onPlayerChanged: {
+ _suppressNewPlayer = true;
+ _suppressTimer.restart();
+ _syncVolume();
+ }
+
+ Timer {
+ id: _suppressTimer
+ interval: 2000
+ onTriggered: _suppressNewPlayer = false
+ }
+
+ osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
+ osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
+ autoHideInterval: 3000
+ enableMouseInteraction: true
+
+ function getVolumeIcon(volume) {
+ if (!player)
+ return "music_note";
+ if (volume === 0)
+ return "music_off";
+ return "music_note";
+ }
+
+ function toggleMute() {
+ if (!player)
+ return;
+ player.volume = player.volume > 0 ? 0 : 1;
+ }
+
+ function setVolume(volumePercent) {
+ if (!player)
+ return;
+ player.volume = volumePercent / 100;
+ resetHideTimer();
+ }
+
+ Connections {
+ target: player
+
+ function onVolumeChanged() {
+ root._syncVolume();
+ if (SettingsData.osdMediaVolumeEnabled && volumeSupported && !_suppressNewPlayer)
+ root.show();
+ }
+ }
+
+ content: Loader {
+ anchors.fill: parent
+ sourceComponent: useVertical ? verticalContent : horizontalContent
+ }
+
+ Component {
+ id: horizontalContent
+
+ Item {
+ property int gap: Theme.spacingS
+
+ anchors.centerIn: parent
+ width: parent.width - Theme.spacingS * 2
+ height: 40
+
+ Rectangle {
+ width: Theme.iconSize
+ height: Theme.iconSize
+ radius: Theme.iconSize / 2
+ color: "transparent"
+ x: parent.gap
+ anchors.verticalCenter: parent.verticalCenter
+
+ DankIcon {
+ anchors.centerIn: parent
+ name: getVolumeIcon(player?.volume ?? 0)
+ size: Theme.iconSize
+ color: muteButton.containsMouse ? Theme.primary : Theme.surfaceText
+ }
+
+ MouseArea {
+ id: muteButton
+
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: toggleMute()
+ onContainsMouseChanged: setChildHovered(containsMouse || volumeSlider.containsMouse)
+ }
+ }
+
+ DankSlider {
+ id: volumeSlider
+
+ width: parent.width - Theme.iconSize - parent.gap * 3
+ height: 40
+ x: parent.gap * 2 + Theme.iconSize
+ anchors.verticalCenter: parent.verticalCenter
+ minimum: 0
+ maximum: 100
+ enabled: volumeSupported
+ showValue: true
+ unit: "%"
+ thumbOutlineColor: Theme.surfaceContainer
+ valueOverride: root._displayVolume
+ alwaysShowValue: SettingsData.osdAlwaysShowValue
+
+ Component.onCompleted: {
+ root._syncVolume();
+ value = root._displayVolume;
+ }
+
+ onSliderValueChanged: newValue => setVolume(newValue)
+
+ onContainsMouseChanged: setChildHovered(containsMouse || muteButton.containsMouse)
+
+ Binding on value {
+ value: root._displayVolume
+ when: !volumeSlider.pressed
+ }
+ }
+ }
+ }
+
+ Component {
+ id: verticalContent
+
+ Item {
+ anchors.fill: parent
+ property int gap: Theme.spacingS
+
+ Rectangle {
+ width: Theme.iconSize
+ height: Theme.iconSize
+ radius: Theme.iconSize / 2
+ color: "transparent"
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: gap
+
+ DankIcon {
+ anchors.centerIn: parent
+ name: getVolumeIcon(player?.volume ?? 0)
+ size: Theme.iconSize
+ color: muteButtonVert.containsMouse ? Theme.primary : Theme.surfaceText
+ }
+
+ MouseArea {
+ id: muteButtonVert
+
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: toggleMute()
+ onContainsMouseChanged: setChildHovered(containsMouse || vertSliderArea.containsMouse)
+ }
+ }
+
+ Item {
+ id: vertSlider
+ width: 12
+ height: parent.height - Theme.iconSize - gap * 3 - 24
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: gap * 2 + Theme.iconSize
+
+ property bool dragging: false
+ property int value: root._displayVolume
+
+ Rectangle {
+ id: vertTrack
+ width: parent.width
+ height: parent.height
+ anchors.centerIn: parent
+ color: Theme.outline
+ radius: Theme.cornerRadius
+ }
+
+ Rectangle {
+ id: vertFill
+ width: parent.width
+ height: (vertSlider.value / 100) * parent.height
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: Theme.primary
+ radius: Theme.cornerRadius
+ }
+
+ Rectangle {
+ id: vertHandle
+ width: 24
+ height: 8
+ radius: Theme.cornerRadius
+ y: {
+ const ratio = vertSlider.value / 100;
+ const travel = parent.height - height;
+ return Math.max(0, Math.min(travel, travel * (1 - ratio)));
+ }
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: Theme.primary
+ border.width: 3
+ border.color: Theme.surfaceContainer
+ }
+
+ MouseArea {
+ id: vertSliderArea
+ anchors.fill: parent
+ anchors.margins: -12
+ enabled: volumeSupported
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+
+ onContainsMouseChanged: setChildHovered(containsMouse || muteButtonVert.containsMouse)
+
+ onPressed: mouse => {
+ vertSlider.dragging = true;
+ updateVolume(mouse);
+ }
+
+ onReleased: vertSlider.dragging = false
+
+ onPositionChanged: mouse => {
+ if (pressed)
+ updateVolume(mouse);
+ }
+
+ onClicked: mouse => updateVolume(mouse)
+
+ function updateVolume(mouse) {
+ const ratio = 1.0 - (mouse.y / height);
+ const volume = Math.max(0, Math.min(100, Math.round(ratio * 100)));
+ setVolume(volume);
+ }
+ }
+ }
+
+ StyledText {
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottomMargin: gap
+ text: vertSlider.value + "%"
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceText
+ visible: SettingsData.osdAlwaysShowValue
+ }
+ }
+ }
+}