summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-07-26 19:41:56 +1000
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-07-26 19:41:56 +1000
commitbe6b19ad21f13404fd70d2be6bf3ac16d786f3a8 (patch)
tree51d78316ac4d6cb2129c8a56e034ce8962b63fb6 /modules
parent[CI] chore: update flake (diff)
downloadcaelestia-shell-be6b19ad21f13404fd70d2be6bf3ac16d786f3a8.tar.gz
caelestia-shell-be6b19ad21f13404fd70d2be6bf3ac16d786f3a8.tar.bz2
caelestia-shell-be6b19ad21f13404fd70d2be6bf3ac16d786f3a8.zip
dcontent: add bt pane
Diffstat (limited to 'modules')
-rw-r--r--modules/bar/popouts/Bluetooth.qml2
-rw-r--r--modules/detachedcontent/Panes.qml100
-rw-r--r--modules/detachedcontent/bluetooth/BtPane.qml42
-rw-r--r--modules/detachedcontent/bluetooth/Details.qml8
-rw-r--r--modules/detachedcontent/bluetooth/DeviceList.qml200
5 files changed, 280 insertions, 72 deletions
diff --git a/modules/bar/popouts/Bluetooth.qml b/modules/bar/popouts/Bluetooth.qml
index 56dd4a4..97cb01e 100644
--- a/modules/bar/popouts/Bluetooth.qml
+++ b/modules/bar/popouts/Bluetooth.qml
@@ -67,7 +67,7 @@ ColumnLayout {
id: device
required property BluetoothDevice modelData
- readonly property bool loading: device.modelData.state === BluetoothDeviceState.Connecting || device.modelData.state === BluetoothDeviceState.Disconnecting
+ readonly property bool loading: modelData.state === BluetoothDeviceState.Connecting || modelData.state === BluetoothDeviceState.Disconnecting
Layout.fillWidth: true
Layout.rightMargin: Appearance.padding.small
diff --git a/modules/detachedcontent/Panes.qml b/modules/detachedcontent/Panes.qml
index b0c8440..b9f53ae9 100644
--- a/modules/detachedcontent/Panes.qml
+++ b/modules/detachedcontent/Panes.qml
@@ -1,12 +1,12 @@
pragma ComponentBehavior: Bound
+import "bluetooth"
import qs.widgets
import qs.services
import qs.config
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
-import QtQuick.Effects
ClippingRectangle {
id: root
@@ -24,23 +24,21 @@ ClippingRectangle {
y: -root.session.activeIndex * root.height
Pane {
- StyledText {
- anchors.centerIn: parent
- text: qsTr("Work in progress")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.extraLarge
- font.weight: 500
+ index: 0
+ sourceComponent: Item {
+ StyledText {
+ anchors.centerIn: parent
+ text: qsTr("Work in progress")
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.extraLarge
+ font.weight: 500
+ }
}
}
Pane {
- StyledText {
- anchors.centerIn: parent
- text: qsTr("Work in progress")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.extraLarge
- font.weight: 500
- }
+ index: 1
+ sourceComponent: BtPane {}
}
Behavior on y {
@@ -52,71 +50,31 @@ ClippingRectangle {
}
}
- StyledRect {
- anchors.fill: parent
- color: Colours.palette.m3surfaceContainer
-
- layer.enabled: true
- layer.effect: MultiEffect {
- maskSource: mask
- maskEnabled: true
- maskInverted: true
- maskThresholdMin: 0.5
- maskSpreadAtMin: 1
- }
- }
-
- Item {
- id: mask
-
- anchors.fill: parent
- layer.enabled: true
- visible: false
-
- Rectangle {
- anchors.fill: parent
- anchors.margins: Appearance.padding.normal
- anchors.leftMargin: 0
- radius: Appearance.rounding.small
- }
+ InnerBorder {
+ leftThickness: 0
}
- component Pane: Loader {
+ component Pane: Item {
id: pane
- default property Item child
-
- asynchronous: true
- active: {
- const ly = -layout.y;
- const ty = layout.children.indexOf(this) * root.height;
- return ly + root.height > ty && ly < ty + root.height;
- }
-
- sourceComponent: Item {
- implicitWidth: root.width
- implicitHeight: root.height
+ required property int index
+ property alias sourceComponent: loader.sourceComponent
- Item {
- anchors.fill: parent
- anchors.margins: Appearance.padding.normal
- anchors.leftMargin: 0
+ implicitWidth: root.width
+ implicitHeight: root.height
- children: [pane.child]
- }
+ Loader {
+ id: loader
- StyledRect {
- anchors.fill: parent
- color: Colours.palette.m3surfaceContainer
+ anchors.fill: parent
+ asynchronous: true
+ active: {
+ if (root.session.activeIndex === pane.index)
+ return true;
- layer.enabled: true
- layer.effect: MultiEffect {
- maskSource: mask
- maskEnabled: true
- maskInverted: true
- maskThresholdMin: 0.5
- maskSpreadAtMin: 1
- }
+ const ly = -layout.y;
+ const ty = pane.index * root.height;
+ return ly + root.height > ty && ly < ty + root.height;
}
}
}
diff --git a/modules/detachedcontent/bluetooth/BtPane.qml b/modules/detachedcontent/bluetooth/BtPane.qml
new file mode 100644
index 0000000..750166b
--- /dev/null
+++ b/modules/detachedcontent/bluetooth/BtPane.qml
@@ -0,0 +1,42 @@
+pragma ComponentBehavior: Bound
+
+import qs.widgets
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+RowLayout {
+ anchors.fill: parent
+
+ spacing: 0
+
+ Item {
+ Layout.preferredWidth: Math.floor(parent.width / 3)
+ Layout.fillHeight: true
+
+ DeviceList {
+ anchors.margins: Appearance.padding.large + Appearance.padding.normal
+ anchors.leftMargin: Appearance.padding.large
+ anchors.rightMargin: Appearance.padding.large + Appearance.padding.normal / 2
+ }
+
+ InnerBorder {
+ leftThickness: 0
+ rightThickness: Appearance.padding.normal / 2
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Details {
+ anchors.margins: Appearance.padding.normal
+ anchors.leftMargin: Appearance.padding.normal / 2
+ }
+
+ InnerBorder {
+ leftThickness: Appearance.padding.normal / 2
+ }
+ }
+}
diff --git a/modules/detachedcontent/bluetooth/Details.qml b/modules/detachedcontent/bluetooth/Details.qml
new file mode 100644
index 0000000..b879195
--- /dev/null
+++ b/modules/detachedcontent/bluetooth/Details.qml
@@ -0,0 +1,8 @@
+import qs.widgets
+import qs.services
+import qs.config
+import Quickshell
+import Quickshell.Bluetooth
+import QtQuick.Layouts
+
+ColumnLayout {}
diff --git a/modules/detachedcontent/bluetooth/DeviceList.qml b/modules/detachedcontent/bluetooth/DeviceList.qml
new file mode 100644
index 0000000..8f77cfd
--- /dev/null
+++ b/modules/detachedcontent/bluetooth/DeviceList.qml
@@ -0,0 +1,200 @@
+import qs.widgets
+import qs.services
+import qs.config
+import qs.utils
+import Quickshell
+import Quickshell.Bluetooth
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+
+ColumnLayout {
+ id: root
+
+ anchors.fill: parent
+ spacing: Appearance.spacing.small
+
+ StyledText {
+ text: qsTr("Settings")
+ font.pointSize: Appearance.font.size.large
+ font.weight: 500
+ }
+
+ StyledText {
+ text: qsTr("General bluetooth settings")
+ color: Colours.palette.m3outline
+ }
+
+ StyledRect {
+ Layout.fillWidth: true
+ implicitHeight: settingsText.implicitHeight + Appearance.padding.normal * 2
+
+ radius: Appearance.rounding.normal
+ color: Colours.palette.m3surfaceContainer
+
+ StateLayer {}
+
+ StyledText {
+ id: settingsText
+
+ anchors.centerIn: parent
+ text: qsTr("Bluetooth settings")
+ }
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.large
+ text: qsTr("Devices")
+ font.pointSize: Appearance.font.size.large
+ font.weight: 500
+ }
+
+ StyledText {
+ text: qsTr("All available bluetooth devices")
+ color: Colours.palette.m3outline
+ }
+
+ StyledListView {
+ model: ScriptModel {
+ values: [...Bluetooth.devices.values].sort((a, b) => (b.connected - a.connected) || (b.paired - a.paired))
+ }
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ clip: true
+
+ ScrollBar.vertical: StyledScrollBar {}
+
+ delegate: StyledRect {
+ id: device
+
+ required property BluetoothDevice modelData
+ readonly property bool loading: modelData.state === BluetoothDeviceState.Connecting || modelData.state === BluetoothDeviceState.Disconnecting
+ readonly property bool connected: modelData.state === BluetoothDeviceState.Connected
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ implicitHeight: deviceInner.implicitHeight + Appearance.padding.normal * 2
+
+ StateLayer {
+ id: stateLayer
+
+ function onClicked(): void {
+ }
+ }
+
+ RowLayout {
+ id: deviceInner
+
+ anchors.fill: parent
+ anchors.margins: Appearance.padding.normal
+ anchors.leftMargin: Appearance.padding.large
+ anchors.rightMargin: Appearance.padding.large
+
+ spacing: Appearance.spacing.normal
+
+ StyledRect {
+ implicitWidth: implicitHeight
+ implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2
+
+ radius: Appearance.rounding.full
+ color: device.connected ? Colours.palette.m3primaryContainer : device.modelData.bonded ? Colours.palette.m3secondaryContainer : Colours.palette.m3surfaceContainerHigh
+
+ StyledRect {
+ anchors.fill: parent
+ radius: parent.radius
+ color: Qt.alpha(device.connected ? Colours.palette.m3onPrimaryContainer : device.modelData.bonded ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface, stateLayer.pressed ? 0.1 : stateLayer.containsMouse ? 0.08 : 0)
+ }
+
+ MaterialIcon {
+ id: icon
+
+ anchors.centerIn: parent
+ text: Icons.getBluetoothIcon(device.modelData.icon)
+ color: device.connected ? Colours.palette.m3onPrimaryContainer : device.modelData.bonded ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
+ font.pointSize: Appearance.font.size.large
+ fill: device.connected ? 1 : 0
+
+ Behavior on fill {
+ Anim {}
+ }
+ }
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+
+ spacing: 0
+
+ StyledText {
+ Layout.fillWidth: true
+ text: device.modelData.name
+ elide: Text.ElideRight
+ }
+
+ StyledText {
+ Layout.fillWidth: true
+ text: device.modelData.address + (device.connected ? qsTr(" (Connected)") : device.modelData.bonded ? qsTr(" (Paired)") : "")
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.small
+ elide: Text.ElideRight
+ }
+ }
+
+ StyledRect {
+ id: connectBtn
+
+ implicitWidth: implicitHeight
+ implicitHeight: connectIcon.implicitHeight + Appearance.padding.small * 2
+
+ radius: Appearance.rounding.full
+ color: device.connected ? Colours.palette.m3primaryContainer : "transparent"
+
+ StyledBusyIndicator {
+ anchors.centerIn: parent
+
+ implicitWidth: implicitHeight
+ implicitHeight: connectIcon.implicitHeight
+
+ running: opacity > 0
+ opacity: device.loading ? 1 : 0
+
+ Behavior on opacity {
+ Anim {}
+ }
+ }
+
+ StateLayer {
+ color: device.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface
+ disabled: device.loading
+
+ function onClicked(): void {
+ device.modelData.connected = !device.modelData.connected;
+ }
+ }
+
+ MaterialIcon {
+ id: connectIcon
+
+ anchors.centerIn: parent
+ animate: true
+ text: device.modelData.connected ? "link_off" : "link"
+ color: device.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface
+
+ opacity: device.loading ? 0 : 1
+
+ Behavior on opacity {
+ Anim {}
+ }
+ }
+ }
+ }
+ }
+ }
+
+ component Anim: NumberAnimation {
+ duration: Appearance.anim.durations.normal
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.anim.curves.standard
+ }
+}