307 lines
8.9 KiB
QML
307 lines
8.9 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import QtQuick.Controls
|
|
import Quickshell
|
|
import Quickshell.Bluetooth
|
|
import Quickshell.Wayland
|
|
import qs.Commons
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
ColumnLayout {
|
|
id: root
|
|
|
|
property string label: ""
|
|
property string tooltipText: ""
|
|
property var model: {
|
|
|
|
}
|
|
|
|
Layout.fillWidth: true
|
|
spacing: Style.marginM * scaling
|
|
|
|
NText {
|
|
text: root.label
|
|
font.pointSize: Style.fontSizeL * scaling
|
|
color: Color.mSecondary
|
|
font.weight: Style.fontWeightMedium
|
|
Layout.fillWidth: true
|
|
visible: root.model.length > 0
|
|
}
|
|
|
|
Repeater {
|
|
id: deviceList
|
|
Layout.fillWidth: true
|
|
model: root.model
|
|
visible: BluetoothService.adapter && BluetoothService.adapter.enabled
|
|
|
|
Rectangle {
|
|
id: bluetoothDeviceRectangle
|
|
property bool canConnect: BluetoothService.canConnect(modelData)
|
|
property bool canDisconnect: BluetoothService.canDisconnect(modelData)
|
|
property bool isBusy: BluetoothService.isDeviceBusy(modelData)
|
|
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 64 * scaling + (10 * scaling * modelData.batteryAvailable)
|
|
radius: Style.radiusM * scaling
|
|
|
|
color: {
|
|
if (availableDeviceArea.containsMouse){
|
|
if (canDisconnect && !isBusy)
|
|
return Color.mError
|
|
|
|
if(!isBusy)
|
|
return Color.mTertiary
|
|
return Color.mPrimary
|
|
}
|
|
|
|
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
|
return Color.mPrimary
|
|
|
|
if (modelData.blocked )
|
|
return Color.mError
|
|
|
|
return Color.mSurfaceVariant
|
|
}
|
|
border.color: Color.mOutline
|
|
border.width: Math.max(1, Style.borderS * scaling)
|
|
|
|
NTooltip {
|
|
id: tooltip
|
|
target: bluetoothDeviceRectangle
|
|
positionAbove: Settings.data.bar.position === "bottom"
|
|
text: root.tooltipText
|
|
}
|
|
|
|
RowLayout {
|
|
anchors.fill: parent
|
|
anchors.margins: Style.marginM * scaling
|
|
spacing: Style.marginS * scaling
|
|
Layout.alignment: Qt.AlignVCenter
|
|
|
|
// One device BT icon
|
|
NIcon {
|
|
text: BluetoothService.getDeviceIcon(modelData)
|
|
font.pointSize: Style.fontSizeXXL * scaling
|
|
color: {
|
|
if (availableDeviceArea.containsMouse)
|
|
return Color.mOnTertiary
|
|
|
|
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
|
return Color.mOnPrimary
|
|
|
|
if (modelData.blocked)
|
|
return Color.mOnError
|
|
|
|
return Color.mOnSurface
|
|
}
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
spacing: Style.marginXXS * scaling
|
|
|
|
// Device name
|
|
NText {
|
|
text: modelData.name || modelData.deviceName
|
|
font.pointSize: Style.fontSizeM * scaling
|
|
elide: Text.ElideRight
|
|
color: {
|
|
if (availableDeviceArea.containsMouse)
|
|
return Color.mOnTertiary
|
|
|
|
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
|
return Color.mOnPrimary
|
|
|
|
if (modelData.blocked)
|
|
return Color.mOnError
|
|
|
|
return Color.mOnSurface
|
|
}
|
|
font.weight: Style.fontWeightMedium
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
// Signal Strength
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
spacing: Style.marginXS * scaling
|
|
|
|
// Device signal strength - "Unknown" when not connected
|
|
NText {
|
|
text: BluetoothService.getSignalStrength(modelData)
|
|
font.pointSize: Style.fontSizeXS * scaling
|
|
color: {
|
|
if (availableDeviceArea.containsMouse)
|
|
return Color.mOnTertiary
|
|
|
|
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
|
return Color.mOnPrimary
|
|
|
|
if (modelData.blocked)
|
|
return Color.mOnError
|
|
|
|
return Color.mOnSurfaceVariant
|
|
}
|
|
}
|
|
|
|
NIcon {
|
|
text: BluetoothService.getSignalIcon(modelData)
|
|
font.pointSize: Style.fontSizeXS * scaling
|
|
color: {
|
|
if (availableDeviceArea.containsMouse)
|
|
return Color.mOnTertiary
|
|
|
|
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
|
return Color.mOnPrimary
|
|
|
|
if (modelData.blocked)
|
|
return Color.mOnError
|
|
|
|
return Color.mOnSurface
|
|
}
|
|
visible: modelData.signalStrength !== undefined && modelData.signalStrength > 0 && !modelData.pairing
|
|
&& !modelData.blocked
|
|
}
|
|
|
|
NText {
|
|
text: (modelData.signalStrength !== undefined
|
|
&& modelData.signalStrength > 0) ? modelData.signalStrength + "%" : ""
|
|
font.pointSize: Style.fontSizeXS * scaling
|
|
color: {
|
|
if (availableDeviceArea.containsMouse)
|
|
return Color.mOnTertiary
|
|
|
|
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
|
return Color.mOnPrimary
|
|
|
|
if (modelData.blocked)
|
|
return Color.mOnError
|
|
|
|
return Color.mOnSurface
|
|
}
|
|
visible: modelData.signalStrength !== undefined && modelData.signalStrength > 0 && !modelData.pairing
|
|
&& !modelData.blocked
|
|
}
|
|
}
|
|
|
|
NText {
|
|
visible: modelData.batteryAvailable
|
|
text: BluetoothService.getBattery(modelData)
|
|
font.pointSize: Style.fontSizeXS * scaling
|
|
color: {
|
|
if (availableDeviceArea.containsMouse)
|
|
return Color.mOnTertiary
|
|
|
|
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
|
return Color.mOnPrimary
|
|
|
|
if (modelData.blocked)
|
|
return Color.mOnError
|
|
|
|
return Color.mOnSurfaceVariant
|
|
}
|
|
}
|
|
}
|
|
|
|
// Spacer to push connect button to the right
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
|
|
// Call to action
|
|
Rectangle {
|
|
Layout.preferredWidth: 80 * scaling
|
|
Layout.preferredHeight: 28 * scaling
|
|
radius: Style.radiusM * scaling
|
|
visible: (modelData.state !== BluetoothDeviceState.Connecting)
|
|
color: Color.transparent
|
|
|
|
border.color: {
|
|
if (availableDeviceArea.containsMouse) {
|
|
return Color.mOnTertiary
|
|
}
|
|
if (bluetoothDeviceRectangle.canDisconnect && !isBusy) {
|
|
return Color.mError
|
|
}
|
|
return Color.mPrimary
|
|
}
|
|
border.width: Math.max(1, Style.borderS * scaling)
|
|
opacity: canConnect || isBusy || canDisconnect ? 1 : 0.5
|
|
|
|
NText {
|
|
anchors.centerIn: parent
|
|
text: {
|
|
if (modelData.pairing) {
|
|
return "Pairing..."
|
|
}
|
|
if (modelData.blocked) {
|
|
return "Blocked"
|
|
}
|
|
if(modelData.connected){
|
|
return "Disconnect"
|
|
}
|
|
return "Connect"
|
|
}
|
|
font.pointSize: Style.fontSizeXS * scaling
|
|
font.weight: Style.fontWeightMedium
|
|
color: {
|
|
|
|
if (availableDeviceArea.containsMouse) {
|
|
return Color.mOnTertiary
|
|
}
|
|
|
|
if (bluetoothDeviceRectangle.canDisconnect && !isBusy) {
|
|
return Color.mError
|
|
} else {
|
|
return Color.mPrimary
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
|
|
id: availableDeviceArea
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: (canConnect || canDisconnect) && !isBusy ? Qt.PointingHandCursor : (isBusy ? Qt.BusyCursor : Qt.ArrowCursor)
|
|
onEntered: {
|
|
if (root.tooltipText && !isBusy) {
|
|
tooltip.show()
|
|
}
|
|
}
|
|
onExited: {
|
|
if(root.tooltipText && !isBusy) {
|
|
tooltip.hide()
|
|
}
|
|
}
|
|
onClicked: function(mouse) {
|
|
|
|
if (!modelData || modelData.pairing) {
|
|
return
|
|
}
|
|
|
|
if (root.tooltipText && !isBusy) {
|
|
tooltip.hide()
|
|
}
|
|
|
|
|
|
if (mouse.button === Qt.LeftButton){
|
|
if (modelData.connected) {
|
|
BluetoothService.disconnectDevice(modelData)
|
|
} else {
|
|
BluetoothService.connectDeviceWithTrust(modelData)
|
|
}
|
|
} else if (mouse.button === Qt.RightButton) {
|
|
BluetoothService.forgetDevice(modelData)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|