add available devices and fix formatting/icons

This commit is contained in:
Benjamin Palko 2025-07-29 16:28:47 -04:00
parent 622604ad08
commit 0bbb032823
6 changed files with 105 additions and 34 deletions

View file

@ -0,0 +1,49 @@
pragma ComponentBehavior: Bound
import qs.config
import qs.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Widgets
StyledLabel {
id: root
required property BluetoothDevice modelData
RowLayout {
id: row
spacing: 8
Loader {
active: root.modelData?.icon != undefined
sourceComponent: IconImage {
implicitSize: 22
source: Quickshell.iconPath(root.modelData.icon, "device-support-unknown-symbolic")
}
}
StyledText {
text: root.modelData.deviceName
}
StyledButton {
Layout.alignment: Qt.AlignRight
hoverEnabled: !root.modelData.pairing
color: containsMouse ? Theme.palette.primary : Theme.palette.base200
content: StyledText {
text: 'Pair'
font.pixelSize: 12
}
onClicked: {
if (!hoverEnabled) {
return;
}
root.modelData.trusted = true;
root.modelData.pair();
}
}
}
}

View file

@ -22,17 +22,31 @@ StyledPopupWindow {
color: Theme.palette.base200 color: Theme.palette.base200
radius: 8 radius: 8
Layout.fillWidth: true Layout.fillWidth: true
RowLayout {
RowLayout { RowLayout {
StyledText { StyledText {
text: "Bluetooth" text: "Enabled"
} }
Switch { Switch {
Layout.alignment: Qt.AlignRight
checked: Bluetooth.defaultAdapter.enabled checked: Bluetooth.defaultAdapter.enabled
onClicked: Bluetooth.defaultAdapter.enabled = checked onClicked: Bluetooth.defaultAdapter.enabled = checked
} }
} }
RowLayout {
Layout.alignment: Qt.AlignRight
StyledText {
text: "Scan"
}
Switch {
checked: Bluetooth.defaultAdapter.discovering
onClicked: Bluetooth.defaultAdapter.discovering = true;
}
}
}
} }
WrapperRectangle { WrapperRectangle {
@ -76,10 +90,12 @@ StyledPopupWindow {
text: "Available Devices" text: "Available Devices"
} }
DeviceList { ColumnLayout {
devices: Bluetooth.availableDevices Repeater {
onDeviceActivated: device => { model: Bluetooth.availableDevices
device.pair(); delegate: AvailableDevice {
Layout.fillWidth: true
}
} }
} }
} }

View file

@ -10,7 +10,7 @@ import Quickshell.Bluetooth
import Quickshell.Widgets import Quickshell.Widgets
StyledLabel { StyledLabel {
id: device id: root
required property BluetoothDevice modelData required property BluetoothDevice modelData
RowLayout { RowLayout {
@ -19,19 +19,19 @@ StyledLabel {
spacing: 8 spacing: 8
Loader { Loader {
active: modelData.icon != undefined active: root.modelData?.icon != undefined
sourceComponent: IconImage { sourceComponent: IconImage {
implicitSize: 18 implicitSize: 22
source: Quickshell.iconPath(modelData.icon) source: Quickshell.iconPath(root.modelData.icon, "device-support-unknown-symbolic")
} }
} }
StyledText { StyledText {
text: device.modelData.deviceName text: root.modelData.deviceName
} }
Loader { Loader {
active: device.modelData.batteryAvailable active: root.modelData.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: device.modelData.battery > 0.66 when: root.modelData.battery > 0.66
}, },
State { State {
name: "medium" name: "medium"
when: device.modelData.battery > 0.33 when: root.modelData.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: device.modelData.battery > 0.10 when: root.modelData.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: device.modelData.battery > 0.10 when: root.modelData.battery > 0.10
PropertyChanges { PropertyChanges {
icon { icon {
text: Icons.batteryWarning text: Icons.batteryWarning
@ -82,12 +82,13 @@ StyledLabel {
color: containsMouse ? Theme.palette.error : Theme.palette.base200 color: containsMouse ? Theme.palette.error : Theme.palette.base200
content: StyledText { content: StyledText {
text: 'Disconnect' text: 'Disconnect'
font.pixelSize: 12
} }
onClicked: { onClicked: {
if (modelData.state != BluetoothDeviceState.Connected) { if (root.modelData.state != BluetoothDeviceState.Connected) {
return; return;
} }
modelData.disconnect(); root.modelData.connected = false;
} }
} }
} }

View file

@ -9,7 +9,7 @@ import Quickshell.Bluetooth
import Quickshell.Widgets import Quickshell.Widgets
StyledLabel { StyledLabel {
id: device id: root
required property BluetoothDevice modelData required property BluetoothDevice modelData
RowLayout { RowLayout {
@ -18,44 +18,46 @@ StyledLabel {
spacing: 8 spacing: 8
Loader { Loader {
active: modelData.icon != undefined active: root.modelData?.icon != undefined
sourceComponent: IconImage { sourceComponent: IconImage {
implicitSize: 18 implicitSize: 22
source: Quickshell.iconPath(device.modelData.icon) source: Quickshell.iconPath(root.modelData.icon, "device-support-unknown-symbolic")
} }
} }
StyledText { StyledText {
text: device.modelData.deviceName text: root.modelData.deviceName
} }
RowLayout { RowLayout {
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
StyledButton { StyledButton {
hoverEnabled: device.modelData.state == BluetoothDeviceState.Disconnected hoverEnabled: root.modelData.state == BluetoothDeviceState.Disconnected
color: containsMouse ? Theme.palette.info : Theme.palette.base200 color: containsMouse ? Theme.palette.primary : Theme.palette.base200
content: StyledText { content: StyledText {
text: 'Connect' text: 'Connect'
font.pixelSize: 12
} }
onClicked: { onClicked: {
if (!hoverEnabled) { if (!hoverEnabled) {
return; return;
} }
device.modelData.connect(); root.modelData.connect();
} }
} }
StyledButton { StyledButton {
hoverEnabled: device.modelData.state == BluetoothDeviceState.Disconnected hoverEnabled: root.modelData.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'
font.pixelSize: 12
} }
onClicked: { onClicked: {
if (!hoverEnabled) { if (!hoverEnabled) {
return; return;
} }
device.modelData.forget(); root.modelData.forget();
} }
} }
} }

View file

@ -1,5 +1,6 @@
pragma Singleton pragma Singleton
import QtQuick
import Quickshell import Quickshell
import Quickshell.Bluetooth import Quickshell.Bluetooth
@ -7,9 +8,9 @@ Singleton {
id: root id: root
property BluetoothAdapter defaultAdapter: Bluetooth.defaultAdapter property BluetoothAdapter defaultAdapter: Bluetooth.defaultAdapter
property list<BluetoothDevice> connectedDevices: defaultAdapter.devices.values.filter(device => device.connected) property list<BluetoothDevice> connectedDevices: defaultAdapter?.devices.values.filter(device => device.state == BluetoothDeviceState.Connected)
property list<BluetoothDevice> pairedDevices: defaultAdapter.devices.values.filter(device => device.paired && !device.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.paired) property list<BluetoothDevice> availableDevices: defaultAdapter?.devices.values.filter(device => !device.bonded && device.deviceName != "")
function isConnected(BluetoothDevice: device) { function isConnected(BluetoothDevice: device) {
return device.state == BluetoothDeviceState.Connected; return device.state == BluetoothDeviceState.Connected;

View file

@ -1,3 +1,5 @@
//@ pragma IconTheme WhiteSur-dark
import Quickshell import Quickshell
import "modules" import "modules"
import "modules/bar" import "modules/bar"