pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import Quickshell import Quickshell.Services.Pipewire import qs.Components import ZShell.Config import qs.Services ItemList { id: root property int currentId: -1 property string iconName: "speaker" property var nodes: [] signal selected(node: PwNode) last: true showList: true delegate: Item { id: device readonly property bool active: device.modelData?.id === root.currentId required property int index required property PwNode modelData anchors.left: root.list.contentItem.left anchors.right: root.list.contentItem.right implicitHeight: deviceLayout.implicitHeight + deviceLayout.anchors.margins * 2 StateLayer { bottomLeftRadius: device.index === root?.list.count - 1 ? Tokens.rounding.largeIncreased : radius bottomRightRadius: device.index === root?.list.count - 1 ? Tokens.rounding.largeIncreased : radius radius: Tokens.rounding.extraSmall onClicked: root.selected(device.modelData) } RowLayout { id: deviceLayout anchors.fill: parent anchors.leftMargin: Tokens.padding.largeIncreased anchors.margins: Tokens.padding.large anchors.rightMargin: Tokens.padding.largeIncreased spacing: Tokens.spacing.medium CustomRect { color: device.active ? Colors.palette.m3primary : Colors.palette.m3secondaryContainer implicitHeight: devIcon.implicitHeight + Tokens.padding.small * 2 implicitWidth: implicitHeight radius: Tokens.rounding.full MaterialIcon { id: devIcon anchors.centerIn: parent color: device.active ? Colors.palette.m3onPrimary : Colors.palette.m3onSecondaryContainer fill: device.active ? 1 : 0 font.pointSize: Tokens.font.size.large text: root.iconName Behavior on fill { Anim { } } } } CustomText { Layout.fillWidth: true elide: Text.ElideRight font.pointSize: Tokens.font.size.smaller text: device.modelData?.description || device.modelData?.name || qsTr("Unknown") } MaterialIcon { color: Colors.palette.m3primary font.pointSize: Tokens.font.size.large opacity: device.active ? 1 : 0 text: "check" Behavior on opacity { Anim { type: Anim.DefaultEffects } } } } } model: ScriptModel { values: [...root.nodes].sort((a, b) => (a.description || a.name || "").localeCompare(b.description || b.name || "")) } }