import QtQuick import qs.Common import qs.Services import qs.Widgets Item { id: row property var node: null property int maxPercent: 100 property string activeIcon: "volume_up" property string mutedIcon: "volume_off" readonly property var audio: (node && node.audio) ? node.audio : null readonly property bool muted: audio ? audio.muted : false readonly property int percent: audio ? Math.round(audio.volume * 100) : 0 readonly property int sliderMaximum: Math.max(100, maxPercent) // DankSlider assigns its own `value` while dragging, which breaks a declarative // binding, so the slider is synced imperatively whenever the node volume changes. function syncSlider() { slider.value = Math.min(row.sliderMaximum, row.percent); } function applyVolume(newValue) { if (!row.audio) return; row.audio.volume = newValue / 100; if (newValue > 0 && row.audio.muted) row.audio.muted = false; } height: 48 onPercentChanged: row.syncSlider() onSliderMaximumChanged: row.syncSlider() onNodeChanged: row.syncSlider() Rectangle { id: muteButton anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter width: 40 height: 40 radius: width / 2 color: muteArea.containsMouse ? Theme.primaryHover : "transparent" DankIcon { anchors.centerIn: parent name: (row.muted || row.percent === 0) ? row.mutedIcon : row.activeIcon size: Theme.iconSize color: row.muted ? Theme.error : Theme.primary } MouseArea { id: muteArea anchors.fill: parent hoverEnabled: true enabled: row.audio !== null cursorShape: Qt.PointingHandCursor onClicked: { if (row.audio) row.audio.muted = !row.audio.muted; } } } StyledText { id: valueLabel anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter width: 48 horizontalAlignment: Text.AlignRight text: row.percent + "%" font.pixelSize: Theme.fontSizeMedium font.weight: Font.Medium color: row.muted ? Theme.surfaceVariantText : Theme.surfaceText } DankSlider { id: slider anchors.left: muteButton.right anchors.leftMargin: Theme.spacingS anchors.right: valueLabel.left anchors.rightMargin: Theme.spacingS anchors.verticalCenter: parent.verticalCenter enabled: row.audio !== null minimum: 0 maximum: row.sliderMaximum showValue: false onSliderValueChanged: newValue => row.applyVolume(newValue) Component.onCompleted: row.syncSlider() } }