Files
dms-gamebar/components/DeviceList.qml
T

148 lines
5.0 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Services.Pipewire
import qs.Common
import qs.Services
import qs.Widgets
DankFlickable {
id: deviceList
property bool isSink: true
readonly property var activeNode: isSink ? AudioService.sink : AudioService.source
readonly property var deviceNodes: {
const hidden = isSink ? (SessionData.hiddenOutputDeviceNames ?? []) : (SessionData.hiddenInputDeviceNames ?? []);
const nodes = Pipewire.nodes.values.filter(node => {
if (!node.audio || node.isStream)
return false;
if (node.isSink !== isSink)
return false;
return !hidden.includes(node.name);
});
const active = activeNode;
return [...nodes].sort((a, b) => {
if (a === active)
return -1;
if (b === active)
return 1;
return AudioService.displayName(a).localeCompare(AudioService.displayName(b));
});
}
function activate(node) {
if (!node || !node.name)
return;
if (deviceList.isSink)
AudioService.setDefaultSinkByName(node.name);
else
AudioService.setDefaultSourceByName(node.name);
}
clip: true
contentHeight: deviceColumn.height
contentWidth: width
Column {
id: deviceColumn
width: deviceList.width
spacing: Theme.spacingXS
Repeater {
model: ScriptModel {
values: deviceList.deviceNodes
}
delegate: Rectangle {
id: deviceItem
required property var modelData
readonly property bool isActive: modelData === deviceList.activeNode
width: deviceColumn.width
height: 46
radius: Theme.cornerRadius
color: isActive ? Theme.primarySelected : (deviceArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.surfaceLight, Theme.popupTransparency))
border.color: isActive ? Theme.primary : Theme.outlineLight
border.width: isActive ? 2 : Theme.layerOutlineWidth
DankIcon {
id: deviceIcon
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
name: deviceList.isSink ? AudioService.sinkIcon(deviceItem.modelData) : "mic"
size: Theme.iconSize - 4
color: deviceItem.isActive ? Theme.primary : Theme.surfaceText
}
DankIcon {
id: activeCheck
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
name: "check_circle"
size: Theme.iconSize - 6
color: Theme.primary
visible: deviceItem.isActive
}
Column {
anchors.left: deviceIcon.right
anchors.leftMargin: Theme.spacingS
anchors.right: activeCheck.visible ? activeCheck.left : parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: 1
StyledText {
width: parent.width
text: AudioService.displayName(deviceItem.modelData)
font.pixelSize: Theme.fontSizeMedium
font.weight: deviceItem.isActive ? Font.Medium : Font.Normal
color: Theme.surfaceText
elide: Text.ElideRight
}
StyledText {
width: parent.width
text: AudioService.subtitle(deviceItem.modelData.name)
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
elide: Text.ElideRight
visible: text !== ""
}
}
MouseArea {
id: deviceArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: deviceList.activate(deviceItem.modelData)
}
PwObjectTracker {
objects: [deviceItem.modelData]
}
}
}
StyledText {
width: deviceColumn.width
text: deviceList.isSink ? "No output devices found" : "No input devices found"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
horizontalAlignment: Text.AlignHCenter
visible: deviceList.deviceNodes.length === 0
}
}
}