Files

128 lines
3.9 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import qs.Common
import qs.Modules.ControlCenter.Widgets
import qs.Services
CcSheetDialog {
id: root
property var node: null
property var availablePorts: []
property string currentPort: ""
property bool isLoading: false
readonly property bool nodeValid: node !== null && node.isSink
signal portSelected(string sinkName, string portName)
iconName: node ? AudioService.sinkIcon(node) : "speaker"
title: node ? AudioService.displayName(node) : ""
subtitle: I18n.tr("Port Selection", "audio port selector modal subtitle")
statusText: {
if (isLoading)
return I18n.tr("Loading ports...", "audio port selector loading state");
if (availablePorts.length === 0)
return I18n.tr("No ports found", "audio port selector empty state");
return I18n.tr("Current: %1", "audio port selector active port label, %1 is the port name").arg(portDescription(currentPort));
}
statusColor: isLoading ? Theme.primary : Theme.surfaceVariantText
function show(sinkNode) {
if (!sinkNode || !sinkNode.isSink)
return;
node = sinkNode;
isLoading = true;
availablePorts = [];
currentPort = "";
populateFromCache();
AudioService.refreshSinkPorts(() => {
root.isLoading = false;
});
present();
}
function populateFromCache() {
const info = AudioService.getSinkPorts(node);
if (!info) {
availablePorts = [];
currentPort = "";
return;
}
availablePorts = (info.ports || []).slice().sort((a, b) => b.priority - a.priority);
currentPort = info.active || "";
isLoading = false;
}
function portDescription(portName) {
const port = availablePorts.find(p => p.name === portName);
return port ? port.description : portName;
}
function selectPort(portName) {
if (!nodeValid || isLoading)
return;
const port = availablePorts.find(p => p.name === portName);
if (!port || port.availability === "no")
return;
const capturedName = node.name;
isLoading = true;
AudioService.setSinkPort(capturedName, portName, (success, message) => {
isLoading = false;
if (!root.node || root.node.name !== capturedName)
return;
if (!success) {
ToastService.showToast(message, ToastService.levelError);
return;
}
root.portSelected(capturedName, portName);
ToastService.showToast(message, ToastService.levelInfo);
root.dismiss();
});
}
onNodeValidChanged: {
if (shown && !nodeValid)
dismiss();
}
onDismissed: node = null
readonly property var audioSinkPorts: AudioService.sinkPorts
onAudioSinkPortsChanged: {
if (!nodeValid)
return;
populateFromCache();
isLoading = false;
}
CcGroup {
visible: root.availablePorts.length > 0
Repeater {
model: root.availablePorts
CcListRow {
required property var modelData
readonly property bool unavailable: modelData.availability === "no"
title: modelData.description
subtitle: {
if (unavailable)
return I18n.tr("Unavailable", "audio port availability status");
if (modelData.availability === "yes")
return I18n.tr("Available", "audio port availability status");
return "";
}
active: modelData.name === root.currentPort
enabled: !unavailable && !root.isLoading
clickable: !active
onClicked: root.selectPort(modelData.name)
}
}
}
}