diff --git a/modules/bar/components/Caffeine.qml b/modules/bar/components/Caffeine.qml index d97ebd1..19b0d0f 100644 --- a/modules/bar/components/Caffeine.qml +++ b/modules/bar/components/Caffeine.qml @@ -1,10 +1,11 @@ import qs.config import qs.constants +import qs.styled import qs.widgets import Quickshell.Io StyledButton { - id: root + id: clickable border.color: process.running ? Theme.palette.secondary : 'transparent' border.width: 2 @@ -26,7 +27,7 @@ StyledButton { font.bold: true text: Icons.coffee - color: root.containsMouse ? Theme.palette.base300 : Theme.palette.basecontent + color: clickable.containsMouse ? Theme.palette.base300 : Theme.palette.basecontent } Process { diff --git a/modules/bar/components/Pipewire.qml b/modules/bar/components/Pipewire.qml index a06afba..94791ad 100644 --- a/modules/bar/components/Pipewire.qml +++ b/modules/bar/components/Pipewire.qml @@ -1,34 +1,53 @@ import qs.config -import qs.services import qs.widgets import QtQuick +import Quickshell.Services.Pipewire StyledButton { - id: root + id: clickable + + property var sink: Pipewire.defaultAudioSink + + PwObjectTracker { + id: bound + objects: [clickable.sink] + } onClicked: mouse => { - if (mouse.button == Qt.LeftButton) { - Pipewire.toggleMute(); - } else if (mouse.button == Qt.RightButton) { - popup.opened = !popup.opened; + if (!sink) { + return; } + if (mouse.button == Qt.LeftButton) { + sink.audio.muted = !sink?.audio.muted; + } else if (mouse.button == Qt.RightButton) + // show menu + {} } onWheel: event => { if (event.angleDelta.y > 0) { - Pipewire.incrementVolume(); + sink.audio.volume = Math.min(sink.audio.volume + 0.02, 1.0); } else if (event.angleDelta.y < 0) { - Pipewire.decrementVolume(); + sink.audio.volume -= 0.02; } } states: [ State { name: "muted" - when: Pipewire.muted + when: clickable.sink?.audio.muted ?? false PropertyChanges { - root { - color: Theme.palette.error + text { + icon: " " + } + } + }, + State { + name: "off" + when: clickable.sink?.audio.volume <= 0 + PropertyChanges { + text { + icon: " " } } } @@ -36,9 +55,9 @@ StyledButton { content: StyledText { id: text - property string icon: Pipewire.muted ? " " : Pipewire.volume <= 0 ? " " : " " - text: `${icon} ${(Pipewire.volume * 100).toFixed()}%` + property string icon: " " + text: `${icon} ${(clickable.sink?.audio.volume * 100).toFixed()}%` font.pixelSize: Dimensions.pipewire.fontSize - color: root.containsMouse || Pipewire.muted ? Theme.palette.base300 : Theme.palette.basecontent + color: clickable.containsMouse ? Theme.palette.base300 : Theme.palette.basecontent } } diff --git a/modules/bar/components/bluetooth/Bluetooth.qml b/modules/bar/components/bluetooth/Bluetooth.qml index 80097e0..2414f69 100644 --- a/modules/bar/components/bluetooth/Bluetooth.qml +++ b/modules/bar/components/bluetooth/Bluetooth.qml @@ -5,7 +5,9 @@ import qs.widgets StyledButton { id: root - onClicked: popup.toggle() + onClicked: { + popup.opened = !popup.opened; + } content: StyledText { id: text diff --git a/modules/bar/components/bluetooth/DeviceList.qml b/modules/bar/components/bluetooth/DeviceList.qml new file mode 100644 index 0000000..c4e5d92 --- /dev/null +++ b/modules/bar/components/bluetooth/DeviceList.qml @@ -0,0 +1,46 @@ +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 e199d8d..055171f 100644 --- a/modules/bar/components/tray/TrayItem.qml +++ b/modules/bar/components/tray/TrayItem.qml @@ -1,42 +1,54 @@ -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/" -StyledButton { +Clickable { id: root property SystemTrayItem trayItem + property bool menuOpened: false - onClicked: menu.toggle() + implicitWidth: Dimensions.tray.width + implicitHeight: Dimensions.tray.height - content: IconImage { + onClicked: toggleMenu() + + function toggleMenu() { + menuOpened = !menuOpened; + } + + IconImage { id: icon + anchors.margins: 6 + anchors.fill: parent asynchronous: true - implicitSize: 18 source: { - let icon = root.trayItem.icon; + let icon = modelData.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: root.trayItem.menu + menu: trayItem.menu } } } diff --git a/modules/bar/components/tray/menu/Menu.qml b/modules/bar/components/tray/menu/Menu.qml index 5b57904..4d49037 100644 --- a/modules/bar/components/tray/menu/Menu.qml +++ b/modules/bar/components/tray/menu/Menu.qml @@ -20,7 +20,6 @@ StyledPopupWindow { Repeater { model: window.menuOpener.children delegate: Loader { - id: loader required property QsMenuEntry modelData active: true @@ -35,7 +34,7 @@ StyledPopupWindow { color: Theme.palette.base100 } property Component menuItem: MenuItem { - menuEntry: loader.modelData + menuEntry: modelData } } } diff --git a/services/Pipewire.qml b/services/Pipewire.qml deleted file mode 100644 index 53cc141..0000000 --- a/services/Pipewire.qml +++ /dev/null @@ -1,48 +0,0 @@ -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 deleted file mode 100644 index 3015f7a..0000000 --- a/services/Visibility.qml +++ /dev/null @@ -1,16 +0,0 @@ -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 new file mode 100644 index 0000000..c012668 --- /dev/null +++ b/styled/Clickable.qml @@ -0,0 +1,26 @@ +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 new file mode 100644 index 0000000..2c19f55 --- /dev/null +++ b/styled/Icon.qml @@ -0,0 +1,21 @@ +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 new file mode 100644 index 0000000..3d78058 --- /dev/null +++ b/styled/StyledLabel.qml @@ -0,0 +1,8 @@ +import QtQuick +import "../config/" + +Rectangle { + color: Theme.palette.base100 + + radius: Dimensions.radius +} diff --git a/styled/StyledText.qml b/styled/StyledText.qml new file mode 100644 index 0000000..d2fc577 --- /dev/null +++ b/styled/StyledText.qml @@ -0,0 +1,7 @@ +import QtQuick +import "root:config" + +Text { + color: Theme.palette.basecontent + font.family: Theme.fontFamily +} diff --git a/widgets/StyledWindow.qml b/styled/StyledWindow.qml similarity index 100% rename from widgets/StyledWindow.qml rename to styled/StyledWindow.qml diff --git a/widgets/StyledPopupWindow.qml b/widgets/StyledPopupWindow.qml index 4b7ed4f..924001a 100644 --- a/widgets/StyledPopupWindow.qml +++ b/widgets/StyledPopupWindow.qml @@ -1,4 +1,3 @@ -import qs.services import QtQuick import Quickshell import Quickshell.Widgets @@ -10,15 +9,10 @@ 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 {