Bluetooth WIP but way more reliable than before
This commit is contained in:
parent
a390af2aae
commit
d2acdd1c19
3 changed files with 371 additions and 593 deletions
|
|
@ -15,18 +15,11 @@ NIconButton {
|
||||||
showBorder: false
|
showBorder: false
|
||||||
visible: bluetoothEnabled
|
visible: bluetoothEnabled
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
Logger.log("Bluetooth", "Component loaded, bluetoothEnabled:", bluetoothEnabled)
|
|
||||||
Logger.log("Bluetooth", "BluetoothService available:", typeof BluetoothService !== 'undefined')
|
|
||||||
if (typeof BluetoothService !== 'undefined') {
|
|
||||||
Logger.log("Bluetooth", "Connected devices:", BluetoothService.connectedDevices.length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
icon: {
|
icon: {
|
||||||
// Show different icons based on connection status
|
// Show different icons based on connection status
|
||||||
if (BluetoothService.connectedDevices.length > 0) {
|
if (BluetoothService.pairedDevices.length > 0) {
|
||||||
return "bluetooth_connected"
|
return "bluetooth_connected"
|
||||||
} else if (BluetoothService.isDiscovering) {
|
} else if (BluetoothService.discovering) {
|
||||||
return "bluetooth_searching"
|
return "bluetooth_searching"
|
||||||
} else {
|
} else {
|
||||||
return "bluetooth"
|
return "bluetooth"
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Bluetooth
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
@ -38,7 +39,7 @@ NLoader {
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible && Settings.data.network.bluetoothEnabled) {
|
if (visible && Settings.data.network.bluetoothEnabled) {
|
||||||
// Always refresh devices when menu opens to get fresh device objects
|
// Always refresh devices when menu opens to get fresh device objects
|
||||||
BluetoothService.refreshDevices()
|
BluetoothService.adapter.discovering = true
|
||||||
} else if (bluetoothMenuRect.opacityValue > 0) {
|
} else if (bluetoothMenuRect.opacityValue > 0) {
|
||||||
// Start hide animation
|
// Start hide animation
|
||||||
bluetoothMenuRect.scaleValue = 0.8
|
bluetoothMenuRect.scaleValue = 0.8
|
||||||
|
|
@ -63,11 +64,14 @@ NLoader {
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: bluetoothMenuRect
|
id: bluetoothMenuRect
|
||||||
|
|
||||||
|
property var deviceData: null
|
||||||
|
|
||||||
color: Color.mSurface
|
color: Color.mSurface
|
||||||
radius: Style.radiusLarge * scaling
|
radius: Style.radiusLarge * scaling
|
||||||
border.color: Color.mOutlineVariant
|
border.color: Color.mOutlineVariant
|
||||||
border.width: Math.max(1, Style.borderThin * scaling)
|
border.width: Math.max(1, Style.borderThin * scaling)
|
||||||
width: 340 * scaling
|
width: 400 * scaling
|
||||||
height: 500 * scaling
|
height: 500 * scaling
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
@ -81,6 +85,11 @@ NLoader {
|
||||||
scale: scaleValue
|
scale: scaleValue
|
||||||
opacity: opacityValue
|
opacity: opacityValue
|
||||||
|
|
||||||
|
// Prevent closing the window if clicking inside it
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
// Animate in when component is completed
|
// Animate in when component is completed
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
scaleValue = 1.0
|
scaleValue = 1.0
|
||||||
|
|
@ -107,6 +116,7 @@ NLoader {
|
||||||
anchors.margins: Style.marginLarge * scaling
|
anchors.margins: Style.marginLarge * scaling
|
||||||
spacing: Style.marginMedium * scaling
|
spacing: Style.marginMedium * scaling
|
||||||
|
|
||||||
|
// HEADER
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: Style.marginMedium * scaling
|
spacing: Style.marginMedium * scaling
|
||||||
|
|
@ -121,18 +131,19 @@ NLoader {
|
||||||
NText {
|
NText {
|
||||||
text: "Bluetooth"
|
text: "Bluetooth"
|
||||||
font.pointSize: Style.fontSizeLarge * scaling
|
font.pointSize: Style.fontSizeLarge * scaling
|
||||||
font.bold: true
|
font.weight: Style.fontWeightBold
|
||||||
color: Color.mOnSurface
|
color: Color.mOnSurface
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
NIconButton {
|
NIconButton {
|
||||||
icon: "refresh"
|
icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop_circle" : "refresh"
|
||||||
tooltipText: "Refresh Devices"
|
tooltipText: "Refresh Devices"
|
||||||
sizeMultiplier: 0.8
|
sizeMultiplier: 0.8
|
||||||
enabled: Settings.data.network.bluetoothEnabled && !BluetoothService.isDiscovering
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
BluetoothService.refreshDevices()
|
if (BluetoothService.adapter) {
|
||||||
|
BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,247 +159,311 @@ NLoader {
|
||||||
|
|
||||||
NDivider {}
|
NDivider {}
|
||||||
|
|
||||||
Item {
|
// Available devices
|
||||||
Layout.fillWidth: true
|
Column {
|
||||||
Layout.fillHeight: true
|
id: column
|
||||||
|
|
||||||
// Loading indicator
|
width: parent.width
|
||||||
ColumnLayout {
|
spacing: Style.marginMedium * scaling
|
||||||
anchors.centerIn: parent
|
visible: BluetoothService.adapter && BluetoothService.adapter.enabled
|
||||||
visible: Settings.data.network.bluetoothEnabled && BluetoothService.isDiscovering
|
|
||||||
spacing: Style.marginMedium * scaling
|
|
||||||
|
|
||||||
NBusyIndicator {
|
RowLayout {
|
||||||
running: BluetoothService.isDiscovering
|
width: parent.width
|
||||||
color: Color.mPrimary
|
|
||||||
size: Style.baseWidgetSize * scaling
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
NText {
|
|
||||||
text: "Scanning for devices..."
|
|
||||||
font.pointSize: Style.fontSizeNormal * scaling
|
|
||||||
color: Color.mOnSurfaceVariant
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bluetooth disabled message
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
visible: !Settings.data.network.bluetoothEnabled
|
|
||||||
spacing: Style.marginMedium * scaling
|
spacing: Style.marginMedium * scaling
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: "bluetooth_disabled"
|
text: "Available Devices"
|
||||||
font.family: "Material Symbols Outlined"
|
|
||||||
font.pointSize: Style.fontSizeXXL * scaling
|
|
||||||
color: Color.mOnSurfaceVariant
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
NText {
|
|
||||||
text: "Bluetooth is disabled"
|
|
||||||
font.pointSize: Style.fontSizeLarge * scaling
|
font.pointSize: Style.fontSizeLarge * scaling
|
||||||
color: Color.mOnSurfaceVariant
|
color: Color.mOnSurface
|
||||||
Layout.alignment: Qt.AlignHCenter
|
font.weight: Style.fontWeightMedium
|
||||||
}
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
NText {
|
|
||||||
text: "Enable Bluetooth to see available devices"
|
|
||||||
font.pointSize: Style.fontSizeNormal * scaling
|
|
||||||
color: Color.mOnSurfaceVariant
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device list
|
Repeater {
|
||||||
ListView {
|
model: {
|
||||||
id: deviceList
|
if (!BluetoothService.adapter || !BluetoothService.adapter.discovering || !Bluetooth.devices)
|
||||||
anchors.fill: parent
|
return []
|
||||||
visible: Settings.data.network.bluetoothEnabled && !BluetoothService.isDiscovering
|
|
||||||
model: []
|
|
||||||
spacing: Style.marginMedium * scaling
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
// Combine all devices into a single list for the ListView
|
var filtered = Bluetooth.devices.values.filter(dev => {
|
||||||
property var allDevices: {
|
return dev && !dev.paired && !dev.pairing
|
||||||
const devices = []
|
&& !dev.blocked && (dev.signalStrength === undefined
|
||||||
|
|| dev.signalStrength > 0)
|
||||||
// Add connected devices first
|
})
|
||||||
for (const device of BluetoothService.connectedDevices) {
|
return BluetoothService.sortDevices(filtered)
|
||||||
devices.push({
|
|
||||||
"device": device,
|
|
||||||
"type": 'connected',
|
|
||||||
"section": 'Connected Devices'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add paired devices
|
|
||||||
for (const device of BluetoothService.pairedDevices) {
|
|
||||||
devices.push({
|
|
||||||
"device": device,
|
|
||||||
"type": 'paired',
|
|
||||||
"section": 'Paired Devices'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add available devices
|
|
||||||
for (const device of BluetoothService.availableDevices) {
|
|
||||||
devices.push({
|
|
||||||
"device": device,
|
|
||||||
"type": 'available',
|
|
||||||
"section": 'Available Devices'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return devices
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update model when devices change
|
Rectangle {
|
||||||
onAllDevicesChanged: {
|
property bool canConnect: BluetoothService.canConnect(modelData)
|
||||||
deviceList.model = allDevices
|
property bool isBusy: BluetoothService.isDeviceBusy(modelData)
|
||||||
}
|
|
||||||
|
|
||||||
// Also watch for changes in the service arrays
|
width: parent.width
|
||||||
Connections {
|
height: 70
|
||||||
target: BluetoothService
|
radius: Style.radiusMedium * scaling
|
||||||
function onConnectedDevicesChanged() {
|
color: {
|
||||||
deviceList.model = deviceList.allDevices
|
if (availableDeviceArea.containsMouse && !isBusy)
|
||||||
|
return Qt.rgba(Color.mPrimary.r, Color.mPrimary.g, Color.mPrimary.b, 0.08)
|
||||||
|
|
||||||
|
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
||||||
|
return Qt.rgba(Color.mError.r, Color.mError.g, Color.mError.b, 0.12)
|
||||||
|
|
||||||
|
if (modelData.blocked)
|
||||||
|
return Color.mError
|
||||||
|
|
||||||
|
return Color.mSurfaceVariant
|
||||||
}
|
}
|
||||||
function onPairedDevicesChanged() {
|
border.color: {
|
||||||
deviceList.model = deviceList.allDevices
|
if (modelData.pairing)
|
||||||
|
return Color.mError
|
||||||
|
|
||||||
|
if (modelData.blocked)
|
||||||
|
return Color.mError
|
||||||
|
|
||||||
|
return Color.mOutline
|
||||||
}
|
}
|
||||||
function onAvailableDevicesChanged() {
|
border.width: 1
|
||||||
deviceList.model = deviceList.allDevices
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: Item {
|
Row {
|
||||||
width: parent ? parent.width : 0
|
anchors.left: parent.left
|
||||||
height: Style.baseWidgetSize * 1.5 * scaling
|
anchors.leftMargin: Style.marginMedium * scaling
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Style.marginSmall * scaling
|
||||||
|
|
||||||
Rectangle {
|
NText {
|
||||||
anchors.fill: parent
|
text: BluetoothService.getDeviceIcon(modelData)
|
||||||
radius: Style.radiusMedium * scaling
|
font.family: "Material Symbols Outlined"
|
||||||
color: modelData.device.connected ? Color.mPrimary : (deviceMouseArea.containsMouse ? Color.mTertiary : Color.transparent)
|
font.pointSize: Style.fontSizeXL * scaling
|
||||||
|
color: {
|
||||||
|
if (modelData.pairing)
|
||||||
|
return Color.mError
|
||||||
|
|
||||||
RowLayout {
|
if (modelData.blocked)
|
||||||
anchors.fill: parent
|
return Color.mError
|
||||||
anchors.margins: Style.marginSmall * scaling
|
|
||||||
spacing: Style.marginSmall * scaling
|
return Color.mOnSurface
|
||||||
|
}
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 2
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: BluetoothService.getDeviceIcon(modelData.device)
|
text: modelData.name || modelData.deviceName
|
||||||
font.family: "Material Symbols Outlined"
|
font.pointSize: Style.fonttSizeMedium * scaling
|
||||||
font.pointSize: Style.fontSizeXL * scaling
|
color: {
|
||||||
color: modelData.device.connected ? Color.mSurface : (deviceMouseArea.containsMouse ? Color.mSurface : Color.mOnSurface)
|
if (modelData.pairing)
|
||||||
|
return Color.mError
|
||||||
|
|
||||||
|
if (modelData.blocked)
|
||||||
|
return Color.mError
|
||||||
|
|
||||||
|
return Color.mOnSurface
|
||||||
|
}
|
||||||
|
font.weight: modelData.pairing ? Style.fontWeightMedium : Font.Normal
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
Row {
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: Style.marginTiny * scaling
|
spacing: Style.marginTiny * scaling
|
||||||
|
|
||||||
NText {
|
Row {
|
||||||
text: modelData.device.name || modelData.device.deviceName || "Unknown Device"
|
spacing: Style.marginSmall * spacing
|
||||||
font.pointSize: Style.fontSizeNormal * scaling
|
|
||||||
elide: Text.ElideRight
|
|
||||||
Layout.fillWidth: true
|
|
||||||
color: modelData.device.connected ? Color.mSurface : (deviceMouseArea.containsMouse ? Color.mSurface : Color.mOnSurface)
|
|
||||||
}
|
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: {
|
text: {
|
||||||
if (modelData.device.connected) {
|
if (modelData.pairing)
|
||||||
return "Connected"
|
return "Pairing..."
|
||||||
} else if (modelData.device.paired) {
|
|
||||||
return "Paired"
|
if (modelData.blocked)
|
||||||
} else {
|
return "Blocked"
|
||||||
return "Available"
|
|
||||||
|
return BluetoothService.getSignalStrength(modelData)
|
||||||
|
}
|
||||||
|
font.pointSize: Style.fontSizeSmall * scaling
|
||||||
|
color: {
|
||||||
|
if (modelData.pairing)
|
||||||
|
return Color.mError
|
||||||
|
|
||||||
|
if (modelData.blocked)
|
||||||
|
return Theme.error
|
||||||
|
|
||||||
|
return Qt.rgba(Color.mOnSurface.r, Color.mOnSurface.g, Color.mOnSurface.b, 0.7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
font.pointSize: Style.fontSizeSmall * scaling
|
|
||||||
color: modelData.device.connected ? Color.mSurface : (deviceMouseArea.containsMouse ? Color.mSurface : Color.mOnSurfaceVariant)
|
|
||||||
}
|
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: BluetoothService.getBatteryText(modelData.device)
|
text: BluetoothService.getSignalIcon(modelData)
|
||||||
font.pointSize: Style.fontSizeSmall * scaling
|
font.family: "Material Symbols Outlined"
|
||||||
color: modelData.device.connected ? Color.mSurface : (deviceMouseArea.containsMouse ? Color.mSurface : Color.mOnSurfaceVariant)
|
font.pointSize: Style.fontSizeSmall * scaling
|
||||||
visible: modelData.device.batteryAvailable
|
color: Qt.rgba(Color.mOnSurface.r, Color.mOnSurface.g, Color.mOnSurface.b, 0.7)
|
||||||
|
visible: modelData.signalStrength !== undefined && modelData.signalStrength > 0
|
||||||
|
&& !modelData.pairing && !modelData.blocked
|
||||||
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: (modelData.signalStrength !== undefined
|
||||||
|
&& modelData.signalStrength > 0) ? modelData.signalStrength + "%" : ""
|
||||||
|
font.pointSize: Style.fontSizeSmall * scaling
|
||||||
|
color: Qt.rgba(Color.mOnSurface.r, Color.mOnSurface.g, Color.mOnSurface.b, 0.5)
|
||||||
|
visible: modelData.signalStrength !== undefined && modelData.signalStrength > 0
|
||||||
|
&& !modelData.pairing && !modelData.blocked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Rectangle {
|
||||||
Layout.preferredWidth: Style.baseWidgetSize * 0.7 * scaling
|
width: 80
|
||||||
Layout.preferredHeight: Style.baseWidgetSize * 0.7 * scaling
|
height: 28
|
||||||
visible: modelData.device.pairing || modelData.device.state === 2 // Connecting state
|
radius: Style.radiusMedium * scaling
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Style.marginMedium * scaling
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: modelData.state !== BluetoothDeviceState.Connecting
|
||||||
|
color: {
|
||||||
|
if (!canConnect && !isBusy)
|
||||||
|
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||||
|
|
||||||
NBusyIndicator {
|
if (actionButtonArea.containsMouse && !isBusy)
|
||||||
visible: modelData.device.pairing || modelData.device.state === 2
|
return Qt.rgba(Color.mPrimary.r, Color.mPrimary.g, Color.mPrimary.b, 0.12)
|
||||||
running: modelData.device.pairing || modelData.device.state === 2
|
|
||||||
color: Color.mPrimary
|
return "transparent"
|
||||||
anchors.centerIn: parent
|
}
|
||||||
size: Style.baseWidgetSize * 0.7 * scaling
|
border.color: canConnect || isBusy ? Color.mPrimary : Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||||
}
|
Theme.outline.b, 0.2)
|
||||||
}
|
border.width: 1
|
||||||
|
opacity: canConnect || isBusy ? 1 : 0.5
|
||||||
NText {
|
|
||||||
visible: modelData.device.connected
|
NText {
|
||||||
text: "connected"
|
anchors.centerIn: parent
|
||||||
font.pointSize: Style.fontSizeSmall * scaling
|
text: {
|
||||||
color: modelData.device.connected ? Color.mSurface : (deviceMouseArea.containsMouse ? Color.mSurface : Color.mOnSurface)
|
if (modelData.pairing)
|
||||||
|
return "Pairing..."
|
||||||
|
|
||||||
|
if (modelData.blocked)
|
||||||
|
return "Blocked"
|
||||||
|
|
||||||
|
return "Connect"
|
||||||
}
|
}
|
||||||
|
font.pointSize: Style.fontSizeSmall * scaling
|
||||||
|
color: canConnect || isBusy ? Color.mPrimary : Qt.rgba(Color.mOnSurface.r, Color.mOnSurface.g,
|
||||||
|
Color.mOnSurface.b, 0.5)
|
||||||
|
font.weight: Style.fontWeightMedium
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: deviceMouseArea
|
id: actionButtonArea
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
cursorShape: canConnect
|
||||||
|
&& !isBusy ? Qt.PointingHandCursor : (isBusy ? Qt.BusyCursor : Qt.ArrowCursor)
|
||||||
|
enabled: canConnect && !isBusy
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (modelData.device.connected) {
|
if (modelData)
|
||||||
BluetoothService.disconnectDevice(modelData.device)
|
BluetoothService.connectDeviceWithTrust(modelData)
|
||||||
} else if (modelData.device.paired) {
|
|
||||||
BluetoothService.connectDevice(modelData.device)
|
|
||||||
} else {
|
|
||||||
BluetoothService.pairDevice(modelData.device)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: availableDeviceArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.rightMargin: 90
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: canConnect && !isBusy ? Qt.PointingHandCursor : (isBusy ? Qt.BusyCursor : Qt.ArrowCursor)
|
||||||
|
enabled: canConnect && !isBusy
|
||||||
|
onClicked: {
|
||||||
|
if (modelData)
|
||||||
|
BluetoothService.connectDeviceWithTrust(modelData)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty state when no devices found
|
Column {
|
||||||
ColumnLayout {
|
width: parent.width
|
||||||
anchors.centerIn: parent
|
|
||||||
visible: Settings.data.network.bluetoothEnabled && !BluetoothService.isDiscovering
|
|
||||||
&& deviceList.count === 0
|
|
||||||
spacing: Style.marginMedium * scaling
|
spacing: Style.marginMedium * scaling
|
||||||
|
visible: {
|
||||||
|
if (!BluetoothService.adapter || !BluetoothService.adapter.discovering || !Bluetooth.devices)
|
||||||
|
return false
|
||||||
|
|
||||||
NText {
|
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||||
text: "bluetooth_disabled"
|
return dev && !dev.paired && !dev.pairing
|
||||||
font.family: "Material Symbols Outlined"
|
&& !dev.blocked
|
||||||
font.pointSize: Style.fontSizeXXL * scaling
|
&& (dev.signalStrength === undefined
|
||||||
color: Color.mOnSurfaceVariant
|
|| dev.signalStrength > 0)
|
||||||
Layout.alignment: Qt.AlignHCenter
|
}).length
|
||||||
|
return availableCount === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
spacing: Style.marginMedium * scaling
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: "sync"
|
||||||
|
font.family: "Material Symbols Outlined"
|
||||||
|
font.pointSize: 32 * scaling
|
||||||
|
color: Color.mPrimary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
RotationAnimation on rotation {
|
||||||
|
running: true
|
||||||
|
loops: Animation.Infinite
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
duration: 2000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: "Scanning for devices..."
|
||||||
|
font.pointSize: Style.fontSizeLarge * scaling
|
||||||
|
color: Color.mOnSurface
|
||||||
|
font.weight: Style.fontWeightMedium
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: "No Bluetooth devices"
|
text: "Make sure your device is in pairing mode"
|
||||||
font.pointSize: Style.fontSizeLarge * scaling
|
font.pointSize: Style.fontSizeMedium * scaling
|
||||||
color: Color.mOnSurfaceVariant
|
color: Qt.rgba(Color.mOnSurface.r, Color.mOnSurface.g, Color.mOnSurface.b, 0.7)
|
||||||
Layout.alignment: Qt.AlignHCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
|
||||||
|
|
||||||
NText {
|
|
||||||
text: "Click the refresh button to discover devices"
|
|
||||||
font.pointSize: Style.fontSizeNormal * scaling
|
|
||||||
color: Color.mOnSurfaceVariant
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NText {
|
||||||
|
text: "No devices found. Put your device in pairing mode and click Start Scanning."
|
||||||
|
font.pointSize: Style.fontSizeMedium * scaling
|
||||||
|
color: Qt.rgba(Color.mOnSurface.r, Color.mOnSurface.g, Color.mOnSurface.b, 0.7)
|
||||||
|
visible: {
|
||||||
|
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||||
|
return true
|
||||||
|
|
||||||
|
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||||
|
return dev && !dev.paired && !dev.pairing
|
||||||
|
&& !dev.blocked
|
||||||
|
&& (dev.signalStrength === undefined
|
||||||
|
|| dev.signalStrength > 0)
|
||||||
|
}).length
|
||||||
|
return availableCount === 0 && !BluetoothService.adapter.discovering
|
||||||
|
}
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: parent.width
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This item takes up all the remaining vertical space.
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,432 +3,142 @@ pragma Singleton
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Bluetooth
|
import Quickshell.Bluetooth
|
||||||
import qs.Commons
|
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// Bluetooth state properties
|
readonly property BluetoothAdapter adapter: Bluetooth.defaultAdapter
|
||||||
property bool isEnabled: Settings.data.network.bluetoothEnabled
|
readonly property bool available: adapter !== null
|
||||||
property bool isDiscovering: false
|
readonly property bool enabled: (adapter && adapter.enabled) ?? false
|
||||||
property var connectedDevices: []
|
readonly property bool discovering: (adapter && adapter.discovering) ?? false
|
||||||
property var pairedDevices: []
|
readonly property var devices: adapter ? adapter.devices : null
|
||||||
property var availableDevices: []
|
readonly property var pairedDevices: {
|
||||||
property string lastConnectedDevice: ""
|
if (!adapter || !adapter.devices)
|
||||||
property string connectStatus: ""
|
return []
|
||||||
property string connectStatusDevice: ""
|
|
||||||
property string connectError: ""
|
|
||||||
|
|
||||||
// Timer for refreshing device lists
|
return adapter.devices.values.filter(dev => {
|
||||||
property Timer refreshTimer: Timer {
|
return dev && (dev.paired || dev.trusted)
|
||||||
interval: 5000 // Refresh every 5 seconds when discovery is active
|
})
|
||||||
repeat: true
|
}
|
||||||
running: root.isEnabled && Bluetooth.defaultAdapter && Bluetooth.defaultAdapter.discovering
|
readonly property var allDevicesWithBattery: {
|
||||||
onTriggered: root.refreshDevices()
|
if (!adapter || !adapter.devices)
|
||||||
|
return []
|
||||||
|
|
||||||
|
return adapter.devices.values.filter(dev => {
|
||||||
|
return dev && dev.batteryAvailable && dev.battery > 0
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
function sortDevices(devices) {
|
||||||
Logger.log("Bluetooth", "Service started")
|
return devices.sort((a, b) => {
|
||||||
|
var aName = a.name || a.deviceName || ""
|
||||||
|
var bName = b.name || b.deviceName || ""
|
||||||
|
|
||||||
if (isEnabled && Bluetooth.defaultAdapter) {
|
var aHasRealName = aName.includes(" ") && aName.length > 3
|
||||||
// Ensure adapter is enabled
|
var bHasRealName = bName.includes(" ") && bName.length > 3
|
||||||
if (!Bluetooth.defaultAdapter.enabled) {
|
|
||||||
Bluetooth.defaultAdapter.enabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start discovery to find devices
|
if (aHasRealName && !bHasRealName)
|
||||||
if (!Bluetooth.defaultAdapter.discovering) {
|
return -1
|
||||||
Bluetooth.defaultAdapter.discovering = true
|
if (!aHasRealName && bHasRealName)
|
||||||
}
|
return 1
|
||||||
|
|
||||||
// Refresh devices after a short delay to allow discovery to start
|
var aSignal = (a.signalStrength !== undefined && a.signalStrength > 0) ? a.signalStrength : 0
|
||||||
Qt.callLater(function () {
|
var bSignal = (b.signalStrength !== undefined && b.signalStrength > 0) ? b.signalStrength : 0
|
||||||
refreshDevices()
|
return bSignal - aSignal
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to enable/disable Bluetooth
|
|
||||||
function setBluetoothEnabled(enabled) {
|
|
||||||
|
|
||||||
if (enabled) {
|
|
||||||
// Store the currently connected devices before enabling
|
|
||||||
for (const device of connectedDevices) {
|
|
||||||
if (device.connected) {
|
|
||||||
lastConnectedDevice = device.name || device.deviceName
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable Bluetooth
|
|
||||||
if (Bluetooth.defaultAdapter) {
|
|
||||||
Bluetooth.defaultAdapter.enabled = true
|
|
||||||
|
|
||||||
// Start discovery to find devices
|
|
||||||
if (!Bluetooth.defaultAdapter.discovering) {
|
|
||||||
Bluetooth.defaultAdapter.discovering = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh devices after enabling
|
|
||||||
Qt.callLater(refreshDevices)
|
|
||||||
} else {
|
|
||||||
Logger.warn("Bluetooth", "No adapter found")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Disconnect from current devices before disabling
|
|
||||||
for (const device of connectedDevices) {
|
|
||||||
if (device.connected) {
|
|
||||||
device.disconnect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable Bluetooth
|
|
||||||
if (Bluetooth.defaultAdapter) {
|
|
||||||
Logger.log("Bluetooth", "Disabling adapter")
|
|
||||||
Bluetooth.defaultAdapter.enabled = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings.data.network.bluetoothEnabled = enabled
|
|
||||||
isEnabled = enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to refresh device lists
|
|
||||||
function refreshDevices() {
|
|
||||||
if (!isEnabled || !Bluetooth.defaultAdapter) {
|
|
||||||
connectedDevices = []
|
|
||||||
pairedDevices = []
|
|
||||||
availableDevices = []
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.log("Bluetooth", "refreshDevices")
|
|
||||||
|
|
||||||
// Remove duplicate check since we already did it above
|
|
||||||
const connected = []
|
|
||||||
const paired = []
|
|
||||||
const available = []
|
|
||||||
|
|
||||||
let devices = null
|
|
||||||
|
|
||||||
// Try adapter devices first
|
|
||||||
if (Bluetooth.defaultAdapter.enabled && Bluetooth.defaultAdapter.devices) {
|
|
||||||
devices = Bluetooth.defaultAdapter.devices
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to global devices list
|
|
||||||
if (!devices && Bluetooth.devices) {
|
|
||||||
devices = Bluetooth.devices
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!devices) {
|
|
||||||
connectedDevices = []
|
|
||||||
pairedDevices = []
|
|
||||||
availableDevices = []
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use Qt model methods to iterate through the ObjectModel
|
|
||||||
let deviceFound = false
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Get the row count using the Qt model method
|
|
||||||
const rowCount = devices.rowCount()
|
|
||||||
|
|
||||||
if (rowCount > 0) {
|
|
||||||
// Iterate through each row using the Qt model data() method
|
|
||||||
for (var i = 0; i < rowCount; i++) {
|
|
||||||
try {
|
|
||||||
// Create a model index for this row
|
|
||||||
const modelIndex = devices.index(i, 0)
|
|
||||||
if (!modelIndex.valid)
|
|
||||||
continue
|
|
||||||
|
|
||||||
// Get the device object using the Qt.UserRole (typically 256)
|
|
||||||
const device = devices.data(modelIndex, 256) // Qt.UserRole
|
|
||||||
if (!device) {
|
|
||||||
// Try alternative role values
|
|
||||||
const deviceAlt = devices.data(modelIndex, 0) // Qt.DisplayRole
|
|
||||||
if (deviceAlt) {
|
|
||||||
device = deviceAlt
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceFound = true
|
|
||||||
|
|
||||||
if (device.connected) {
|
|
||||||
connected.push(device)
|
|
||||||
} else if (device.paired) {
|
|
||||||
paired.push(device)
|
|
||||||
} else {
|
|
||||||
available.push(device)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
|
|
||||||
// Silent error handling
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alternative method: try the values property if available
|
|
||||||
if (!deviceFound && devices.values) {
|
|
||||||
try {
|
|
||||||
const values = devices.values
|
|
||||||
if (values && typeof values === 'object') {
|
|
||||||
// Try to iterate through values if it's iterable
|
|
||||||
if (values.length !== undefined) {
|
|
||||||
for (var i = 0; i < values.length; i++) {
|
|
||||||
const device = values[i]
|
|
||||||
if (device) {
|
|
||||||
deviceFound = true
|
|
||||||
if (device.connected) {
|
|
||||||
connected.push(device)
|
|
||||||
} else if (device.paired) {
|
|
||||||
paired.push(device)
|
|
||||||
} else {
|
|
||||||
available.push(device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
|
|
||||||
// Silent error handling
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Logger.warn("Bluetooth", "Error accessing device model:", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!deviceFound) {
|
|
||||||
Logger.log("Bluetooth", "No device found")
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedDevices = connected
|
|
||||||
pairedDevices = paired
|
|
||||||
availableDevices = available
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to start discovery
|
|
||||||
function startDiscovery() {
|
|
||||||
if (!isEnabled || !Bluetooth.defaultAdapter)
|
|
||||||
return
|
|
||||||
|
|
||||||
isDiscovering = true
|
|
||||||
Bluetooth.defaultAdapter.discovering = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to stop discovery
|
|
||||||
function stopDiscovery() {
|
|
||||||
if (!Bluetooth.defaultAdapter)
|
|
||||||
return
|
|
||||||
|
|
||||||
isDiscovering = false
|
|
||||||
Bluetooth.defaultAdapter.discovering = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to connect to a device
|
|
||||||
function connectDevice(device) {
|
|
||||||
if (!device)
|
|
||||||
return
|
|
||||||
|
|
||||||
// Check if device is still valid (not stale from previous session)
|
|
||||||
if (!device.connect || typeof device.connect !== 'function') {
|
|
||||||
Logger.warn("Bluetooth", "Device object is stale, refreshing devices")
|
|
||||||
refreshDevices()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
connectStatus = "connecting"
|
|
||||||
connectStatusDevice = device.name || device.deviceName
|
|
||||||
connectError = ""
|
|
||||||
|
|
||||||
try {
|
|
||||||
device.connect()
|
|
||||||
} catch (error) {
|
|
||||||
Logger.error("Bluetooth", "Error connecting to device:", error)
|
|
||||||
connectStatus = "error"
|
|
||||||
connectError = error.toString()
|
|
||||||
Qt.callLater(refreshDevices)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to disconnect from a device
|
|
||||||
function disconnectDevice(device) {
|
|
||||||
if (!device)
|
|
||||||
return
|
|
||||||
|
|
||||||
// Check if device is still valid (not stale from previous session)
|
|
||||||
if (!device.disconnect || typeof device.disconnect !== 'function') {
|
|
||||||
Logger.warn("Bluetooth", "Device object is stale, refreshing devices")
|
|
||||||
refreshDevices()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
device.disconnect()
|
|
||||||
// Clear connection status
|
|
||||||
connectStatus = ""
|
|
||||||
connectStatusDevice = ""
|
|
||||||
connectError = ""
|
|
||||||
} catch (error) {
|
|
||||||
Logger.warn("Bluetooth", "Error disconnecting device:", error)
|
|
||||||
Qt.callLater(refreshDevices)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to pair with a device
|
|
||||||
function pairDevice(device) {
|
|
||||||
if (!device)
|
|
||||||
return
|
|
||||||
|
|
||||||
// Check if device is still valid (not stale from previous session)
|
|
||||||
if (!device.pair || typeof device.pair !== 'function') {
|
|
||||||
Logger.warn("Bluetooth", "Device object is stale, refreshing devices")
|
|
||||||
refreshDevices()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
device.pair()
|
|
||||||
} catch (error) {
|
|
||||||
Logger.warn("Bluetooth", "Error pairing device:", error)
|
|
||||||
Qt.callLater(refreshDevices)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to forget a device
|
|
||||||
function forgetDevice(device) {
|
|
||||||
if (!device)
|
|
||||||
return
|
|
||||||
|
|
||||||
// Check if device is still valid (not stale from previous session)
|
|
||||||
if (!device.forget || typeof device.forget !== 'function') {
|
|
||||||
Logger.warn("Bluetooth", "Device object is stale, refreshing devices")
|
|
||||||
refreshDevices()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store device info before forgetting (in case device object becomes invalid)
|
|
||||||
const deviceName = device.name || device.deviceName || "Unknown Device"
|
|
||||||
|
|
||||||
try {
|
|
||||||
device.forget()
|
|
||||||
|
|
||||||
// Clear any connection status that might be related to this device
|
|
||||||
if (connectStatusDevice === deviceName) {
|
|
||||||
connectStatus = ""
|
|
||||||
connectStatusDevice = ""
|
|
||||||
connectError = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh devices after a delay to ensure the forget operation is complete
|
|
||||||
Qt.callLater(refreshDevices, 1000)
|
|
||||||
} catch (error) {
|
|
||||||
Logger.warn("Bluetooth", "Error forgetting device:", error)
|
|
||||||
Qt.callLater(refreshDevices, 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to get device icon
|
|
||||||
function getDeviceIcon(device) {
|
function getDeviceIcon(device) {
|
||||||
if (!device)
|
if (!device)
|
||||||
return "bluetooth"
|
return "bluetooth"
|
||||||
|
|
||||||
// Use device icon if available, otherwise fall back to device type
|
var name = (device.name || device.deviceName || "").toLowerCase()
|
||||||
if (device.icon) {
|
var icon = (device.icon || "").toLowerCase()
|
||||||
return device.icon
|
if (icon.includes("headset") || icon.includes("audio") || name.includes("headphone") || name.includes("airpod")
|
||||||
}
|
|| name.includes("headset") || name.includes("arctis"))
|
||||||
|
return "headset"
|
||||||
|
|
||||||
// Fallback icons based on common device types
|
if (icon.includes("mouse") || name.includes("mouse"))
|
||||||
const name = (device.name || device.deviceName || "").toLowerCase()
|
|
||||||
if (name.includes("headphone") || name.includes("earbud") || name.includes("airpods")) {
|
|
||||||
return "headphones"
|
|
||||||
} else if (name.includes("speaker")) {
|
|
||||||
return "speaker"
|
|
||||||
} else if (name.includes("keyboard")) {
|
|
||||||
return "keyboard"
|
|
||||||
} else if (name.includes("mouse")) {
|
|
||||||
return "mouse"
|
return "mouse"
|
||||||
} else if (name.includes("phone") || name.includes("mobile")) {
|
|
||||||
|
if (icon.includes("keyboard") || name.includes("keyboard"))
|
||||||
|
return "keyboard"
|
||||||
|
|
||||||
|
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") || name.includes("android")
|
||||||
|
|| name.includes("samsung"))
|
||||||
return "smartphone"
|
return "smartphone"
|
||||||
} else if (name.includes("laptop") || name.includes("computer")) {
|
|
||||||
return "laptop"
|
if (icon.includes("watch") || name.includes("watch"))
|
||||||
}
|
return "watch"
|
||||||
|
|
||||||
|
if (icon.includes("speaker") || name.includes("speaker"))
|
||||||
|
return "speaker"
|
||||||
|
|
||||||
|
if (icon.includes("display") || name.includes("tv"))
|
||||||
|
return "tv"
|
||||||
|
|
||||||
return "bluetooth"
|
return "bluetooth"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to get device status text
|
function canConnect(device) {
|
||||||
function getDeviceStatus(device) {
|
|
||||||
if (!device)
|
if (!device)
|
||||||
return ""
|
return false
|
||||||
|
|
||||||
if (device.connected) {
|
return !device.paired && !device.pairing && !device.blocked
|
||||||
return "Connected"
|
|
||||||
} else if (device.pairing) {
|
|
||||||
return "Pairing..."
|
|
||||||
} else if (device.paired) {
|
|
||||||
return "Paired"
|
|
||||||
} else {
|
|
||||||
return "Available"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to get battery level text
|
function getSignalStrength(device) {
|
||||||
function getBatteryText(device) {
|
if (!device || device.signalStrength === undefined || device.signalStrength <= 0)
|
||||||
if (!device || !device.batteryAvailable)
|
return "Unknown"
|
||||||
return ""
|
|
||||||
|
|
||||||
const percentage = Math.round(device.battery * 100)
|
var signal = device.signalStrength
|
||||||
return `${percentage}%`
|
if (signal >= 80)
|
||||||
|
return "Excellent"
|
||||||
|
|
||||||
|
if (signal >= 60)
|
||||||
|
return "Good"
|
||||||
|
|
||||||
|
if (signal >= 40)
|
||||||
|
return "Fair"
|
||||||
|
|
||||||
|
if (signal >= 20)
|
||||||
|
return "Poor"
|
||||||
|
|
||||||
|
return "Very Poor"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watch for Bluetooth adapter changes
|
function getSignalIcon(device) {
|
||||||
Connections {
|
if (!device || device.signalStrength === undefined || device.signalStrength <= 0)
|
||||||
target: Bluetooth.defaultAdapter
|
return "signal_cellular_null"
|
||||||
ignoreUnknownSignals: true
|
|
||||||
|
|
||||||
function onEnabledChanged() {
|
var signal = device.signalStrength
|
||||||
root.isEnabled = Bluetooth.defaultAdapter.enabled
|
if (signal >= 80)
|
||||||
Settings.data.network.bluetoothEnabled = root.isEnabled
|
return "signal_cellular_4_bar"
|
||||||
if (root.isEnabled) {
|
|
||||||
Qt.callLater(refreshDevices)
|
|
||||||
} else {
|
|
||||||
connectedDevices = []
|
|
||||||
pairedDevices = []
|
|
||||||
availableDevices = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDiscoveringChanged() {
|
if (signal >= 60)
|
||||||
root.isDiscovering = Bluetooth.defaultAdapter.discovering
|
return "signal_cellular_3_bar"
|
||||||
if (Bluetooth.defaultAdapter.discovering) {
|
|
||||||
Qt.callLater(refreshDevices)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onStateChanged() {
|
if (signal >= 40)
|
||||||
if (Bluetooth.defaultAdapter.state >= 4) {
|
return "signal_cellular_2_bar"
|
||||||
Qt.callLater(refreshDevices)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDevicesChanged() {
|
if (signal >= 20)
|
||||||
Qt.callLater(refreshDevices)
|
return "signal_cellular_1_bar"
|
||||||
}
|
|
||||||
|
return "signal_cellular_0_bar"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watch for global device changes
|
function isDeviceBusy(device) {
|
||||||
Connections {
|
if (!device)
|
||||||
target: Bluetooth
|
return false
|
||||||
ignoreUnknownSignals: true
|
return device.pairing || device.state === BluetoothDeviceState.Disconnecting
|
||||||
|
|| device.state === BluetoothDeviceState.Connecting
|
||||||
|
}
|
||||||
|
|
||||||
function onDevicesChanged() {
|
function connectDeviceWithTrust(device) {
|
||||||
Qt.callLater(refreshDevices)
|
if (!device)
|
||||||
}
|
return
|
||||||
|
|
||||||
|
device.trusted = true
|
||||||
|
device.connect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue