1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 21:45:38 -05:00

audio: create and connect volume popup to IPCs

This commit is contained in:
bbedward
2025-07-25 11:24:27 -04:00
parent 1cf252599b
commit 786b8f3fa1
5 changed files with 294 additions and 21 deletions

View File

@@ -23,7 +23,6 @@ Column {
id: volumeSlider
width: parent.width
value: Math.round(root.volumeLevel)
minimum: 0
maximum: 100
leftIcon: root.volumeMuted ? "volume_off" : "volume_down"
@@ -32,16 +31,18 @@ Column {
showValue: true
unit: "%"
onSliderValueChanged: (newValue) => {
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = false;
AudioService.sink.audio.volume = newValue / 100;
Connections {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
function onVolumeChanged() {
volumeSlider.value = Math.round(AudioService.sink.audio.volume * 100);
}
}
// Add click handler for mute icon
Component.onCompleted: {
// Find the left icon and add mouse area
if (AudioService.sink && AudioService.sink.audio) {
value = Math.round(AudioService.sink.audio.volume * 100);
}
let leftIconItem = volumeSlider.children[0].children[0];
if (leftIconItem) {
let mouseArea = Qt.createQmlObject(
@@ -51,5 +52,12 @@ Column {
);
}
}
onSliderValueChanged: (newValue) => {
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = false;
AudioService.sink.audio.volume = newValue / 100;
}
}
}
}

209
Modules/VolumePopup.qml Normal file
View File

@@ -0,0 +1,209 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common
import qs.Services
import qs.Widgets
PanelWindow {
id: root
property bool volumePopupVisible: false
visible: volumePopupVisible
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
color: "transparent"
anchors {
top: true
left: true
right: true
bottom: true
}
Timer {
id: hideTimer
interval: 3000
repeat: false
onTriggered: {
if (!volumePopup.containsMouse) {
root.volumePopupVisible = false
} else {
hideTimer.restart()
}
}
}
function show() {
root.volumePopupVisible = true;
hideTimer.restart();
}
function resetHideTimer() {
if (root.volumePopupVisible) {
hideTimer.restart();
}
}
Connections {
target: AudioService
function onVolumeChanged() {
root.show();
}
function onSinkChanged() {
if (root.volumePopupVisible) {
root.show();
}
}
}
Rectangle {
id: volumePopup
property bool containsMouse: popupMouseArea.containsMouse
width: Math.min(260, Screen.width - Theme.spacingM * 2)
height: volumeContent.height + Theme.spacingS * 2
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: Theme.spacingM
color: Theme.popupBackground()
radius: Theme.cornerRadiusLarge
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
opacity: root.volumePopupVisible ? 1 : 0
scale: root.volumePopupVisible ? 1 : 0.9
Column {
id: volumeContent
anchors.centerIn: parent
width: parent.width - Theme.spacingS * 2
spacing: Theme.spacingXS
Item {
width: parent.width
height: 40
property int gap: Theme.spacingS
Rectangle {
width: Theme.iconSize
height: Theme.iconSize
radius: Theme.iconSize / 2
color: "transparent"
x: parent.gap
anchors.verticalCenter: parent.verticalCenter
DankIcon {
anchors.centerIn: parent
name: AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.muted ?
"volume_off" : "volume_up"
size: Theme.iconSize
color: muteButton.containsMouse ? Theme.primary : Theme.surfaceText
}
MouseArea {
id: muteButton
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
AudioService.toggleMute();
root.resetHideTimer();
}
}
}
DankSlider {
id: volumeSlider
width: parent.width - Theme.iconSize - parent.gap * 3
height: 40
x: parent.gap * 2 + Theme.iconSize
anchors.verticalCenter: parent.verticalCenter
minimum: 0
maximum: 100
enabled: AudioService.sink && AudioService.sink.audio
showValue: true
unit: "%"
Connections {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
function onVolumeChanged() {
volumeSlider.value = Math.round(AudioService.sink.audio.volume * 100);
}
}
Component.onCompleted: {
if (AudioService.sink && AudioService.sink.audio) {
value = Math.round(AudioService.sink.audio.volume * 100);
}
}
onSliderValueChanged: function(newValue) {
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.volume = newValue / 100;
root.resetHideTimer();
}
}
}
}
}
MouseArea {
id: popupMouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
propagateComposedEvents: true
z: -1
}
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowBlur: 0.8
shadowColor: Qt.rgba(0, 0, 0, 0.3)
shadowOpacity: 0.3
}
transform: Translate {
y: root.volumePopupVisible ? 0 : 20
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on transform {
PropertyAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
mask: Region {
item: volumePopup
}
}

View File

@@ -66,16 +66,60 @@ IPC Events are events that can be triggered with `qs` cli.
qs -c DankMaterialShell ipc call <target> <function>
```
| Target | Function | Description |
|--------|----------|-------------|
| spotlight | toggle | Toggle spotlight (app launcher) |
| clipboard | toggle | Toggle clipboard history view |
| processlist | toggle | Toggle process list (task manager) |
| wallpaper | set \<path\> | Set wallpaper to image path and refresh theme (if auto theme enabled) |
| wallpaper | get | Get current wallpaper path |
| lock | lock | Triggers lockscreen |
| lock | demo | Triggers lockscreen demo mode |
| lock | isLocked | Whether we're locked or not |
## System Controls
| Target | Function | Parameters | Description |
|--------|----------|------------|-------------|
| audio | setvolume | percentage (string) | Set audio volume to specific percentage (0-100) |
| audio | increment | step (string, default: "5") | Increase volume by step percentage |
| audio | decrement | step (string, default: "5") | Decrease volume by step percentage |
| audio | mute | none | Toggle audio mute |
| audio | setmic | percentage (string) | Set microphone volume to specific percentage |
| audio | micmute | none | Toggle microphone mute |
| audio | status | none | Get current audio status (output/input levels and mute states) |
## Application Controls
| Target | Function | Parameters | Description |
|--------|----------|------------|-------------|
| spotlight | open | none | Open spotlight (app launcher) |
| spotlight | close | none | Close spotlight (app launcher) |
| spotlight | toggle | none | Toggle spotlight (app launcher) |
| clipboard | open | none | Open clipboard history view |
| clipboard | close | none | Close clipboard history view |
| clipboard | toggle | none | Toggle clipboard history view |
| processlist | open | none | Open process list (task manager) |
| processlist | close | none | Close process list (task manager) |
| processlist | toggle | none | Toggle process list (task manager) |
| lock | lock | none | Activate lockscreen |
| lock | demo | none | Show lockscreen in demo mode |
| lock | isLocked | none | Returns whether screen is currently locked |
| picker | open | none | Open area picker/screenshot tool |
| picker | openFreeze | none | Open area picker in freeze mode |
## Media Controls
| Target | Function | Parameters | Description |
|--------|----------|------------|-------------|
| mpris | list | none | Get list of available media players |
| mpris | play | none | Start media playback on active player |
| mpris | pause | none | Pause media playback on active player |
| mpris | playPause | none | Toggle play/pause state on active player |
| mpris | previous | none | Skip to previous track on active player |
| mpris | next | none | Skip to next track on active player |
| mpris | stop | none | Stop media playback on active player |
| mpris | getActive | prop (string) | Get specified property from active player |
## System Services
| Target | Function | Parameters | Description |
|--------|----------|------------|-------------|
| wallpaper | get | none | Get current wallpaper path |
| wallpaper | set | path (string) | Set wallpaper to image path and refresh theme |
| wallpaper | clear | none | Clear current wallpaper |
| notifs | clear | none | Clear all notifications |
| drawers | toggle | drawer (string) | Toggle visibility of specified drawer/panel |
| drawers | list | none | Get list of available drawers |
## (Optional) Setup Calendar events (Google, Microsoft, other Caldev, etc.)

View File

@@ -128,19 +128,27 @@ Singleton {
target: "audio"
function setvolume(percentage: string): string {
return root.setVolume(parseInt(percentage));
const result = root.setVolume(parseInt(percentage));
root.volumeChanged();
return result;
}
function increment(step: string): string {
return root.incrementVolume(parseInt(step || "5"));
const result = root.incrementVolume(parseInt(step || "5"));
root.volumeChanged();
return result;
}
function decrement(step: string): string {
return root.decrementVolume(parseInt(step || "5"));
const result = root.decrementVolume(parseInt(step || "5"));
root.volumeChanged();
return result;
}
function mute(): string {
return root.toggleMute();
const result = root.toggleMute();
root.volumeChanged();
return result;
}
function setmic(percentage: string): string {

View File

@@ -145,4 +145,8 @@ ShellRoot {
Toast {
id: toastWidget
}
VolumePopup {
id: volumePopup
}
}