Show discovered devices and shrink bluetooth header buttons

- Scan and Manage are now small icon-only buttons in the header beside
  the On/Off pill, with hover tooltips via the new PillButton.tooltipText
  prop (backed by QtQuick.Controls ToolTip).
- New discoveredDevices list pulls everything in Bluetooth.devices that
  isn't paired/connected/bonded/trusted. While scanning, those appear
  under a 'Discovered' header. Click pairs and connects.
- Empty-state text only shows when there are no known and no
  discovered devices, otherwise it would push down real entries.
This commit is contained in:
Ryan Hughes
2026-05-14 02:21:48 -04:00
parent fbe45d517b
commit 53f9899d5a
2 changed files with 76 additions and 35 deletions
@@ -1,10 +1,12 @@
import QtQuick import QtQuick
import QtQuick.Controls
Rectangle { Rectangle {
id: root id: root
property string text: "" property string text: ""
property string iconText: "" property string iconText: ""
property string tooltipText: ""
property color foreground: "#cacccc" property color foreground: "#cacccc"
property color background: "transparent" property color background: "transparent"
property color hoverBackground: Qt.rgba(foreground.r, foreground.g, foreground.b, 0.12) property color hoverBackground: Qt.rgba(foreground.r, foreground.g, foreground.b, 0.12)
@@ -17,6 +19,10 @@ Rectangle {
property bool active: false property bool active: false
property color activeBackground: Qt.rgba(foreground.r, foreground.g, foreground.b, 0.18) property color activeBackground: Qt.rgba(foreground.r, foreground.g, foreground.b, 0.18)
ToolTip.visible: tooltipText !== "" && mouseArea.containsMouse
ToolTip.text: tooltipText
ToolTip.delay: 400
signal clicked() signal clicked()
signal rightClicked() signal rightClicked()
@@ -92,48 +92,49 @@ Item {
font.bold: true font.bold: true
} }
Common.PillButton { Row {
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
iconText: root.adapter && root.adapter.enabled ? "󰂯" : "󰂲" spacing: 4
text: root.adapter && root.adapter.enabled ? "On" : "Off"
foreground: root.bar.foreground
horizontalPadding: 10
verticalPadding: 4
active: root.adapter && root.adapter.enabled
onClicked: if (root.adapter) root.adapter.enabled = !root.adapter.enabled
}
}
// Action row: scan toggle and TUI launcher. Common.PillButton {
Row { iconText: "󰂳"
width: parent.width tooltipText: !root.adapter ? "" : !root.adapter.enabled ? "Bluetooth is off"
spacing: 8 : root.adapter.discovering ? "Stop scanning" : "Scan for devices"
foreground: root.bar.foreground
horizontalPadding: 6
verticalPadding: 4
iconSize: 14
enabled: root.adapter !== null && root.adapter.enabled
opacity: enabled ? 1 : 0.4
active: root.adapter && root.adapter.discovering
onClicked: if (root.adapter) root.adapter.discovering = !root.adapter.discovering
}
Common.PillButton { Common.PillButton {
width: (parent.width - parent.spacing) / 2 iconText: "󱁤"
iconText: "󰂳" tooltipText: "Open Impala (TUI)"
text: root.adapter && root.adapter.discovering ? "Scanning…" : "Scan" foreground: root.bar.foreground
foreground: root.bar.foreground horizontalPadding: 6
horizontalPadding: 10 verticalPadding: 4
verticalPadding: 6 iconSize: 14
enabled: root.adapter !== null && root.adapter.enabled onClicked: { root.bar.run("omarchy-launch-bluetooth"); root.popupOpen = false }
opacity: enabled ? 1 : 0.4 }
active: root.adapter && root.adapter.discovering
onClicked: if (root.adapter) root.adapter.discovering = !root.adapter.discovering
}
Common.PillButton { Common.PillButton {
width: (parent.width - parent.spacing) / 2 iconText: root.adapter && root.adapter.enabled ? "󰂯" : "󰂲"
iconText: "󱁤" text: root.adapter && root.adapter.enabled ? "On" : "Off"
text: "Manage…" tooltipText: root.adapter && root.adapter.enabled ? "Turn Bluetooth off" : "Turn Bluetooth on"
foreground: root.bar.foreground foreground: root.bar.foreground
horizontalPadding: 10 horizontalPadding: 10
verticalPadding: 6 verticalPadding: 4
onClicked: { root.bar.run("omarchy-launch-bluetooth"); root.popupOpen = false } active: root.adapter && root.adapter.enabled
onClicked: if (root.adapter) root.adapter.enabled = !root.adapter.enabled
}
} }
} }
// Paired / known devices.
Repeater { Repeater {
model: root.knownDevices model: root.knownDevices
@@ -147,6 +148,8 @@ Item {
if (modelData && modelData.batteryAvailable) label += " " + Math.round(modelData.battery * 100) + "%" if (modelData && modelData.batteryAvailable) label += " " + Math.round(modelData.battery * 100) + "%"
return label return label
} }
tooltipText: modelData && modelData.connected ? "Click to disconnect · right-click to forget"
: "Click to connect · right-click to forget"
foreground: root.bar.foreground foreground: root.bar.foreground
horizontalPadding: 10 horizontalPadding: 10
verticalPadding: 6 verticalPadding: 6
@@ -161,12 +164,44 @@ Item {
} }
} }
// Discovered (unpaired) devices, only shown while scanning.
Text {
visible: root.adapter && root.adapter.discovering && root.discoveredDevices.length > 0
text: "Discovered"
color: Qt.darker(root.bar.foreground, 1.4)
font.family: root.bar.fontFamily
font.pixelSize: 10
font.bold: true
}
Repeater {
model: root.adapter && root.adapter.discovering ? root.discoveredDevices : []
Common.PillButton {
required property var modelData
width: parent.width
iconText: "󰂯"
text: modelData ? (modelData.deviceName || modelData.name || modelData.address || "Unknown") : ""
tooltipText: "Click to pair and connect"
foreground: Qt.darker(root.bar.foreground, 1.2)
horizontalPadding: 10
verticalPadding: 6
onClicked: {
if (!modelData) return
modelData.pair()
}
}
}
Text { Text {
visible: root.knownDevices.length === 0 visible: root.knownDevices.length === 0
&& (!root.adapter || !root.adapter.discovering || root.discoveredDevices.length === 0)
text: !root.adapter ? "No Bluetooth adapter" text: !root.adapter ? "No Bluetooth adapter"
: !root.adapter.enabled ? "Turn Bluetooth on to scan" : !root.adapter.enabled ? "Turn Bluetooth on to scan"
: root.adapter.discovering ? "Scanning for devices…" : root.adapter.discovering ? "Scanning for devices…"
: "No paired devices. Hit Scan to find new ones." : "No paired devices. Tap the scan icon to find new ones."
color: Qt.darker(root.bar.foreground, 1.5) color: Qt.darker(root.bar.foreground, 1.5)
font.family: root.bar.fontFamily font.family: root.bar.fontFamily
font.pixelSize: 11 font.pixelSize: 11