import QtQuick import QtQuick.Effects import QtQuick.Controls import Quickshell import Quickshell.Widgets import Quickshell.Services.Pipewire import qs.Widgets as Widgets Row { anchors { top: parent.top horizontalCenter: parent.horizontalCenter } padding: 6 height: 316 spacing: 6 PwObjectTracker { objects: Pipewire.nodes.values.filter(node => [17, 21].includes(node.type)) } component NodeList: ClippingRectangle { id: nodeListRect width: 350 color: "transparent" anchors { top: parent.top bottom: parent.bottom bottomMargin: 6 } radius: 10 property var model clip: true ListView { anchors.fill: parent spacing: 6 header: Item {width: 1; height: 6} footer: header model: nodeListRect.model delegate: Rectangle { anchors { left: parent.left right: parent.right } radius: 12 color: "#111" height: children[1].height Image { anchors { left: parent.left verticalCenter: parent.verticalCenter leftMargin: 6 } sourceSize {width: width; height: height} source: Quickshell.iconPath((() => { const description = modelData.description.toLowerCase(); if (description.search("hdmi") !== -1) return "display" if (description.search("speaker") !== -1) return "audio-speakers" if (description.search("earphone") !== -1 || description.search("headphone") !== -1) return "audio-headset" if (modelData.properties["device.icon-name"]) return modelData.properties["device.icon-name"] return modelData.properties["application.name"] })()?.toLowerCase(), "audio-on") width: 32 height: width } Column { anchors { left: parent.children[0].right right: parent.right verticalCenter: parent.verticalCenter margins: 6 rightMargin: 12 } topPadding: 6 bottomPadding: 6 spacing: 2 Text { text: { if (modelData.nickname !== "") return modelData.nickname if (modelData.description !== "") return description return modelData.name } color: "white" font.pixelSize: 16 } Widgets.Slider { value: modelData.audio.volume onMoved: modelData.audio.volume = position } } } } } NodeList { model: Pipewire.nodes.values.filter(node => node.type === 17) } NodeList { model: Pipewire.nodes.values.filter(node => node.type === 21) } }