diff --git a/modules/bar/components/Caffeine.qml b/modules/bar/components/Caffeine.qml index 19b0d0f..d97ebd1 100644 --- a/modules/bar/components/Caffeine.qml +++ b/modules/bar/components/Caffeine.qml @@ -1,11 +1,10 @@ import qs.config import qs.constants -import qs.styled import qs.widgets import Quickshell.Io StyledButton { - id: clickable + id: root border.color: process.running ? Theme.palette.secondary : 'transparent' border.width: 2 @@ -27,7 +26,7 @@ StyledButton { font.bold: true text: Icons.coffee - color: clickable.containsMouse ? Theme.palette.base300 : Theme.palette.basecontent + color: root.containsMouse ? Theme.palette.base300 : Theme.palette.basecontent } Process { diff --git a/modules/bar/components/Pipewire.qml b/modules/bar/components/Pipewire.qml index 94791ad..a06afba 100644 --- a/modules/bar/components/Pipewire.qml +++ b/modules/bar/components/Pipewire.qml @@ -1,53 +1,34 @@ import qs.config +import qs.services import qs.widgets import QtQuick -import Quickshell.Services.Pipewire StyledButton { - id: clickable - - property var sink: Pipewire.defaultAudioSink - - PwObjectTracker { - id: bound - objects: [clickable.sink] - } + id: root onClicked: mouse => { - if (!sink) { - return; - } if (mouse.button == Qt.LeftButton) { - sink.audio.muted = !sink?.audio.muted; - } else if (mouse.button == Qt.RightButton) - // show menu - {} + Pipewire.toggleMute(); + } else if (mouse.button == Qt.RightButton) { + popup.opened = !popup.opened; + } } onWheel: event => { if (event.angleDelta.y > 0) { - sink.audio.volume = Math.min(sink.audio.volume + 0.02, 1.0); + Pipewire.incrementVolume(); } else if (event.angleDelta.y < 0) { - sink.audio.volume -= 0.02; + Pipewire.decrementVolume(); } } states: [ State { name: "muted" - when: clickable.sink?.audio.muted ?? false + when: Pipewire.muted PropertyChanges { - text { - icon: " " - } - } - }, - State { - name: "off" - when: clickable.sink?.audio.volume <= 0 - PropertyChanges { - text { - icon: " " + root { + color: Theme.palette.error } } } @@ -55,9 +36,9 @@ StyledButton { content: StyledText { id: text - property string icon: " " - text: `${icon} ${(clickable.sink?.audio.volume * 100).toFixed()}%` + property string icon: Pipewire.muted ? " " : Pipewire.volume <= 0 ? " " : " " + text: `${icon} ${(Pipewire.volume * 100).toFixed()}%` font.pixelSize: Dimensions.pipewire.fontSize - color: clickable.containsMouse ? Theme.palette.base300 : Theme.palette.basecontent + color: root.containsMouse || Pipewire.muted ? Theme.palette.base300 : Theme.palette.basecontent } } diff --git a/modules/bar/components/bluetooth/Bluetooth.qml b/modules/bar/components/bluetooth/Bluetooth.qml index 2414f69..80097e0 100644 --- a/modules/bar/components/bluetooth/Bluetooth.qml +++ b/modules/bar/components/bluetooth/Bluetooth.qml @@ -5,9 +5,7 @@ import qs.widgets StyledButton { id: root - onClicked: { - popup.opened = !popup.opened; - } + onClicked: popup.toggle() content: StyledText { id: text diff --git a/modules/bar/components/bluetooth/DeviceList.qml b/modules/bar/components/bluetooth/DeviceList.qml deleted file mode 100644 index c4e5d92..0000000 --- a/modules/bar/components/bluetooth/DeviceList.qml +++ /dev/null @@ -1,46 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.config -import qs.styled -import QtQuick -import QtQuick.Layouts -import Quickshell.Bluetooth - -ColumnLayout { - id: root - required property var devices - signal deviceActivated(device: BluetoothDevice) - - Repeater { - model: root.devices - delegate: Clickable { - id: device - required property var modelData - - implicitWidth: row.width - implicitHeight: row.height - Layout.fillWidth: true - onClicked: { - root.deviceActivated(modelData); - } - - RowLayout { - id: row - - StyledText { - topPadding: 8 - bottomPadding: 8 - leftPadding: 8 - rightPadding: 8 - text: device.modelData.deviceName - color: device.containsMouse ? Theme.palette.base300 : Theme.palette.basecontent - Behavior on color { - ColorAnimation { - duration: 200 - } - } - } - } - } - } -} diff --git a/modules/bar/components/tray/TrayItem.qml b/modules/bar/components/tray/TrayItem.qml index 055171f..e199d8d 100644 --- a/modules/bar/components/tray/TrayItem.qml +++ b/modules/bar/components/tray/TrayItem.qml @@ -1,54 +1,42 @@ +pragma ComponentBehavior: Bound + +import qs.widgets import QtQuick -import QtQuick.Layouts import Quickshell import Quickshell.Services.SystemTray import Quickshell.Widgets -import "../../../../config/" -import "../../../../styled/" import "menu/" -Clickable { +StyledButton { id: root property SystemTrayItem trayItem - property bool menuOpened: false - implicitWidth: Dimensions.tray.width - implicitHeight: Dimensions.tray.height + onClicked: menu.toggle() - onClicked: toggleMenu() - - function toggleMenu() { - menuOpened = !menuOpened; - } - - IconImage { + content: IconImage { id: icon - anchors.margins: 6 - anchors.fill: parent asynchronous: true + implicitSize: 18 source: { - let icon = modelData.icon; + let icon = root.trayItem.icon; if (icon.includes("?path=")) { const [name, path] = icon.split("?path="); icon = `file://${path}/${name.slice(name.lastIndexOf("/") + 1)}`; } return icon; } - anchors.centerIn: parent } Menu { id: menu - opened: root.menuOpened - anchor.item: root anchor.rect.x: root.width / 2 - width / 2 anchor.rect.y: root.height + 8 menuOpener: QsMenuOpener { - menu: trayItem.menu + menu: root.trayItem.menu } } } diff --git a/modules/bar/components/tray/menu/Menu.qml b/modules/bar/components/tray/menu/Menu.qml index 4d49037..5b57904 100644 --- a/modules/bar/components/tray/menu/Menu.qml +++ b/modules/bar/components/tray/menu/Menu.qml @@ -20,6 +20,7 @@ StyledPopupWindow { Repeater { model: window.menuOpener.children delegate: Loader { + id: loader required property QsMenuEntry modelData active: true @@ -34,7 +35,7 @@ StyledPopupWindow { color: Theme.palette.base100 } property Component menuItem: MenuItem { - menuEntry: modelData + menuEntry: loader.modelData } } } diff --git a/services/Pipewire.qml b/services/Pipewire.qml new file mode 100644 index 0000000..53cc141 --- /dev/null +++ b/services/Pipewire.qml @@ -0,0 +1,48 @@ +pragma Singleton + +import QtQuick +import Quickshell +import Quickshell.Services.Pipewire + +Singleton { + id: root + + readonly property PwNode sink: Pipewire.defaultAudioSink + readonly property PwNode source: Pipewire.defaultAudioSource + + readonly property bool muted: sink?.audio?.muted ?? false + readonly property real volume: sink?.audio?.volume ?? 0 + + function setVolume(volume: real): void { + if (sink?.ready && sink?.audio) { + sink.audio.muted = false; + sink.audio.volume = volume; + } + } + + function incrementVolume() { + if (!sink?.ready || !sink?.audio) { + return; + } + sink.audio.muted = false; + sink.audio.volume = Math.min(sink.audio.volume + 0.02, 1.0); + } + + function decrementVolume() { + if (!sink?.ready || !sink?.audio) { + return; + } + sink.audio.volume -= 0.02; + } + + function toggleMute() { + if (!sink?.ready || !sink?.audio) { + return; + } + sink.audio.muted = !sink.audio.muted; + } + + PwObjectTracker { + objects: [Pipewire.defaultAudioSink, Pipewire.defaultAudioSource] + } +} diff --git a/services/Visibility.qml b/services/Visibility.qml new file mode 100644 index 0000000..3015f7a --- /dev/null +++ b/services/Visibility.qml @@ -0,0 +1,16 @@ +pragma Singleton + +import qs.widgets +import Quickshell + +Singleton { + property StyledPopupWindow activePopup + + function togglePopup(popup: StyledPopupWindow) { + if (activePopup && popup != activePopup) { + activePopup.state = ""; + } + popup.state = popup.state == "opened" ? "" : "opened"; + activePopup = popup; + } +} diff --git a/styled/Clickable.qml b/styled/Clickable.qml deleted file mode 100644 index c012668..0000000 --- a/styled/Clickable.qml +++ /dev/null @@ -1,26 +0,0 @@ -import QtQuick -import "../config/" - -MouseArea { - id: mouseArea - - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - property alias color: rectangle.color - property alias border: rectangle.border - - Rectangle { - id: rectangle - anchors.fill: parent - - radius: Dimensions.radius - color: mouseArea.containsMouse ? Theme.palette.primary : Theme.palette.base100 - Behavior on color { - ColorAnimation { - properties: "color" - duration: 200 - easing.type: Easing.InOutQuad - } - } - } -} diff --git a/styled/Icon.qml b/styled/Icon.qml deleted file mode 100644 index 2c19f55..0000000 --- a/styled/Icon.qml +++ /dev/null @@ -1,21 +0,0 @@ -import QtQuick -import QtQuick.Effects -import "../config/" - -Image { - id: root - - property int size: 18 - property color color: Theme.palette.basecontent - - width: size - height: size - - MultiEffect { - id: effect - source: root - anchors.fill: root - colorization: 1.0 - colorizationColor: color - } -} diff --git a/styled/StyledLabel.qml b/styled/StyledLabel.qml deleted file mode 100644 index 3d78058..0000000 --- a/styled/StyledLabel.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick -import "../config/" - -Rectangle { - color: Theme.palette.base100 - - radius: Dimensions.radius -} diff --git a/styled/StyledText.qml b/styled/StyledText.qml deleted file mode 100644 index d2fc577..0000000 --- a/styled/StyledText.qml +++ /dev/null @@ -1,7 +0,0 @@ -import QtQuick -import "root:config" - -Text { - color: Theme.palette.basecontent - font.family: Theme.fontFamily -} diff --git a/widgets/StyledPopupWindow.qml b/widgets/StyledPopupWindow.qml index 924001a..4b7ed4f 100644 --- a/widgets/StyledPopupWindow.qml +++ b/widgets/StyledPopupWindow.qml @@ -1,3 +1,4 @@ +import qs.services import QtQuick import Quickshell import Quickshell.Widgets @@ -9,10 +10,15 @@ PopupWindow { property alias margins: background.margin property alias backgroundColor: background.color property alias radius: background.radius + property alias state: background.state required property Component content color: "transparent" + function toggle() { + Visibility.togglePopup(this); + } + implicitWidth: background.width Behavior on implicitWidth { NumberAnimation { diff --git a/styled/StyledWindow.qml b/widgets/StyledWindow.qml similarity index 100% rename from styled/StyledWindow.qml rename to widgets/StyledWindow.qml