mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 15:32:50 -05:00
Add percentage to the volume control slider
This commit is contained in:
@@ -10,7 +10,7 @@ import qs.Widgets
|
|||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property real micLevel: (AudioService.source && AudioService.source.audio && AudioService.source.audio.volume * 100) || 0
|
property real micLevel: Math.min(100, (AudioService.source && AudioService.source.audio && AudioService.source.audio.volume * 100) || 0)
|
||||||
property bool micMuted: (AudioService.source && AudioService.source.audio && AudioService.source.audio.muted) || false
|
property bool micMuted: (AudioService.source && AudioService.source.audio && AudioService.source.audio.muted) || false
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -93,6 +93,37 @@ Column {
|
|||||||
duration: 150
|
duration: 150
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: micTooltip
|
||||||
|
width: tooltipText.contentWidth + Theme.spacingS * 2
|
||||||
|
height: tooltipText.contentHeight + Theme.spacingXS * 2
|
||||||
|
radius: Theme.cornerRadiusSmall
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
border.color: Theme.outline
|
||||||
|
border.width: 1
|
||||||
|
anchors.bottom: parent.top
|
||||||
|
anchors.bottomMargin: Theme.spacingS
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
visible: (micMouseArea.containsMouse && !root.micMuted) || micMouseArea.isDragging
|
||||||
|
opacity: visible ? 1 : 0
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: tooltipText
|
||||||
|
text: Math.round(root.micLevel) + "%"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +151,7 @@ Column {
|
|||||||
onPositionChanged: (mouse) => {
|
onPositionChanged: (mouse) => {
|
||||||
if (pressed && isDragging) {
|
if (pressed && isDragging) {
|
||||||
let ratio = Math.max(0, Math.min(1, mouse.x / micSliderTrack.width));
|
let ratio = Math.max(0, Math.min(1, mouse.x / micSliderTrack.width));
|
||||||
let newMicLevel = Math.round(ratio * 100);
|
let newMicLevel = Math.max(0, Math.min(100, Math.round(ratio * 100)));
|
||||||
if (AudioService.source && AudioService.source.audio) {
|
if (AudioService.source && AudioService.source.audio) {
|
||||||
AudioService.source.audio.muted = false;
|
AudioService.source.audio.muted = false;
|
||||||
AudioService.source.audio.volume = newMicLevel / 100;
|
AudioService.source.audio.volume = newMicLevel / 100;
|
||||||
@@ -151,7 +182,7 @@ Column {
|
|||||||
if (micMouseArea.isDragging) {
|
if (micMouseArea.isDragging) {
|
||||||
let globalPos = mapToItem(micSliderTrack, mouse.x, mouse.y);
|
let globalPos = mapToItem(micSliderTrack, mouse.x, mouse.y);
|
||||||
let ratio = Math.max(0, Math.min(1, globalPos.x / micSliderTrack.width));
|
let ratio = Math.max(0, Math.min(1, globalPos.x / micSliderTrack.width));
|
||||||
let newMicLevel = Math.round(ratio * 100);
|
let newMicLevel = Math.max(0, Math.min(100, Math.round(ratio * 100)));
|
||||||
if (AudioService.source && AudioService.source.audio) {
|
if (AudioService.source && AudioService.source.audio) {
|
||||||
AudioService.source.audio.muted = false;
|
AudioService.source.audio.muted = false;
|
||||||
AudioService.source.audio.volume = newMicLevel / 100;
|
AudioService.source.audio.volume = newMicLevel / 100;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import qs.Widgets
|
|||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property real volumeLevel: (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.volume * 100) || 0
|
property real volumeLevel: Math.min(100, (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.volume * 100) || 0)
|
||||||
property bool volumeMuted: (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.muted) || false
|
property bool volumeMuted: (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.muted) || false
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -93,6 +93,37 @@ Column {
|
|||||||
duration: 150
|
duration: 150
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: volumeTooltip
|
||||||
|
width: tooltipText.contentWidth + Theme.spacingS * 2
|
||||||
|
height: tooltipText.contentHeight + Theme.spacingXS * 2
|
||||||
|
radius: Theme.cornerRadiusSmall
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
border.color: Theme.outline
|
||||||
|
border.width: 1
|
||||||
|
anchors.bottom: parent.top
|
||||||
|
anchors.bottomMargin: Theme.spacingS
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
visible: (volumeMouseArea.containsMouse && !root.volumeMuted) || volumeMouseArea.isDragging
|
||||||
|
opacity: visible ? 1 : 0
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: tooltipText
|
||||||
|
text: Math.round(root.volumeLevel) + "%"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +139,7 @@ Column {
|
|||||||
onPressed: (mouse) => {
|
onPressed: (mouse) => {
|
||||||
isDragging = true;
|
isDragging = true;
|
||||||
let ratio = Math.max(0, Math.min(1, mouse.x / volumeSliderTrack.width));
|
let ratio = Math.max(0, Math.min(1, mouse.x / volumeSliderTrack.width));
|
||||||
let newVolume = Math.round(ratio * 100);
|
let newVolume = Math.max(0, Math.min(100, Math.round(ratio * 100)));
|
||||||
if (AudioService.sink && AudioService.sink.audio) {
|
if (AudioService.sink && AudioService.sink.audio) {
|
||||||
AudioService.sink.audio.muted = false;
|
AudioService.sink.audio.muted = false;
|
||||||
AudioService.sink.audio.volume = newVolume / 100;
|
AudioService.sink.audio.volume = newVolume / 100;
|
||||||
@@ -120,7 +151,7 @@ Column {
|
|||||||
onPositionChanged: (mouse) => {
|
onPositionChanged: (mouse) => {
|
||||||
if (pressed && isDragging) {
|
if (pressed && isDragging) {
|
||||||
let ratio = Math.max(0, Math.min(1, mouse.x / volumeSliderTrack.width));
|
let ratio = Math.max(0, Math.min(1, mouse.x / volumeSliderTrack.width));
|
||||||
let newVolume = Math.round(ratio * 100);
|
let newVolume = Math.max(0, Math.min(100, Math.round(ratio * 100)));
|
||||||
if (AudioService.sink && AudioService.sink.audio) {
|
if (AudioService.sink && AudioService.sink.audio) {
|
||||||
AudioService.sink.audio.muted = false;
|
AudioService.sink.audio.muted = false;
|
||||||
AudioService.sink.audio.volume = newVolume / 100;
|
AudioService.sink.audio.volume = newVolume / 100;
|
||||||
@@ -129,7 +160,7 @@ Column {
|
|||||||
}
|
}
|
||||||
onClicked: (mouse) => {
|
onClicked: (mouse) => {
|
||||||
let ratio = Math.max(0, Math.min(1, mouse.x / volumeSliderTrack.width));
|
let ratio = Math.max(0, Math.min(1, mouse.x / volumeSliderTrack.width));
|
||||||
let newVolume = Math.round(ratio * 100);
|
let newVolume = Math.max(0, Math.min(100, Math.round(ratio * 100)));
|
||||||
if (AudioService.sink && AudioService.sink.audio) {
|
if (AudioService.sink && AudioService.sink.audio) {
|
||||||
AudioService.sink.audio.muted = false;
|
AudioService.sink.audio.muted = false;
|
||||||
AudioService.sink.audio.volume = newVolume / 100;
|
AudioService.sink.audio.volume = newVolume / 100;
|
||||||
@@ -151,7 +182,7 @@ Column {
|
|||||||
if (volumeMouseArea.isDragging) {
|
if (volumeMouseArea.isDragging) {
|
||||||
let globalPos = mapToItem(volumeSliderTrack, mouse.x, mouse.y);
|
let globalPos = mapToItem(volumeSliderTrack, mouse.x, mouse.y);
|
||||||
let ratio = Math.max(0, Math.min(1, globalPos.x / volumeSliderTrack.width));
|
let ratio = Math.max(0, Math.min(1, globalPos.x / volumeSliderTrack.width));
|
||||||
let newVolume = Math.round(ratio * 100);
|
let newVolume = Math.max(0, Math.min(100, Math.round(ratio * 100)));
|
||||||
if (AudioService.sink && AudioService.sink.audio) {
|
if (AudioService.sink && AudioService.sink.audio) {
|
||||||
AudioService.sink.audio.muted = false;
|
AudioService.sink.audio.muted = false;
|
||||||
AudioService.sink.audio.volume = newVolume / 100;
|
AudioService.sink.audio.volume = newVolume / 100;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
import Quickshell.Services.Pipewire
|
import Quickshell.Services.Pipewire
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
@@ -11,6 +12,8 @@ Singleton {
|
|||||||
readonly property PwNode sink: Pipewire.defaultAudioSink
|
readonly property PwNode sink: Pipewire.defaultAudioSink
|
||||||
readonly property PwNode source: Pipewire.defaultAudioSource
|
readonly property PwNode source: Pipewire.defaultAudioSource
|
||||||
|
|
||||||
|
signal volumeChanged()
|
||||||
|
|
||||||
function displayName(node) {
|
function displayName(node) {
|
||||||
if (!node) return ""
|
if (!node) return ""
|
||||||
|
|
||||||
@@ -63,4 +66,109 @@ Singleton {
|
|||||||
PwObjectTracker {
|
PwObjectTracker {
|
||||||
objects: [Pipewire.defaultAudioSink, Pipewire.defaultAudioSource]
|
objects: [Pipewire.defaultAudioSink, Pipewire.defaultAudioSource]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Volume control functions
|
||||||
|
function setVolume(percentage) {
|
||||||
|
if (root.sink && root.sink.audio) {
|
||||||
|
const clampedVolume = Math.max(0, Math.min(100, percentage));
|
||||||
|
root.sink.audio.volume = clampedVolume / 100;
|
||||||
|
return "Volume set to " + clampedVolume + "%";
|
||||||
|
}
|
||||||
|
return "No audio sink available";
|
||||||
|
}
|
||||||
|
|
||||||
|
function incrementVolume(step) {
|
||||||
|
if (root.sink && root.sink.audio) {
|
||||||
|
const currentVolume = Math.round(root.sink.audio.volume * 100);
|
||||||
|
const newVolume = Math.max(0, Math.min(100, currentVolume + step));
|
||||||
|
root.sink.audio.volume = newVolume / 100;
|
||||||
|
return "Volume increased to " + newVolume + "%";
|
||||||
|
}
|
||||||
|
return "No audio sink available";
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrementVolume(step) {
|
||||||
|
if (root.sink && root.sink.audio) {
|
||||||
|
const currentVolume = Math.round(root.sink.audio.volume * 100);
|
||||||
|
const newVolume = Math.max(0, Math.min(100, currentVolume - step));
|
||||||
|
root.sink.audio.volume = newVolume / 100;
|
||||||
|
return "Volume decreased to " + newVolume + "%";
|
||||||
|
}
|
||||||
|
return "No audio sink available";
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMute() {
|
||||||
|
if (root.sink && root.sink.audio) {
|
||||||
|
root.sink.audio.muted = !root.sink.audio.muted;
|
||||||
|
return root.sink.audio.muted ? "Audio muted" : "Audio unmuted";
|
||||||
|
}
|
||||||
|
return "No audio sink available";
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMicVolume(percentage) {
|
||||||
|
if (root.source && root.source.audio) {
|
||||||
|
const clampedVolume = Math.max(0, Math.min(100, percentage));
|
||||||
|
root.source.audio.volume = clampedVolume / 100;
|
||||||
|
return "Microphone volume set to " + clampedVolume + "%";
|
||||||
|
}
|
||||||
|
return "No audio source available";
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMicMute() {
|
||||||
|
if (root.source && root.source.audio) {
|
||||||
|
root.source.audio.muted = !root.source.audio.muted;
|
||||||
|
return root.source.audio.muted ? "Microphone muted" : "Microphone unmuted";
|
||||||
|
}
|
||||||
|
return "No audio source available";
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPC Handler for external control
|
||||||
|
IpcHandler {
|
||||||
|
target: "audio"
|
||||||
|
|
||||||
|
function setvolume(percentage: string): string {
|
||||||
|
return root.setVolume(parseInt(percentage));
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment(step: string): string {
|
||||||
|
return root.incrementVolume(parseInt(step || "5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrement(step: string): string {
|
||||||
|
return root.decrementVolume(parseInt(step || "5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function mute(): string {
|
||||||
|
return root.toggleMute();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setmic(percentage: string): string {
|
||||||
|
return root.setMicVolume(parseInt(percentage));
|
||||||
|
}
|
||||||
|
|
||||||
|
function micmute(): string {
|
||||||
|
return root.toggleMicMute();
|
||||||
|
}
|
||||||
|
|
||||||
|
function status(): string {
|
||||||
|
let result = "Audio Status:\n";
|
||||||
|
if (root.sink && root.sink.audio) {
|
||||||
|
const volume = Math.round(root.sink.audio.volume * 100);
|
||||||
|
result += "Output: " + volume + "%" + (root.sink.audio.muted ? " (muted)" : "") + "\n";
|
||||||
|
} else {
|
||||||
|
result += "Output: No sink available\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.source && root.source.audio) {
|
||||||
|
const micVolume = Math.round(root.source.audio.volume * 100);
|
||||||
|
result += "Input: " + micVolume + "%" + (root.source.audio.muted ? " (muted)" : "");
|
||||||
|
} else {
|
||||||
|
result += "Input: No source available";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
//@ pragma UseQApplication
|
//@ pragma UseQApplication
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
@@ -43,6 +44,7 @@ ShellRoot {
|
|||||||
id: systemTrayContextMenu
|
id: systemTrayContextMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NotificationCenterPopout {
|
NotificationCenterPopout {
|
||||||
id: notificationCenter
|
id: notificationCenter
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user