add popup for audio management
This commit is contained in:
parent
f409062ba6
commit
5005ba24db
11 changed files with 298 additions and 120 deletions
1
.qmlls.ini
Symbolic link
1
.qmlls.ini
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/run/user/1000/quickshell/vfs/1b52f593d70d8ccef6fc467cf768a2ef/.qmlls.ini
|
||||||
32
Colors.js
32
Colors.js
|
|
@ -1,18 +1,18 @@
|
||||||
const colors = {
|
const colors = {
|
||||||
base00: "#1e1e2e",
|
base00: "#161616",
|
||||||
base01: "#181825",
|
base01: "#262626",
|
||||||
base02: "#313244",
|
base02: "#393939",
|
||||||
base03: "#45475a",
|
base03: "#525252",
|
||||||
base04: "#585b70",
|
base04: "#dde1e6",
|
||||||
base05: "#cdd6f4",
|
base05: "#f2f4f8",
|
||||||
base06: "#f5e0dc",
|
base06: "#ffffff",
|
||||||
base07: "#b4befe",
|
base07: "#08bdba",
|
||||||
base08: "#f38ba8",
|
base08: "#ee5396",
|
||||||
base09: "#fab387",
|
base09: "#ff7eb6",
|
||||||
base0A: "#f9e2af",
|
base0A: "#ff6f00",
|
||||||
base0B: "#a6e3a1",
|
base0B: "#42be65",
|
||||||
base0C: "#94e2d5",
|
base0C: "#3ddbd9",
|
||||||
base0D: "#89b4fa",
|
base0D: "#33b1ff",
|
||||||
base0E: "#cba6f7",
|
base0E: "#be95ff",
|
||||||
base0F: "#f2cdcd",
|
base0F: "#82cfff",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
modules/Services/Audio.qml
Normal file
34
modules/Services/Audio.qml
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
pragma Singleton
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
property bool ready: Pipewire.ready
|
||||||
|
property bool muted: defaultAudio.audio.muted
|
||||||
|
property PwNode defaultAudio: Pipewire.defaultAudioSink
|
||||||
|
property PwNode preferredAudio: Pipewire.preferredDefaultAudioSink
|
||||||
|
property real percentage: Math.round(preferredAudio?.audio.volume * 100)
|
||||||
|
readonly property list<PwNode> sinks: Pipewire.nodes.values.filter(n => n.audio && n.isSink && !n.isStream)
|
||||||
|
readonly property list<PwNode> sources: Pipewire.nodes.values.filter(n => n.audio && !n.isSink && !n.isStream)
|
||||||
|
PwObjectTracker {
|
||||||
|
objects: [...root.sinks, ...root.sources]
|
||||||
|
}
|
||||||
|
function getVolumeIcon(sink) {
|
||||||
|
let mute = sink.audio.muted
|
||||||
|
let volume = sink.audio.volume
|
||||||
|
if (mute) {
|
||||||
|
return "audio-volume-muted-symbolic";
|
||||||
|
}
|
||||||
|
if (volume <= 0.33) {
|
||||||
|
return "audio-volume-low-symbolic";
|
||||||
|
}
|
||||||
|
if (volume <= 0.66) {
|
||||||
|
return "audio-volume-medium-symbolic";
|
||||||
|
}
|
||||||
|
if (volume >= 0.66) {
|
||||||
|
return "audio-volume-high-symbolic";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
modules/Services/Audio.qml~
Normal file
10
modules/Services/Audio.qml~
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
pragma Singleton
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Pipewire
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
property
|
||||||
|
}
|
||||||
|
|
@ -6,44 +6,48 @@ import qs.settings
|
||||||
import qs.widgets
|
import qs.widgets
|
||||||
import qs
|
import qs
|
||||||
|
|
||||||
|
|
||||||
Variants {
|
Variants {
|
||||||
model: Quickshell.screens
|
model: Quickshell.screens
|
||||||
delegate: PanelWindow {
|
delegate: PanelWindow {
|
||||||
required property ShellScreen modelData
|
id: root
|
||||||
id: root
|
required property ShellScreen modelData
|
||||||
screen: modelData
|
screen: modelData
|
||||||
anchors {
|
anchors {
|
||||||
top: true
|
top: true
|
||||||
left: true
|
left: true
|
||||||
right: true
|
right: true
|
||||||
}
|
}
|
||||||
color: 'transparent'
|
color: 'transparent'
|
||||||
implicitHeight: Config.barHeight
|
implicitHeight: Config.barHeight
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Colors.barBg
|
color: Colors.barBg
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.leftMargin: 10
|
anchors.leftMargin: 10
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
Ws { barScreen: root.modelData }
|
Ws {
|
||||||
ActiveWindow {}
|
barScreen: root.modelData
|
||||||
}
|
}
|
||||||
RowLayout {
|
ActiveWindow {}
|
||||||
anchors.centerIn: parent
|
}
|
||||||
Date {}
|
RowLayout {
|
||||||
}
|
anchors.centerIn: parent
|
||||||
RowLayout {
|
Date {}
|
||||||
anchors.rightMargin: 10
|
}
|
||||||
anchors.right: parent.right
|
RowLayout {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.rightMargin: 10
|
||||||
Mpris {}
|
anchors.right: parent.right
|
||||||
Bat {}
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
Pw {}
|
Mpris {}
|
||||||
Tray {}
|
Bat {}
|
||||||
WallPicker {screenHeight: root.screen.height}
|
|
||||||
}
|
Tray {}
|
||||||
}
|
WallPicker {
|
||||||
|
screenHeight: root.screen.height
|
||||||
|
}
|
||||||
|
Pw {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import QtQuick.Effects
|
||||||
import qs
|
import qs
|
||||||
import qs.widgets
|
import qs.widgets
|
||||||
import qs.settings
|
import qs.settings
|
||||||
|
import qs.modules.Services
|
||||||
|
|
||||||
BarComponent {
|
BarComponent {
|
||||||
id: root
|
id: root
|
||||||
|
|
@ -17,50 +18,23 @@ BarComponent {
|
||||||
property bool mute: Pipewire.ready ? defaultAudio?.audio.muted : null
|
property bool mute: Pipewire.ready ? defaultAudio?.audio.muted : null
|
||||||
implicitHeight: Config.moduleHeight
|
implicitHeight: Config.moduleHeight
|
||||||
implicitWidth: pwLayout.implicitWidth + 16
|
implicitWidth: pwLayout.implicitWidth + 16
|
||||||
function getVolumeIcon() {
|
|
||||||
let volume = Pipewire.ready ? root.defaultAudio.audio.volume : null;
|
|
||||||
if (root.mute) {
|
|
||||||
return "audio-volume-muted";
|
|
||||||
}
|
|
||||||
if (volume <= 0.33) {
|
|
||||||
return "audio-volume-low";
|
|
||||||
}
|
|
||||||
if (volume <= 0.66) {
|
|
||||||
return "audio-volume-medium";
|
|
||||||
}
|
|
||||||
if (volume >= 0.66) {
|
|
||||||
return "audio-volume-high";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
PwObjectTracker {
|
|
||||||
objects: [Pipewire.ready ? Pipewire.defaultAudioSink : null]
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: pavuLauncher
|
|
||||||
command: ["pavucontrol"]
|
|
||||||
running: false
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: pwLayout
|
id: pwLayout
|
||||||
anchors.centerIn: root
|
anchors.centerIn: root
|
||||||
spacing: 4
|
spacing: 4
|
||||||
IconImage {
|
IconImage {
|
||||||
source: Quickshell.iconPath(root.getVolumeIcon() + "-symbolic", root.getVolumeIcon())
|
source: Quickshell.iconPath(Audio.getVolumeIcon(Audio.defaultAudio))
|
||||||
implicitSize: 14
|
implicitSize: 14
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
layer.effect: MultiEffect {
|
layer.effect: MultiEffect {
|
||||||
colorization: 1.0
|
colorization: 1.0
|
||||||
colorizationColor: Colors.text
|
colorizationColor: Colors.text
|
||||||
brightness: 0.5
|
brightness: 0.5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StyledText {
|
StyledText {
|
||||||
text: Math.round(root.defaultAudio?.audio.volume * 100) + "%"
|
text: Audio.percentage + "%"
|
||||||
opacity: root.defaultAudio?.audio.muted ? 0.6 : 1.0
|
opacity: Audio.muted ? 0.6 : 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|
@ -71,35 +45,8 @@ BarComponent {
|
||||||
anchors.fill: root
|
anchors.fill: root
|
||||||
onClicked: volPopup.visible = !volPopup.visible
|
onClicked: volPopup.visible = !volPopup.visible
|
||||||
}
|
}
|
||||||
PopupWindow {
|
VolPopup {
|
||||||
id: volPopup
|
id: volPopup
|
||||||
anchor.item: root
|
anchor.item: root
|
||||||
implicitWidth: 250
|
|
||||||
implicitHeight: 600
|
|
||||||
|
|
||||||
anchor.edges: Edges.Top
|
|
||||||
anchor.gravity: Edges.Bottom
|
|
||||||
anchor.margins.top: 40
|
|
||||||
color: 'transparent'
|
|
||||||
Rectangle {
|
|
||||||
id: test
|
|
||||||
anchors.fill: parent
|
|
||||||
color: Colors.activeModuleBg
|
|
||||||
radius: Config.rounding
|
|
||||||
ListView {
|
|
||||||
id: sourceLayout
|
|
||||||
|
|
||||||
model: Pipewire.nodes
|
|
||||||
delegate: Rectangle {
|
|
||||||
implicitHeight: 10
|
|
||||||
|
|
||||||
required property var modelData
|
|
||||||
StyledText {
|
|
||||||
text: parent.modelData.nickname
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
102
modules/bar/VolPopup.qml
Normal file
102
modules/bar/VolPopup.qml
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
import qs
|
||||||
|
import qs.settings
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import qs.widgets
|
||||||
|
import qs.modules.Services
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
implicitWidth: 400
|
||||||
|
implicitHeight: audioLayout.implicitHeight + 24
|
||||||
|
anchor.edges: Edges.Top | Edges.Right
|
||||||
|
anchor.gravity: Edges.Bottom | Edges.Left
|
||||||
|
anchor.margins.top: 40
|
||||||
|
color: 'transparent'
|
||||||
|
Rectangle {
|
||||||
|
id: test
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Colors.moduleBg
|
||||||
|
radius: Config.rounding
|
||||||
|
ColumnLayout {
|
||||||
|
id: audioLayout
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 12
|
||||||
|
spacing: 8
|
||||||
|
Repeater {
|
||||||
|
model: Audio.sinks
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: audioDelContainer
|
||||||
|
color: Colors.activeModuleBg
|
||||||
|
radius: Config.rounding
|
||||||
|
required property var modelData
|
||||||
|
implicitWidth: 380
|
||||||
|
implicitHeight: audioRow.implicitHeight + 8
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: audioRow
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: audioDelContainer.modelData.nickname
|
||||||
|
Layout.leftMargin: 10
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
IconImage {
|
||||||
|
source: Quickshell.iconPath(Audio.getVolumeIcon(audioDelContainer.modelData))
|
||||||
|
implicitSize: 16
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: MultiEffect {
|
||||||
|
colorization: 1.0
|
||||||
|
colorizationColor: Colors.text
|
||||||
|
brightness: 0.5
|
||||||
|
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
onClicked: {
|
||||||
|
audioDelContainer.modelData.audio.muted = !audioDelContainer.modelData.audio.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IconImage {
|
||||||
|
source: Quickshell.iconPath(audioDelContainer.modelData === Audio.preferredAudio ? "radio-checked-symbolic" : "radio-symbolic")
|
||||||
|
implicitSize: 16
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: MultiEffect {
|
||||||
|
colorization: 1.0
|
||||||
|
colorizationColor: Colors.text
|
||||||
|
brightness: 0.5
|
||||||
|
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
onClicked: {
|
||||||
|
Audio.preferredAudio = audioDelContainer.modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Slider {
|
||||||
|
Layout.rightMargin: 10
|
||||||
|
value: audioDelContainer.modelData.audio.volume
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
onMoved: {
|
||||||
|
audioDelContainer.modelData.audio.volume = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
modules/bar/VolPopup.qml~
Normal file
39
modules/bar/VolPopup.qml~
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import qs
|
||||||
|
import qs.settings
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import qs.widgets
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: volPopup
|
||||||
|
anchor.item: root
|
||||||
|
implicitWidth: 500
|
||||||
|
implicitHeight: 600
|
||||||
|
|
||||||
|
anchor.edges: Edges.Top | Edges.Right
|
||||||
|
anchor.gravity: Edges.Bottom | Edges.Left
|
||||||
|
anchor.margins.top: 40
|
||||||
|
anchor.margins.right: 0
|
||||||
|
color: 'transparent'
|
||||||
|
Rectangle {
|
||||||
|
id: test
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Colors.activeModuleBg
|
||||||
|
radius: Config.rounding
|
||||||
|
ListView {
|
||||||
|
id: sourceLayout
|
||||||
|
|
||||||
|
model: Pipewire.nodes
|
||||||
|
delegate: Rectangle {
|
||||||
|
implicitHeight: 10
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
StyledText {
|
||||||
|
text: parent.modelData.nickname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
modules/bar/volPopup.qml~
Normal file
40
modules/bar/volPopup.qml~
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import qs
|
||||||
|
import qs.settings
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import QtQuick
|
||||||
|
import qs.widgets
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: volPopup
|
||||||
|
anchor.item: root
|
||||||
|
implicitWidth: 500
|
||||||
|
implicitHeight: 600
|
||||||
|
|
||||||
|
anchor.edges: Edges.Top | Edges.Right
|
||||||
|
anchor.gravity: Edges.Bottom | Edges.Left
|
||||||
|
anchor.margins.top: 40
|
||||||
|
anchor.margins.right: 0
|
||||||
|
color: 'transparent'
|
||||||
|
Rectangle {
|
||||||
|
id: test
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Colors.activeModuleBg
|
||||||
|
radius: Config.rounding
|
||||||
|
ListView {
|
||||||
|
id: sourceLayout
|
||||||
|
|
||||||
|
model: Pipewire.nodes
|
||||||
|
delegate: Rectangle {
|
||||||
|
implicitHeight: 10
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
StyledText {
|
||||||
|
text: parent.modelData.nickname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ fontSize=16
|
||||||
iconSize=12
|
iconSize=12
|
||||||
opacity=1
|
opacity=1
|
||||||
primaryMon=eDP-1
|
primaryMon=eDP-1
|
||||||
rounding=4
|
rounding=16
|
||||||
showCorners=true
|
showCorners=true
|
||||||
wallDir=file:///home/lucy/.walls
|
wallDir=file:///home/lucy/.walls
|
||||||
wallpaper=@Variant(\0\0\0\x11\0\0\0!/home/lucy/.walls/frierensuff.png)
|
wallpaper=@Variant(\0\0\0\x11\0\0\0!/home/lucy/.walls/frierensuff.png)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import Quickshell
|
||||||
import qs.modules.bar
|
import qs.modules.bar
|
||||||
import qs.modules.wallpaper
|
import qs.modules.wallpaper
|
||||||
import qs.modules.notifications
|
import qs.modules.notifications
|
||||||
|
import qs.modules.Services
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
Bar {}
|
Bar {}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue