Compare commits

..

No commits in common. "49ec4d8502065b29fc827520327bc215a87071de" and "9873324823bd4a36fe57f2f0218476abbdd52bac" have entirely different histories.

6 changed files with 96 additions and 96 deletions

View file

@ -10,7 +10,7 @@ import Quickshell.Widgets
StyledLabel { StyledLabel {
id: root id: root
required property BluetoothDevice modelData property BluetoothDevice device
RowLayout { RowLayout {
id: row id: row
@ -18,20 +18,20 @@ StyledLabel {
spacing: 8 spacing: 8
Loader { Loader {
active: root.modelData?.icon != undefined active: root.device?.icon != undefined
sourceComponent: IconImage { sourceComponent: IconImage {
implicitSize: 22 implicitSize: 22
source: Quickshell.iconPath(root.modelData.icon, "device-support-unknown-symbolic") source: Quickshell.iconPath(root.device.icon, "device-support-unknown-symbolic")
} }
} }
StyledText { StyledText {
text: root.modelData.deviceName text: root.device.deviceName
} }
StyledButton { StyledButton {
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
hoverEnabled: !root.modelData.pairing hoverEnabled: !root.device.pairing
color: containsMouse ? Theme.palette.primary : Theme.palette.base200 color: containsMouse ? Theme.palette.primary : Theme.palette.base200
content: StyledText { content: StyledText {
text: 'Pair' text: 'Pair'
@ -41,8 +41,8 @@ StyledLabel {
if (!hoverEnabled) { if (!hoverEnabled) {
return; return;
} }
root.modelData.trusted = true; root.device.trusted = true;
root.modelData.pair(); root.device.pair();
} }
} }
} }

View file

@ -1,12 +1,11 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import qs.config import qs.config
import qs.services
import qs.widgets import qs.widgets
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Widgets import Quickshell.Widgets
StyledPopupWindow { StyledPopupWindow {
@ -30,8 +29,7 @@ StyledPopupWindow {
} }
Switch { Switch {
checkable: !!Bluetooth.defaultAdapter checked: Bluetooth.defaultAdapter.enabled
checked: Bluetooth.defaultAdapter?.enabled ?? false
onClicked: Bluetooth.defaultAdapter.enabled = checked onClicked: Bluetooth.defaultAdapter.enabled = checked
} }
} }
@ -43,8 +41,7 @@ StyledPopupWindow {
} }
Switch { Switch {
checkable: !!Bluetooth.defaultAdapter checked: Bluetooth.defaultAdapter.discovering
checked: Bluetooth.defaultAdapter?.discovering ?? false
onClicked: Bluetooth.defaultAdapter.discovering = checked onClicked: Bluetooth.defaultAdapter.discovering = checked
} }
} }
@ -66,28 +63,25 @@ StyledPopupWindow {
text: "Connected Devices" text: "Connected Devices"
} }
StyledListView { ColumnLayout {
id: list1 Loader {
Layout.fillWidth: true active: Bluetooth.connectedDevices.length == 0
spacing: 8
implicitHeight: 20 + Math.min(40 * count, 160)
header: Loader {
active: list1.count == 0
sourceComponent: Loader {
active: list1.count == 0
sourceComponent: StyledText { sourceComponent: StyledText {
font.italic: true font.italic: true
text: "No devices connected..." text: "No devices connected..."
} }
} }
Repeater {
model: Bluetooth.connectedDevices
delegate: Loader {
id: connectedDeviceLoader
required property var modelData
Layout.fillWidth: true
active: modelData != null
sourceComponent: ConnectedDevice {
device: connectedDeviceLoader.modelData
} }
clip: true
model: ScriptModel {
values: Bluetooth.devices.values.filter(device => device.state == BluetoothDeviceState.Connected)
} }
delegate: ConnectedDevice {
anchors.left: parent.left
anchors.right: parent.right
} }
} }
@ -98,25 +92,25 @@ StyledPopupWindow {
text: "Paired Devices" text: "Paired Devices"
} }
StyledListView { ColumnLayout {
id: list2 Loader {
Layout.fillWidth: true active: Bluetooth.availableDevices.length == 0
spacing: 8
implicitHeight: 20 + Math.min(40 * count, 160)
header: Loader {
active: list2.count == 0
sourceComponent: StyledText { sourceComponent: StyledText {
font.italic: true font.italic: true
text: "No paired devices..." text: "No paired devices..."
} }
} }
clip: true Repeater {
model: ScriptModel { model: Bluetooth.pairedDevices
values: Bluetooth.defaultAdapter.devices.values.filter(device => device.bonded && device.state == BluetoothDeviceState.Disconnected) delegate: Loader {
id: pairedDeviceLoader
required property var modelData
Layout.fillWidth: true
active: modelData != null
sourceComponent: PairedDevice {
device: pairedDeviceLoader.modelData
}
} }
delegate: PairedDevice {
anchors.left: parent.left
anchors.right: parent.right
} }
} }
@ -127,25 +121,25 @@ StyledPopupWindow {
text: "Available Devices" text: "Available Devices"
} }
StyledListView { ColumnLayout {
id: list3 Loader {
Layout.fillWidth: true active: Bluetooth.availableDevices.length == 0
spacing: 8
clip: true
implicitHeight: 20 + Math.min(40 * count, 160)
header: Loader {
active: list3.count == 0
sourceComponent: StyledText { sourceComponent: StyledText {
font.italic: true font.italic: true
text: Bluetooth.defaultAdapter.discovering ? "No devices found..." : "Scan to find devices..." text: Bluetooth.defaultAdapter.discovering ? "No devices found..." : "Scan to find devices..."
} }
} }
model: ScriptModel { Repeater {
values: Bluetooth.devices.values.filter(device => !device.bonded && device.deviceName != "") model: Bluetooth.availableDevices
} delegate: Loader {
delegate: AvailableDevice { id: availableDeviceLoader
anchors.left: parent.left required property var modelData
anchors.right: parent.right Layout.fillWidth: true
active: modelData != null
sourceComponent: AvailableDevice {
device: availableDeviceLoader.modelData
}
}
} }
} }
} }

