qs bluetooth

This commit is contained in:
outfoxxed 2025-07-24 18:51:24 -07:00
parent c6699a5b52
commit 6c73e52f6d
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
16 changed files with 277 additions and 3 deletions

View file

@ -0,0 +1,129 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import Quickshell.Widgets
import Quickshell.Bluetooth
import qs
import qs.bar
ClickableIcon {
id: root
required property var bar;
readonly property BluetoothAdapter adapter: Bluetooth.defaultAdapter
readonly property bool connected: adapter.devices.values.some(device => device.connected)
property bool showMenu: false
onPressed: event => {
event.accepted = true;
if (event.button === Qt.RightButton) {
showMenu = !showMenu;
}
}
onClicked: event => {
if (event.button === Qt.LeftButton) {
adapter.enabled = !adapter.enabled;
}
}
showPressed: showMenu || (pressedButtons & ~Qt.RightButton)
implicitHeight: width
fillWindowWidth: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
image: adapter.enabled
? (connected ? "root:/icons/bluetooth-connected.svg" : "root:/icons/bluetooth.svg")
: "root:/icons/bluetooth-slash.svg"
property var tooltip: TooltipItem {
tooltip: bar.tooltip
owner: root
show: root.containsMouse
Label { text: "Bluetooth" }
}
property var rightclickMenu: TooltipItem {
id: rightclickMenu
tooltip: bar.tooltip
owner: root
isMenu: true
show: root.showMenu
onClose: root.showMenu = false
Loader {
width: 400
active: root.showMenu || rightclickMenu.visible
sourceComponent: Column {
spacing: 5
move: Transition {
SmoothedAnimation { property: "y"; velocity: 350 }
}
RowLayout {
width: parent.width
ClickableIcon {
image: root.image
implicitHeight: 40
implicitWidth: height
onClicked: root.adapter.enabled = !root.adapter.enabled
}
Label {
text: `Bluetooth (${root.adapter.adapterId})`
}
Item { Layout.fillWidth: true }
ClickableIcon {
image: root.adapter.enabled ? "root:/icons/bluetooth-slash.svg" : "root:/icons/bluetooth.svg"
implicitHeight: 24
implicitWidth: height
onClicked: root.adapter.enabled = !root.adapter.enabled
}
ActivityButton {
image: "root:/icons/binoculars.svg"
implicitHeight: 24
implicitWidth: height
onClicked: root.adapter.discovering = !root.adapter.discovering
showAction: root.adapter.discovering
Layout.rightMargin: 4
}
}
Rectangle {
width: parent.width
implicitHeight: 1
visible: linkTracker.linkGroups.length > 0
color: ShellGlobals.colors.separator
}
Repeater {
model: ScriptModel {
values: [...root.adapter.devices.values].sort((a, b) => {
if (a.connected && !b.connected) return -1;
if (b.connected && !a.connected) return 1;
if (a.bonded && !b.bonded) return -1;
if (b.bonded && !a.bonded) return 1;
return b.name - a.name;
})
}
delegate: BluetoothDeviceDelegate {
required property BluetoothDevice modelData
device: modelData
width: parent.width
}
}
}
}
}
}

View file

@ -0,0 +1,88 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import Quickshell.Widgets
import Quickshell.Bluetooth
import qs
import qs.bar
WrapperMouseArea {
id: root
required property BluetoothDevice device
property bool menuOpen: false
readonly property bool showBg: false//pairingContext.attentionRequested //device.connected//menuOpen //|| containsMouse
hoverEnabled: true
onClicked: menuOpen = !menuOpen
WrapperRectangle {
color: root.showBg ? ShellGlobals.colors.widget : "transparent"
border.width: 1
border.color: root.showBg ? ShellGlobals.colors.widgetOutline : "transparent"
radius: 4
rightMargin: 2
ColumnLayout {
RowLayout {
ClickableIcon {
image: Quickshell.iconPath(root.device.icon)
implicitHeight: 40
implicitWidth: height
}
Label {
text: root.device.name
}
Item { Layout.fillWidth: true }
ActivityButton {
image: root.device.connected ? "root:/icons/plugs-connected.svg" : "root:/icons/plugs.svg"
implicitHeight: 24
implicitWidth: height
showAction: root.device.pairing || root.device.state === BluetoothDeviceState.Connecting || root.device.state === BluetoothDeviceState.Disconnecting
onClicked: {
if (showAction) return;
else if (root.device.connected) root.device.disconnect();
else if (root.device.paired) root.device.connect();
else root.device.pair();
}
}
ClickableIcon {
image: "root:/icons/trash.svg"
implicitHeight: 24
implicitWidth: height
visible: root.device.bonded
onClicked: root.device.forget()
}
}
/*RowLayout {
Layout.margins: 3
Layout.topMargin: 0
visible: root.showBg
BluetoothPairingContext {
id: pairingContext
device: root.device
}
Label {
text: `Pairing Code: ${pairingContext.pairingCode}`
}
Button {
text: "Accept"
onClicked: pairingContext.confirmCode(true)
}
Button {
text: "Reject"
onClicked: pairingContext.confirmCode(false)
}
}*/
}
}
}

View file

@ -0,0 +1 @@
import Quickshell

View file

@ -0,0 +1,23 @@
import QtQuick
import QtQuick.Layouts
import qs.bar
BarWidgetInner {
id: root
required property var bar;
implicitHeight: column.implicitHeight + 10
ColumnLayout {
id: column
anchors {
fill: parent
margins: 5
}
Bluetooth {
Layout.fillWidth: true
bar: root.bar
}
}
}