From 99eb6956bdac228d1e981a97ed5a153bb2f4c245 Mon Sep 17 00:00:00 2001 From: kossLAN Date: Mon, 3 Nov 2025 14:39:53 -0500 Subject: [PATCH 1/3] feat: proper volume control center, still not done though --- shell/bar/volume/ApplicationMixer.qml | 70 ------------------ shell/bar/volume/DeviceMixer.qml | 65 ----------------- shell/bar/volume/VolumeCard.qml | 77 +++++--------------- shell/bar/volume/VolumeControl.qml | 36 ---------- shell/bar/volume/VolumeIndicator.qml | 79 +++++++++++++++------ shell/launcher/Controller.qml | 2 +- shell/shell.qml | 2 +- shell/{volume-osd => volosd}/Controller.qml | 1 - shell/widgets/StyledListView.qml | 53 ++++++++++++++ shell/widgets/StyledSlider.qml | 11 +-- 10 files changed, 140 insertions(+), 256 deletions(-) delete mode 100644 shell/bar/volume/ApplicationMixer.qml delete mode 100644 shell/bar/volume/DeviceMixer.qml delete mode 100644 shell/bar/volume/VolumeControl.qml rename shell/{volume-osd => volosd}/Controller.qml (97%) create mode 100644 shell/widgets/StyledListView.qml diff --git a/shell/bar/volume/ApplicationMixer.qml b/shell/bar/volume/ApplicationMixer.qml deleted file mode 100644 index 584be77..0000000 --- a/shell/bar/volume/ApplicationMixer.qml +++ /dev/null @@ -1,70 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell.Widgets -import Quickshell.Services.Pipewire -import "../../widgets/" as Widgets -import "../.." - -ColumnLayout { - id: root - - Loader { - id: sinkLoader - active: sink - - property PwNode sink: Pipewire.defaultAudioSink - - sourceComponent: WrapperItem { - PwNodeLinkTracker { - id: linkTracker - node: sinkLoader.sink - } - - ColumnLayout { - Repeater { - model: linkTracker.linkGroups - - delegate: Loader { - id: nodeLoader - active: modelData.source !== null - Layout.preferredWidth: 350 - Layout.preferredHeight: 45 - - required property PwLinkGroup modelData - - sourceComponent: VolumeCard { - id: nodeCard - node: nodeLoader.modelData.source - text: node.properties["media.name"] ?? "" - - // if icon-name is undefined, just gonna fallback on the application name - icon: IconImage { - source: { - if (nodeCard.node.properties["application.icon-name"] !== undefined) - return `image://icon/${nodeCard.node.properties["application.icon-name"]}`; - - let applicationName = nodeCard.node.properties["application.name"]; - return `image://icon/${applicationName?.toLowerCase() ?? "image-missing"}`; - } - } - - button: Widgets.FontIconButton { - hoverEnabled: false - iconName: nodeCard.node.audio.muted ? "volume_off" : "volume_up" - checked: !nodeCard.node.audio.muted - inactiveColor: ShellSettings.colors["surface_container_highest"] - onClicked: { - nodeCard.node.audio.muted = !nodeCard.node.audio.muted; - } - } - - anchors.fill: parent - } - } - } - } - } - } -} diff --git a/shell/bar/volume/DeviceMixer.qml b/shell/bar/volume/DeviceMixer.qml deleted file mode 100644 index e7076dc..0000000 --- a/shell/bar/volume/DeviceMixer.qml +++ /dev/null @@ -1,65 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell.Services.Pipewire -import Quickshell.Widgets -import qs -import qs.widgets - -ColumnLayout { - id: root - - // headphones - // don't load until the node is not null - Loader { - id: sinkLoader - active: sink !== null - Layout.preferredWidth: 350 - Layout.preferredHeight: 45 - - property PwNode sink: Pipewire.defaultAudioSink - - sourceComponent: VolumeCard { - id: sinkCard - node: sinkLoader.sink - button: StyledMouseArea { - property bool checked: !sinkCard.node.audio.muted - - // IconImage {} - - onClicked: { - sinkCard.node.audio.muted = !sinkCard.node.audio.muted; - } - } - - anchors.fill: parent - } - } - - // microphone, same as above - Loader { - id: sourceLoader - active: source !== null - Layout.preferredWidth: 350 - Layout.preferredHeight: 45 - - property PwNode source: Pipewire.defaultAudioSource - - sourceComponent: VolumeCard { - id: sourceCard - node: sourceLoader.source - button: StyledMouseArea { - property bool checked: !sourceCard.node.audio.muted - - // IconImage {} - - onClicked: { - sourceCard.node.audio.muted = !sourceCard.node.audio.muted; - } - } - - anchors.fill: parent - } - } -} diff --git a/shell/bar/volume/VolumeCard.qml b/shell/bar/volume/VolumeCard.qml index c431c30..56c3e26 100644 --- a/shell/bar/volume/VolumeCard.qml +++ b/shell/bar/volume/VolumeCard.qml @@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts -import QtQuick.Controls import Quickshell.Widgets import Quickshell.Services.Pipewire import qs.widgets @@ -13,34 +12,34 @@ Loader { active: node != null required property PwNode node - property string label: node.nickname + property string label: node.nickname ?? node.name - sourceComponent: WrapperRectangle { - id: comp - color: ShellSettings.colors.surface_container_translucent - radius: 12 + property Component leftWidget + + PwObjectTracker { + id: tracker + objects: [root.node] + } + + sourceComponent: WrapperItem { margin: 6 - border { - width: 1 - color: ShellSettings.colors.active_translucent - } - - // property Component button - // property Component icon - - PwObjectTracker { - id: tracker - objects: [root.node] - } - RowLayout { + spacing: 10 + + Loader { + id: leftWidget + sourceComponent: root.leftWidget + Layout.preferredWidth: this.height + Layout.fillHeight: true + } + ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true Text { - text: root.label + text: root.label color: ShellSettings.colors.active elide: Text.ElideRight Layout.fillWidth: true @@ -49,8 +48,6 @@ Loader { StyledSlider { value: root.node.audio.volume ?? 0 - // text: root.text - // icon: root.icon onValueChanged: { // only allow changes when the node is ready other wise you will combust @@ -64,42 +61,6 @@ Loader { Layout.fillHeight: true } } - - // StyledMouseArea { - // id: rightArrow - // Layout.preferredWidth: rightArrow.height - // // Layout.fillWidth: true - // Layout.fillHeight: true - // - // IconImage { - // source: "root:resources/general/right-arrow.svg" - // anchors.fill: parent - // } - // } - - // Loader { - // id: buttonLoader - // sourceComponent: root.button - // - // Layout.preferredWidth: this.height - // Layout.fillHeight: true - // } } } - - // sourceComponent: VolumeCard { - // id: sinkCard - // node: sinkLoader.sink - // button: StyledMouseArea { - // property bool checked: !sinkCard.node.audio.muted - // - // // IconImage {} - // - // onClicked: { - // sinkCard.node.audio.muted = !sinkCard.node.audio.muted; - // } - // } - // - // anchors.fill: parent - // } } diff --git a/shell/bar/volume/VolumeControl.qml b/shell/bar/volume/VolumeControl.qml deleted file mode 100644 index bcb4f48..0000000 --- a/shell/bar/volume/VolumeControl.qml +++ /dev/null @@ -1,36 +0,0 @@ -pragma ComponentBehavior: Bound - -import QtQuick -import QtQuick.Layouts -import Quickshell.Widgets -import qs.widgets - -DeviceMixer {} - -// WrapperItem { -// id: root -// -// ColumnLayout { -// spacing: 10 -// -// // TabBar { -// // id: tabBar -// // model: ["headphones", "tune"] -// // Layout.fillWidth: true -// // Layout.preferredHeight: 35 -// // } -// -// -// // StackLayout { -// // id: page -// // currentIndex: tabBar.currentIndex -// // Layout.fillWidth: true -// // Layout.preferredHeight: currentItem ? currentItem.implicitHeight : 0 -// // -// // readonly property Item currentItem: children[currentIndex] -// // -// // DeviceMixer {} -// // ApplicationMixer {} -// // } -// } -// } diff --git a/shell/bar/volume/VolumeIndicator.qml b/shell/bar/volume/VolumeIndicator.qml index 20b51ef..886a10a 100644 --- a/shell/bar/volume/VolumeIndicator.qml +++ b/shell/bar/volume/VolumeIndicator.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import QtQuick.Effects import Quickshell.Widgets import Quickshell.Services.Pipewire import qs.widgets @@ -49,12 +50,29 @@ StyledMouseArea { // Default Audio VolumeCard { + id: defaultCard node: menu.sink Layout.fillWidth: true Layout.preferredHeight: menu.entryHeight + + leftWidget: StyledMouseArea { + onClicked: defaultCard.node.audio.muted = !defaultCard.node.audio.muted + + IconImage { + anchors.fill: parent + source: { + if (defaultCard.node.audio.muted) { + return "root:resources/volume/volume-mute.svg"; + } else { + return "root:resources/volume/volume-full.svg"; + } + } + } + } } Rectangle { + visible: linkTracker.linkGroups.length !== 0 color: ShellSettings.colors.active_translucent radius: height / 2 Layout.leftMargin: 3 @@ -64,34 +82,55 @@ StyledMouseArea { } // Application Mixer - Loader { - id: sinkLoader - active: menu.sink + PwNodeLinkTracker { + id: linkTracker + node: menu.sink + } + + StyledListView { + id: appList + visible: linkTracker.linkGroups.length !== 0 + spacing: 6 + model: linkTracker.linkGroups + clip: true Layout.fillWidth: true - Layout.preferredHeight: 5 * menu.entryHeight + Layout.preferredHeight: { + const entryHeight = Math.min(5, linkTracker.linkGroups.length); - PwNodeLinkTracker { - id: linkTracker - node: menu.sink + return entryHeight * (menu.entryHeight + appList.spacing); } - sourceComponent: ListView { - anchors.fill: parent - spacing: 6 - model: linkTracker.linkGroups + delegate: VolumeCard { + id: appCard + node: modelData.source + label: node.properties["media.name"] ?? "" + width: ListView.view.width + height: menu.entryHeight - delegate: Loader { - id: nodeLoader - active: modelData.source != null - width: ListView.view.width - height: menu.entryHeight + required property PwLinkGroup modelData - required property PwLinkGroup modelData + leftWidget: StyledMouseArea { + onClicked: appCard.node.audio.muted = !appCard.node.audio.muted - sourceComponent: VolumeCard { - node: nodeLoader.modelData.source - label: node.properties["media.name"] ?? "" + IconImage { + id: appIcon + visible: false + anchors.fill: parent + + source: { + if (appCard.node.properties["application.icon-name"] !== undefined) + return `image://icon/${appCard.node.properties["application.icon-name"]}`; + + let applicationName = appCard.node.properties["application.name"]; + return `image://icon/${applicationName?.toLowerCase() ?? "image-missing"}`; + } + } + + MultiEffect { + source: appIcon + anchors.fill: appIcon + saturation: appCard.node.audio.muted ? -1.0 : 0.0 } } } diff --git a/shell/launcher/Controller.qml b/shell/launcher/Controller.qml index e56f366..099d407 100644 --- a/shell/launcher/Controller.qml +++ b/shell/launcher/Controller.qml @@ -64,7 +64,7 @@ Singleton { anchors { horizontalCenter: parent.horizontalCenter top: parent.top - topMargin: screen.height / 2.75 + topMargin: screen.height / 3 } ColumnLayout { diff --git a/shell/shell.qml b/shell/shell.qml index 8527c2d..7986317 100644 --- a/shell/shell.qml +++ b/shell/shell.qml @@ -6,7 +6,7 @@ import QtQuick import "bar" import "notifications" as Notifications import "mpris" as Mpris -import "volume-osd" as VolumeOSD +import "volosd" as VolumeOSD import "settings" as Settings import "launcher" as Launcher import "lockscreen" as LockScreen diff --git a/shell/volume-osd/Controller.qml b/shell/volosd/Controller.qml similarity index 97% rename from shell/volume-osd/Controller.qml rename to shell/volosd/Controller.qml index 5e6bd3e..352e051 100644 --- a/shell/volume-osd/Controller.qml +++ b/shell/volosd/Controller.qml @@ -21,7 +21,6 @@ Scope { target: Pipewire.defaultAudioSink?.audio function onVolumeChanged() { - console.log("Volume Changed, showing OSD."); root.shouldShowOsd = true; hideTimer.restart(); } diff --git a/shell/widgets/StyledListView.qml b/shell/widgets/StyledListView.qml new file mode 100644 index 0000000..c53f7f9 --- /dev/null +++ b/shell/widgets/StyledListView.qml @@ -0,0 +1,53 @@ +import QtQuick + +ListView { + id: root + + add: Transition { + NumberAnimation { + property: "opacity" + from: 0 + to: 1 + duration: 100 + } + } + + displaced: Transition { + NumberAnimation { + property: "y" + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "opacity" + to: 1 + duration: 100 + } + } + + move: Transition { + NumberAnimation { + property: "y" + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "opacity" + to: 1 + duration: 100 + } + } + + remove: Transition { + NumberAnimation { + property: "y" + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "opacity" + to: 0 + duration: 100 + } + } +} diff --git a/shell/widgets/StyledSlider.qml b/shell/widgets/StyledSlider.qml index 11b653a..d7b59c8 100644 --- a/shell/widgets/StyledSlider.qml +++ b/shell/widgets/StyledSlider.qml @@ -7,15 +7,18 @@ import ".." Slider { id: slider - implicitHeight: 8 + implicitHeight: 7 + property var accentColor: ShellSettings.colors.active background: Rectangle { id: sliderContainer width: slider.availableWidth height: slider.implicitHeight - color: ShellSettings.colors.inactive - radius: 4 + color: "transparent" + border.color: ShellSettings.colors.active_translucent + border.width: 1 + radius: 5 anchors.verticalCenter: parent.verticalCenter layer.enabled: true @@ -39,7 +42,7 @@ Slider { id: fill width: slider.handle.width / 2 + slider.visualPosition * (sliderContainer.width - slider.handle.width) height: sliderContainer.height - color: Qt.color(slider.accentColor ?? "purple").darker(1.2) + color: ShellSettings.colors.active_translucent } } From 468291c9eaa84c1435186843c3df55b660c2786d Mon Sep 17 00:00:00 2001 From: kossLAN Date: Mon, 3 Nov 2025 14:55:33 -0500 Subject: [PATCH 2/3] bump dots again --- shell/volosd/Controller.qml | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/shell/volosd/Controller.qml b/shell/volosd/Controller.qml index 352e051..0d7f825 100644 --- a/shell/volosd/Controller.qml +++ b/shell/volosd/Controller.qml @@ -24,6 +24,11 @@ Scope { root.shouldShowOsd = true; hideTimer.restart(); } + + function onMutedChanged() { + root.shouldShowOsd = true; + hideTimer.restart(); + } } property bool shouldShowOsd: false @@ -52,6 +57,8 @@ Scope { // radius: 8 RowLayout { + spacing: 10 + anchors { fill: parent leftMargin: 10 @@ -60,15 +67,23 @@ Scope { IconImage { implicitSize: 30 - source: "root:resources/volume/volume-full.svg" + source: { + if (Pipewire.defaultAudioSink?.audio.muted) { + return "root:resources/volume/volume-mute.svg"; + } else { + return "root:resources/volume/volume-full.svg"; + } + } } Rectangle { id: sliderBackground Layout.fillWidth: true implicitHeight: 10 - radius: 20 - color: ShellSettings.colors.inactive + radius: height / 2 + color: "transparent" + border.color: ShellSettings.colors.active_translucent + border.width: 1 layer.enabled: true layer.effect: OpacityMask { @@ -82,13 +97,13 @@ Scope { Rectangle { color: ShellSettings.colors.active + implicitWidth: parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0) + anchors { left: parent.left top: parent.top bottom: parent.bottom } - - implicitWidth: parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0) } } } From 83d7dc47c432e69aa962646b1181e691bbd2ef01 Mon Sep 17 00:00:00 2001 From: kossLAN Date: Mon, 3 Nov 2025 18:00:43 -0500 Subject: [PATCH 3/3] update volume icons --- shell/bar/volume/VolumeCard.qml | 2 +- shell/bar/volume/VolumeIndicator.qml | 55 ++++++++++----------- shell/resources/mask.png | Bin 1156 -> 0 bytes shell/resources/volume/microphone-full.svg | 2 - shell/resources/volume/microphone-mute.svg | 2 - shell/resources/volume/volume-full.svg | 9 ---- shell/resources/volume/volume-low.svg | 9 ---- shell/resources/volume/volume-mute.svg | 9 ---- shell/resources/volume/volume-off.svg | 9 ---- shell/volosd/Controller.qml | 14 +++--- 10 files changed, 34 insertions(+), 77 deletions(-) delete mode 100644 shell/resources/mask.png delete mode 100644 shell/resources/volume/microphone-full.svg delete mode 100644 shell/resources/volume/microphone-mute.svg delete mode 100644 shell/resources/volume/volume-full.svg delete mode 100644 shell/resources/volume/volume-low.svg delete mode 100644 shell/resources/volume/volume-mute.svg delete mode 100644 shell/resources/volume/volume-off.svg diff --git a/shell/bar/volume/VolumeCard.qml b/shell/bar/volume/VolumeCard.qml index 56c3e26..9a47ba4 100644 --- a/shell/bar/volume/VolumeCard.qml +++ b/shell/bar/volume/VolumeCard.qml @@ -12,7 +12,7 @@ Loader { active: node != null required property PwNode node - property string label: node.nickname ?? node.name + property string label: node.nickname === "" ? node.description : node.nickname property Component leftWidget diff --git a/shell/bar/volume/VolumeIndicator.qml b/shell/bar/volume/VolumeIndicator.qml index 886a10a..f4b6785 100644 --- a/shell/bar/volume/VolumeIndicator.qml +++ b/shell/bar/volume/VolumeIndicator.qml @@ -7,7 +7,6 @@ import Quickshell.Widgets import Quickshell.Services.Pipewire import qs.widgets import qs.bar -import qs StyledMouseArea { id: root @@ -15,14 +14,19 @@ StyledMouseArea { required property var bar property bool showMenu: false + property PwNode sink: Pipewire.defaultAudioSink IconImage { id: icon - source: "root:resources/volume/volume-full.svg" - - anchors { - fill: parent - margins: 2 + anchors.fill: parent + source: if (root.sink.audio.muted) { + return "image://icon/audio-volume-muted"; + } else if (root.sink.audio.volume > 0.66) { + return "image://icon/audio-volume-high"; + } else if (root.sink.audio.volume > 0.33) { + return "image://icon/audio-volume-medium"; + } else { + return "image://icon/audio-volume-low"; } } @@ -33,25 +37,24 @@ StyledMouseArea { show: root.showMenu onClosed: root.showMenu = false - implicitWidth: 300 + implicitWidth: 275 implicitHeight: container.implicitHeight + (2 * 8) - property PwNode sink: Pipewire.defaultAudioSink - property real entryHeight: 45 + property real entryHeight: 40 ColumnLayout { id: container - spacing: 4 + spacing: 2 anchors { fill: parent - margins: 8 + margins: 4 } // Default Audio VolumeCard { id: defaultCard - node: menu.sink + node: root.sink Layout.fillWidth: true Layout.preferredHeight: menu.entryHeight @@ -60,37 +63,29 @@ StyledMouseArea { IconImage { anchors.fill: parent - source: { - if (defaultCard.node.audio.muted) { - return "root:resources/volume/volume-mute.svg"; - } else { - return "root:resources/volume/volume-full.svg"; - } + source: if (root.sink.audio.muted) { + return "image://icon/audio-volume-muted"; + } else if (root.sink.audio.volume > 0.66) { + return "image://icon/audio-volume-high"; + } else if (root.sink.audio.volume > 0.33) { + return "image://icon/audio-volume-medium"; + } else { + return "image://icon/audio-volume-low"; } } } } - Rectangle { - visible: linkTracker.linkGroups.length !== 0 - color: ShellSettings.colors.active_translucent - radius: height / 2 - Layout.leftMargin: 3 - Layout.rightMargin: 3 - Layout.fillWidth: true - Layout.preferredHeight: 2 - } - // Application Mixer PwNodeLinkTracker { id: linkTracker - node: menu.sink + node: root.sink } StyledListView { id: appList visible: linkTracker.linkGroups.length !== 0 - spacing: 6 + spacing: 2 model: linkTracker.linkGroups clip: true diff --git a/shell/resources/mask.png b/shell/resources/mask.png deleted file mode 100644 index e6cac946fb0e3fbf29d343d07799c4a950079a55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1156 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANNf&6&>50iMpz3I#>^X_+~x z3=A3*YbV-z9Cna78ZVsf8YS~a;n9SJRySQ;WwJ%P0u--st+kpF^NZD2$Fr+@@q?&> z56K%}J$STcb@OTkj=F{&+dvrNltyuIV?^3eV+}vTFM&34j1n0mt9`U)N%g6)QcbU zO&VwVUy_#9Eo0%yVHUqG>wA}3ue@R5@>xk*>r^g@bh$qG+p|xTpXVOa-_>#XZ)@k+ zF+{%7s%4guVMdIlB$^PrO*PCgRYeyAlVq&Me$FhvC*n_VkV7@*g-q zht{p|`tq3P+{0=H8~2Sd4A&kBTwBQgdiAE8VS)eoY7UCXJyKJf&h22%m*7605GCR;N4JP6$M?ubF#Dydyv#oT8eCEU3`TggPI z;Ol zoZd0rEP4u`Y%hbv(d<13CEhJ_&g=A=XBkw51LgysnB*-e*f&<&iRe|3=AVDEuCjL z-S95Yf};%27QbD);X-?_rrGa9N4D$O1Qyj!EH|#`6yGr~d#@-1Z_SaVAsb?EvflPS zn(iC3e+Tn5<%cZyp3gqLGyh}@>%2!v5)yuybG?o+SKf=)va)5|sc2+Ydnfn$lFw$fKl1-=>KI=2E>o4T_HScg PU|{fc^>bP0l+XkK7 - diff --git a/shell/resources/volume/microphone-mute.svg b/shell/resources/volume/microphone-mute.svg deleted file mode 100644 index 8c2d3b5..0000000 --- a/shell/resources/volume/microphone-mute.svg +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/shell/resources/volume/volume-full.svg b/shell/resources/volume/volume-full.svg deleted file mode 100644 index 19bbfb1..0000000 --- a/shell/resources/volume/volume-full.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/shell/resources/volume/volume-low.svg b/shell/resources/volume/volume-low.svg deleted file mode 100644 index 69e95e5..0000000 --- a/shell/resources/volume/volume-low.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/shell/resources/volume/volume-mute.svg b/shell/resources/volume/volume-mute.svg deleted file mode 100644 index 4b67e0c..0000000 --- a/shell/resources/volume/volume-mute.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/shell/resources/volume/volume-off.svg b/shell/resources/volume/volume-off.svg deleted file mode 100644 index f975a8b..0000000 --- a/shell/resources/volume/volume-off.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/shell/volosd/Controller.qml b/shell/volosd/Controller.qml index 0d7f825..2b7f45e 100644 --- a/shell/volosd/Controller.qml +++ b/shell/volosd/Controller.qml @@ -67,12 +67,14 @@ Scope { IconImage { implicitSize: 30 - source: { - if (Pipewire.defaultAudioSink?.audio.muted) { - return "root:resources/volume/volume-mute.svg"; - } else { - return "root:resources/volume/volume-full.svg"; - } + source: if (Pipewire.defaultAudioSink?.audio.muted) { + return "image://icon/audio-volume-muted"; + } else if (Pipewire.defaultAudioSink?.audio.volume > 0.66) { + return "image://icon/audio-volume-high"; + } else if (Pipewire.defaultAudioSink?.audio.volume > 0.33) { + return "image://icon/audio-volume-medium"; + } else { + return "image://icon/audio-volume-low"; } }