View file

@ -11,7 +11,7 @@ import Quickshell.Widgets
StyledLabel { StyledLabel {
id: root id: root
required property BluetoothDevice modelData required property BluetoothDevice device
RowLayout { RowLayout {
id: row id: row
@ -19,19 +19,19 @@ StyledLabel {
spacing: 8 spacing: 8
Loader { Loader {
active: root.modelData?.icon != undefined active: root.device?.icon != undefined
sourceComponent: IconImage { sourceComponent: IconImage {
implicitSize: 22 implicitSize: 22
source: Quickshell.iconPath(root.modelData.icon, "device-support-unknown-symbolic") source: Quickshell.iconPath(root.device.icon, "device-support-unknown-symbolic")
} }
} }
StyledText { StyledText {
text: root.modelData.deviceName text: root.device.deviceName
} }
Loader { Loader {
active: root.modelData.batteryAvailable active: root.device.batteryAvailable
sourceComponent: RowLayout { sourceComponent: RowLayout {
StyledText { StyledText {
id: icon id: icon
@ -42,11 +42,11 @@ StyledLabel {
states: [ states: [
State { State {
name: "full" name: "full"
when: root.modelData.battery > 0.66 when: root.device.battery > 0.66
}, },
State { State {
name: "medium" name: "medium"
when: root.modelData.battery > 0.33 when: root.device.battery > 0.33
PropertyChanges { PropertyChanges {
icon { icon {
text: Icons.batteryFull text: Icons.batteryFull
@ -55,7 +55,7 @@ StyledLabel {
}, },
State { State {
name: "low" name: "low"
when: root.modelData.battery > 0.10 when: root.device.battery > 0.10
PropertyChanges { PropertyChanges {
icon { icon {
text: Icons.batteryFull text: Icons.batteryFull
@ -64,7 +64,7 @@ StyledLabel {
}, },
State { State {
name: "critical" name: "critical"
when: root.modelData.battery > 0.10 when: root.device.battery > 0.10
PropertyChanges { PropertyChanges {
icon { icon {
text: Icons.batteryWarning text: Icons.batteryWarning
@ -85,10 +85,10 @@ StyledLabel {
font.pixelSize: 12 font.pixelSize: 12
} }
onClicked: { onClicked: {
if (root.modelData.state != BluetoothDeviceState.Connected) { if (root.device.state != BluetoothDeviceState.Connected) {
return; return;
} }
root.modelData.connected = false; root.device.connected = false;
} }
} }
} }

View file

@ -10,7 +10,7 @@ import Quickshell.Widgets
StyledLabel { StyledLabel {
id: root id: root
required property BluetoothDevice modelData required property BluetoothDevice device
RowLayout { RowLayout {
id: row id: row
@ -18,21 +18,21 @@ StyledLabel {
spacing: 8 spacing: 8
Loader { Loader {
active: root.modelData?.icon != undefined active: root.device?.icon != undefined
sourceComponent: IconImage { sourceComponent: IconImage {
implicitSize: 22 implicitSize: 22
source: Quickshell.iconPath(root.modelData.icon, "device-support-unknown-symbolic") source: Quickshell.iconPath(root.device.icon, "device-support-unknown-symbolic")
} }
} }
StyledText { StyledText {
text: root.modelData.deviceName text: root.device.deviceName
} }
RowLayout { RowLayout {
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
StyledButton { StyledButton {
hoverEnabled: root.modelData.state == BluetoothDeviceState.Disconnected hoverEnabled: root.device.state == BluetoothDeviceState.Disconnected
color: containsMouse ? Theme.palette.primary : Theme.palette.base200 color: containsMouse ? Theme.palette.primary : Theme.palette.base200
content: StyledText { content: StyledText {
text: 'Connect' text: 'Connect'
@ -42,12 +42,12 @@ StyledLabel {
if (!hoverEnabled) { if (!hoverEnabled) {
return; return;
} }
root.modelData.connect(); root.device.connect();
} }
} }
StyledButton { StyledButton {
hoverEnabled: root.modelData.state == BluetoothDeviceState.Disconnected hoverEnabled: root.device.state == BluetoothDeviceState.Disconnected
color: containsMouse ? Theme.palette.error : Theme.palette.base200 color: containsMouse ? Theme.palette.error : Theme.palette.base200
content: StyledText { content: StyledText {
text: 'Unpair' text: 'Unpair'
@ -57,7 +57,7 @@ StyledLabel {
if (!hoverEnabled) { if (!hoverEnabled) {
return; return;
} }
root.modelData.forget(); root.device.forget();
} }
} }
} }

22
services/Bluetooth.qml Normal file
View file

@ -0,0 +1,22 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Bluetooth
Singleton {
id: root
property BluetoothAdapter defaultAdapter: Bluetooth.defaultAdapter
property list<BluetoothDevice> connectedDevices: defaultAdapter?.devices.values.filter(device => device.state == BluetoothDeviceState.Connected)
property list<BluetoothDevice> pairedDevices: defaultAdapter?.devices.values.filter(device => device.bonded && device.state == BluetoothDeviceState.Disconnected)
property list<BluetoothDevice> availableDevices: defaultAdapter?.devices.values.filter(device => !device.bonded && device.deviceName != "")
function isConnected(BluetoothDevice: device) {
return device.state == BluetoothDeviceState.Connected;
}
function isConnecting(BluetoothDevice: device) {
return device.state == BluetoothDeviceState.Connecting;
}
}

View file

@ -1,16 +0,0 @@
import QtQuick
ListView {
id: root
maximumFlickVelocity: 3000
rebound: Transition {
NumberAnimation {
properties: "x,y"
duration: 400
easing.type: Easing.BezierSpline
easing.bezierCurve: [0.2, 0, 0, 1, 1, 1]
}
}
}