mirror of
https://github.com/kossLAN/dots.git
synced 2025-11-04 14:39:51 -05:00
135 lines
4.3 KiB
QML
135 lines
4.3 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import QtQuick.Layouts
|
|
import QtQuick.Effects
|
|
import Quickshell.Widgets
|
|
import Quickshell.Services.Pipewire
|
|
import qs.widgets
|
|
import qs.bar
|
|
|
|
StyledMouseArea {
|
|
id: root
|
|
onClicked: showMenu = !showMenu
|
|
|
|
required property var bar
|
|
property bool showMenu: false
|
|
property PwNode sink: Pipewire.defaultAudioSink
|
|
|
|
IconImage {
|
|
id: icon
|
|
anchors.fill: parent
|
|
source: if (root.sink.audio.muted) {
|
|
return "image://icon/audio-volume-muted";
|
|
} else if (root.sink.audio.volume > 0.66) {
|
|
return "image://icon/audio-volume-high";
|
|
} else if (root.sink.audio.volume > 0.33) {
|
|
return "image://icon/audio-volume-medium";
|
|
} else {
|
|
return "image://icon/audio-volume-low";
|
|
}
|
|
}
|
|
|
|
property PopupItem menu: PopupItem {
|
|
id: menu
|
|
owner: root
|
|
popup: root.bar.popup
|
|
show: root.showMenu
|
|
onClosed: root.showMenu = false
|
|
|
|
implicitWidth: 275
|
|
implicitHeight: container.implicitHeight + (2 * 8)
|
|
|
|
property real entryHeight: 40
|
|
|
|
ColumnLayout {
|
|
id: container
|
|
spacing: 2
|
|
|
|
anchors {
|
|
fill: parent
|
|
margins: 4
|
|
}
|
|
|
|
// Default Audio
|
|
VolumeCard {
|
|
id: defaultCard
|
|
node: root.sink
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: menu.entryHeight
|
|
|
|
leftWidget: StyledMouseArea {
|
|
onClicked: defaultCard.node.audio.muted = !defaultCard.node.audio.muted
|
|
|
|
IconImage {
|
|
anchors.fill: parent
|
|
source: if (root.sink.audio.muted) {
|
|
return "image://icon/audio-volume-muted";
|
|
} else if (root.sink.audio.volume > 0.66) {
|
|
return "image://icon/audio-volume-high";
|
|
} else if (root.sink.audio.volume > 0.33) {
|
|
return "image://icon/audio-volume-medium";
|
|
} else {
|
|
return "image://icon/audio-volume-low";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Application Mixer
|
|
PwNodeLinkTracker {
|
|
id: linkTracker
|
|
node: root.sink
|
|
}
|
|
|
|
StyledListView {
|
|
id: appList
|
|
visible: linkTracker.linkGroups.length !== 0
|
|
spacing: 2
|
|
model: linkTracker.linkGroups
|
|
clip: true
|
|
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: {
|
|
const entryHeight = Math.min(5, linkTracker.linkGroups.length);
|
|
|
|
return entryHeight * (menu.entryHeight + appList.spacing);
|
|
}
|
|
|
|
delegate: VolumeCard {
|
|
id: appCard
|
|
node: modelData.source
|
|
label: node.properties["media.name"] ?? ""
|
|
width: ListView.view.width
|
|
height: menu.entryHeight
|
|
|
|
required property PwLinkGroup modelData
|
|
|
|
leftWidget: StyledMouseArea {
|
|
onClicked: appCard.node.audio.muted = !appCard.node.audio.muted
|
|
|
|
IconImage {
|
|
id: appIcon
|
|
visible: false
|
|
anchors.fill: parent
|
|
|
|
source: {
|
|
if (appCard.node.properties["application.icon-name"] !== undefined)
|
|
return `image://icon/${appCard.node.properties["application.icon-name"]}`;
|
|
|
|
let applicationName = appCard.node.properties["application.name"];
|
|
return `image://icon/${applicationName?.toLowerCase() ?? "image-missing"}`;
|
|
}
|
|
}
|
|
|
|
MultiEffect {
|
|
source: appIcon
|
|
anchors.fill: appIcon
|
|
saturation: appCard.node.audio.muted ? -1.0 : 0.0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|