nova-shell/shell/modules/VolumeModule.qml

93 lines
2.6 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Services.Pipewire
import "." as M
import "../services" as S
import "../applets" as C
M.BarModule {
id: root
active: S.Modules.volume.enable
spacing: S.Theme.moduleSpacing
tooltip: "Volume: " + Math.round(volume * 100) + "%" + (muted ? " (muted)" : "")
panelNamespace: "nova-volume"
panelContentWidth: 220
panelComponent: Component {
C.VolumeApplet {
width: parent.width
sink: root.sink
sinkList: root._sinkList
streamList: root._streamList
accentColor: root.accentColor
}
}
PwObjectTracker {
objects: [Pipewire.defaultAudioSink, ...root._streamList]
}
readonly property var sink: Pipewire.defaultAudioSink
readonly property real volume: sink?.audio?.volume ?? 0
readonly property bool muted: sink?.audio?.muted ?? false
readonly property string _volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026"))
readonly property color _volumeColor: muted ? S.Theme.base04 : root.accentColor
readonly property var _sinkList: {
const sinks = [];
if (Pipewire.nodes) {
for (const node of Pipewire.nodes.values)
if (!node.isStream && node.isSink)
sinks.push(node);
}
return sinks;
}
readonly property var _streamList: {
const streams = [];
if (Pipewire.nodes) {
for (const node of Pipewire.nodes.values)
if (node.isStream && node.audio)
streams.push(node);
}
return streams;
}
property bool _volumeInit: false
property bool _mutedInit: false
onVolumeChanged: {
if (!_volumeInit) {
_volumeInit = true;
return;
}
flashPanel();
}
onMutedChanged: {
if (!_mutedInit) {
_mutedInit = true;
return;
}
flashPanel();
}
M.BarIcon {
icon: root._volumeIcon
minIcon: "\uF028"
color: root._volumeColor
anchors.verticalCenter: parent.verticalCenter
}
M.BarLabel {
label: Math.round(root.volume * 100) + "%"
minText: "100%"
color: root._volumeColor
anchors.verticalCenter: parent.verticalCenter
}
WheelHandler {
onWheel: event => {
if (!root.sink?.audio)
return;
root.sink.audio.volume = Math.max(0, root.sink.audio.volume + (event.angleDelta.y > 0 ? 0.05 : -0.05));
}
}
}