C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 20s
JS/TS / lint (pull_request) Successful in 22s
Python / static (pull_request) Successful in 57s
Rust / fmt (pull_request) Successful in 1m2s
C++ / build (pull_request) Successful in 2m10s
Rust / build (pull_request) Successful in 1m50s
Rust / clippy (pull_request) Successful in 1m25s
Python / verify (pull_request) Successful in 2m58s
C++ / clang-tidy (pull_request) Successful in 7m8s
341 lines
8.9 KiB
QML
341 lines
8.9 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import Quickshell
|
|
import Quickshell.Services.Pipewire
|
|
import Quickshell.Widgets
|
|
import QtQuick
|
|
import QtQuick.Layouts
|
|
import QtQuick.Controls
|
|
import ZShell.Config
|
|
import qs.Components
|
|
import qs.Daemons
|
|
import qs.Helpers
|
|
import qs.Services
|
|
|
|
Item {
|
|
id: root
|
|
|
|
readonly property int panelRadius: Tokens.rounding.largeIncreased + Tokens.padding.smaller
|
|
readonly property int rounding: panelRadius - Tokens.padding.smaller
|
|
readonly property int topMargin: 0
|
|
required property var wrapper
|
|
|
|
implicitHeight: vol.implicitHeight + Tokens.padding.smaller * 2
|
|
implicitWidth: 500 + Tokens.padding.smaller * 2
|
|
|
|
CustomRect {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
color: Colors.tPalette.m3surfaceContainer
|
|
implicitHeight: parent.implicitHeight
|
|
radius: root.rounding
|
|
y: parent.y
|
|
|
|
Behavior on implicitHeight {
|
|
Anim {
|
|
}
|
|
}
|
|
}
|
|
|
|
VolumesTab {
|
|
id: vol
|
|
|
|
anchors.left: parent.left
|
|
anchors.margins: Tokens.padding.smaller
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
component VolumesTab: ColumnLayout {
|
|
spacing: 12
|
|
|
|
CustomRect {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 65 + Tokens.spacing.small * 2
|
|
Layout.topMargin: root.topMargin
|
|
color: Colors.tPalette.m3surfaceContainer
|
|
radius: root.rounding - vol.anchors.margins
|
|
|
|
ColumnLayout {
|
|
anchors.bottomMargin: Tokens.padding.small
|
|
anchors.fill: parent
|
|
anchors.leftMargin: Tokens.padding.small
|
|
anchors.rightMargin: Tokens.padding.small
|
|
anchors.topMargin: Tokens.padding.small
|
|
|
|
RowLayout {
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
CustomText {
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
|
Layout.fillWidth: true
|
|
text: "Output volume"
|
|
}
|
|
|
|
CustomText {
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
|
color: Qt.alpha(Colors.palette.m3onSurface, 0.7)
|
|
font.bold: true
|
|
text: qsTr("%1").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`)
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
spacing: Tokens.spacing.largeIncreased
|
|
|
|
CustomMouseArea {
|
|
Layout.bottomMargin: Tokens.padding.small
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Tokens.padding.medium * 3
|
|
|
|
CustomSlider {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
bgColor: Audio.muted ? Qt.alpha(Colors.palette.m3errorContainer, 0.5) : Colors.palette.m3secondaryContainer
|
|
fgColor: Audio.muted ? Colors.palette.m3error : Colors.palette.m3primary
|
|
implicitHeight: parent.height
|
|
insetColor: Audio.muted ? (inset.attached ? Colors.palette.m3onErrorContainer : Colors.palette.m3onError) : (inset.attached ? Colors.palette.m3onSecondaryContainer : Colors.palette.m3onPrimary)
|
|
insetIcon: Audio.muted || Audio.volume < 0.001 ? "volume_off" : "volume_up"
|
|
value: Audio.volume
|
|
|
|
Behavior on value {
|
|
Anim {
|
|
}
|
|
}
|
|
|
|
onInteraction: value => Audio.setVolume(value)
|
|
}
|
|
}
|
|
|
|
CustomSwitch {
|
|
Layout.bottomMargin: Tokens.padding.small
|
|
checked: !Audio.muted
|
|
|
|
onToggled: {
|
|
const audio = Audio.sink?.audio;
|
|
if (audio)
|
|
audio.muted = !audio.muted;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CustomClippingRect {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 65 + Tokens.spacing.small * 2
|
|
Layout.topMargin: root.topMargin
|
|
color: Colors.tPalette.m3surfaceContainer
|
|
radius: root.rounding - vol.anchors.margins
|
|
|
|
PwNodePeakMonitor {
|
|
id: sourcePeak
|
|
|
|
node: Audio.source
|
|
}
|
|
|
|
CustomRect {
|
|
id: sourcePeakFill
|
|
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: parent.left
|
|
anchors.top: parent.top
|
|
color: Qt.alpha(Colors.palette.m3primary, 0.15)
|
|
implicitWidth: parent.width * sourcePeak.peak
|
|
|
|
Behavior on implicitWidth {
|
|
Anim {
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.bottomMargin: Tokens.padding.small
|
|
anchors.fill: parent
|
|
anchors.leftMargin: Tokens.padding.small
|
|
anchors.rightMargin: Tokens.padding.small
|
|
anchors.topMargin: Tokens.padding.small
|
|
|
|
RowLayout {
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
CustomText {
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
|
Layout.fillWidth: true
|
|
text: "Input volume"
|
|
}
|
|
|
|
CustomText {
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
|
color: Qt.alpha(Colors.palette.m3onSurface, 0.7)
|
|
font.bold: true
|
|
text: qsTr("%1").arg(Audio.sourceMuted ? qsTr("Muted") : `${Math.round(Audio.sourceVolume * 100)}%`)
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
spacing: Tokens.spacing.largeIncreased
|
|
|
|
CustomMouseArea {
|
|
Layout.bottomMargin: Tokens.padding.small
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Tokens.padding.medium * 3
|
|
|
|
CustomSlider {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
bgColor: Audio.sourceMuted ? Qt.alpha(Colors.palette.m3errorContainer, 0.5) : Colors.palette.m3secondaryContainer
|
|
fgColor: Audio.sourceMuted ? Colors.palette.m3error : Colors.palette.m3primary
|
|
implicitHeight: parent.height
|
|
insetColor: Audio.sourceMuted ? (inset.attached ? Colors.palette.m3onErrorContainer : Colors.palette.m3onError) : (inset.attached ? Colors.palette.m3onSecondaryContainer : Colors.palette.m3onPrimary)
|
|
insetIcon: Audio.sourceMuted || Audio.sourceVolume < 0.001 ? "mic_off" : "mic"
|
|
value: Audio.sourceVolume
|
|
|
|
Behavior on value {
|
|
Anim {
|
|
}
|
|
}
|
|
|
|
onInteraction: value => Audio.setSourceVolume(value)
|
|
}
|
|
}
|
|
|
|
CustomSwitch {
|
|
Layout.bottomMargin: Tokens.padding.small
|
|
checked: !Audio.sourceMuted
|
|
|
|
onToggled: {
|
|
const audio = Audio.source?.audio;
|
|
if (audio)
|
|
audio.muted = !audio.muted;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 1
|
|
Layout.topMargin: root.topMargin
|
|
color: Colors.tPalette.m3outline
|
|
visible: appTracks.model.length > 0
|
|
}
|
|
|
|
Repeater {
|
|
id: appTracks
|
|
|
|
model: Audio.streams.filter(s => s.isSink)
|
|
|
|
CustomClippingRect {
|
|
id: appBox
|
|
|
|
required property int index
|
|
required property var modelData
|
|
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 65 + Tokens.spacing.small * 2
|
|
Layout.topMargin: root.topMargin
|
|
color: Colors.tPalette.m3surfaceContainer
|
|
radius: root.rounding - vol.anchors.margins
|
|
|
|
PwNodePeakMonitor {
|
|
id: peak
|
|
|
|
node: appBox.modelData
|
|
}
|
|
|
|
CustomRect {
|
|
id: peakFill
|
|
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: parent.left
|
|
anchors.top: parent.top
|
|
color: Qt.alpha(Colors.palette.m3primary, 0.15)
|
|
implicitWidth: parent.width * peak.peak
|
|
|
|
Behavior on implicitWidth {
|
|
Anim {
|
|
}
|
|
}
|
|
}
|
|
|
|
TextMetrics {
|
|
id: metrics
|
|
|
|
elide: Text.ElideRight
|
|
elideWidth: root.width - 50
|
|
text: Audio.getStreamName(appBox.modelData)
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.bottomMargin: Tokens.padding.small
|
|
anchors.fill: parent
|
|
anchors.leftMargin: Tokens.padding.small
|
|
anchors.rightMargin: Tokens.padding.small
|
|
anchors.topMargin: Tokens.padding.small
|
|
|
|
RowLayout {
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
CustomText {
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
|
Layout.fillWidth: true
|
|
elide: Text.ElideRight
|
|
text: metrics.elidedText
|
|
}
|
|
|
|
CustomText {
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
|
color: Qt.alpha(Colors.palette.m3onSurface, 0.7)
|
|
font.bold: true
|
|
text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`)
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
spacing: Tokens.spacing.largeIncreased
|
|
|
|
CustomMouseArea {
|
|
Layout.bottomMargin: Tokens.padding.small
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Tokens.padding.medium * 3
|
|
|
|
CustomSlider {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
bgColor: appBox.modelData.audio.muted ? Qt.alpha(Colors.palette.m3errorContainer, 0.5) : Colors.palette.m3secondaryContainer
|
|
fgColor: appBox.modelData.audio.muted ? Colors.palette.m3error : Colors.palette.m3primary
|
|
implicitHeight: parent.height
|
|
insetColor: appBox.modelData.audio.muted ? (inset.attached ? Colors.palette.m3onErrorContainer : Colors.palette.m3onError) : (inset.attached ? Colors.palette.m3onSecondaryContainer : Colors.palette.m3onPrimary)
|
|
insetIcon: appBox.modelData.audio.muted || appBox.modelData.audio.volume < 0.001 ? "volume_off" : "volume_up"
|
|
value: appBox.modelData.audio.volume
|
|
|
|
Behavior on value {
|
|
Anim {
|
|
}
|
|
}
|
|
|
|
onInteraction: value => Audio.setStreamVolume(appBox.modelData, value)
|
|
}
|
|
}
|
|
|
|
CustomSwitch {
|
|
Layout.bottomMargin: Tokens.padding.small
|
|
checked: !appBox.modelData.audio.muted
|
|
|
|
onToggled: {
|
|
appBox.modelData.audio.muted = !appBox.modelData.audio.muted;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|