Bluetooth Panel: UI cleanup/factorization

This commit is contained in:
LemmyCook 2025-09-04 23:26:19 -04:00
parent 5910c65bcf
commit cc8a24f445
5 changed files with 135 additions and 187 deletions

View file

@ -21,6 +21,6 @@ NIconButton {
colorBorderHover: Color.transparent
icon: "bluetooth"
tooltipText: "Bluetooth devices"
tooltipText: "Bluetooth"
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(screen, this)
}

View file

@ -132,7 +132,6 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Row {

View file

@ -36,65 +36,39 @@ ColumnLayout {
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)
id: device
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
}
readonly property bool canConnect: BluetoothService.canConnect(modelData)
readonly property bool canDisconnect: BluetoothService.canDisconnect(modelData)
readonly property bool isBusy: BluetoothService.isDeviceBusy(modelData)
function getContentColor(defaultColor = Color.mOnSurface) {
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
return Color.mPrimary
if (modelData.blocked)
return Color.mError
return Color.mSurfaceVariant
return defaultColor
}
border.color: Color.mOutline
Layout.fillWidth: true
Layout.preferredHeight: deviceLayout.implicitHeight + (Style.marginM * scaling * 2)
radius: Style.radiusM * scaling
color: Color.mSurface
border.width: Math.max(1, Style.borderS * scaling)
NTooltip {
id: tooltip
target: bluetoothDeviceRectangle
positionAbove: Settings.data.bar.position === "bottom"
text: root.tooltipText
}
border.color: getContentColor(Color.mOutline)
RowLayout {
id: deviceLayout
anchors.fill: parent
anchors.margins: Style.marginM * scaling
spacing: Style.marginS * scaling
spacing: Style.marginM * 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
}
color: getContentColor(Color.mOnSurface)
Layout.alignment: Qt.AlignVCenter
}
@ -106,25 +80,23 @@ ColumnLayout {
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
elide: Text.ElideRight
color: getContentColor(Color.mOnSurface)
Layout.fillWidth: true
}
// Status
NText {
text: BluetoothService.getStatusString(modelData)
visible: text !== ""
font.pointSize: Style.fontSizeXS * scaling
color: getContentColor(Color.mOnSurfaceVariant)
}
// Signal Strength
RowLayout {
visible: modelData.signalStrength !== undefined
Layout.fillWidth: true
spacing: Style.marginXS * scaling
@ -132,76 +104,32 @@ ColumnLayout {
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
}
color: getContentColor(Color.mOnSurfaceVariant)
}
NIcon {
visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
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
color: getContentColor(Color.mOnSurface)
}
NText {
visible: modelData.signalStrength > 0 && !modelData.pairing
&& !modelData.blocked
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
color: getContentColor(Color.mOnSurface)
}
}
// Battery
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
}
color: getContentColor(Color.mOnSurfaceVariant)
}
}
@ -211,96 +139,86 @@ ColumnLayout {
}
// Call to action
Rectangle {
Layout.preferredWidth: 80 * scaling
Layout.preferredHeight: 28 * scaling
radius: Style.radiusM * scaling
NButton {
id: button
visible: (modelData.state !== BluetoothDeviceState.Connecting)
color: Color.transparent
border.color: {
if (availableDeviceArea.containsMouse) {
return Color.mOnTertiary
}
if (bluetoothDeviceRectangle.canDisconnect && !isBusy) {
enabled: (canConnect || canDisconnect) && !isBusy
outlined: !button.hovered
fontSize: Style.fontSizeXS * scaling
fontWeight: Style.fontWeightMedium
backgroundColor: {
if (device.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"
tooltipText: root.tooltipText
text: {
if (modelData.pairing) {
return "Pairing..."
}
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
}
if (modelData.blocked) {
return "Blocked"
}
if (modelData.connected) {
return "Disconnect"
}
return "Connect"
}
}
}
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) {
icon: (isBusy ? "hourglass_full" : null)
onClicked: {
if (modelData.connected) {
BluetoothService.disconnectDevice(modelData)
} else {
BluetoothService.connectDeviceWithTrust(modelData)
}
} else if (mouse.button === Qt.RightButton) {
}
}
onRightClicked:
{
BluetoothService.forgetDevice(modelData)
}
}
}
// 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)
// }
// }
// }
}
}
}

View file

@ -107,13 +107,21 @@ Singleton {
return device.connected && !device.pairing && !device.blocked
}
function getSignalStrength(device) {
function getStatusString(device) {
if (device.state === BluetoothDeviceState.Connecting) {
return "Connecting..."
}
if (device.pairing) {
return "Pairing..."
}
if (device.blocked) {
return "Blocked"
}
return ""
}
function getSignalStrength(device) {
if (!device || device.signalStrength === undefined || device.signalStrength <= 0) {
return "Signal: Unknown"
}

View file

@ -9,13 +9,15 @@ Rectangle {
// Public properties
property string text: ""
property string icon: ""
property string tooltipText
property color backgroundColor: Color.mPrimary
property color textColor: Color.mOnPrimary
property color hoverColor: Color.mTertiary
property color pressColor: Color.mSecondary
property bool enabled: true
property int fontSize: Style.fontSizeM * scaling
property int iconSize: Style.fontSizeL * scaling
property real fontSize: Style.fontSizeM * scaling
property int fontWeight: Style.fontWeightBold
property real iconSize: Style.fontSizeL * scaling
property bool outlined: false
property real customWidth: -1
property real customHeight: -1
@ -106,7 +108,7 @@ Rectangle {
visible: root.text !== ""
text: root.text
font.pointSize: root.fontSize
font.weight: Style.fontWeightBold
font.weight: root.fontWeight
color: {
if (!root.enabled)
return Color.mOnSurfaceVariant
@ -127,6 +129,13 @@ Rectangle {
}
}
NTooltip {
id: tooltip
target: root
positionAbove: Settings.data.bar.position === "bottom"
text: root.tooltipText
}
// Mouse interaction
MouseArea {
id: mouseArea
@ -136,16 +145,27 @@ Rectangle {
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onEntered: root.hovered = true
onEntered: {
root.hovered = true
if (tooltipText) {
tooltip.show()
}
}
onExited: {
root.hovered = false
root.pressed = false
if (tooltipText) {
tooltip.hide()
}
}
onPressed: mouse => {
root.pressed = true
}
onReleased: mouse => {
root.pressed = false
if (tooltipText) {
tooltip.hide()
}
if (!root.hovered) {
return
}
@ -161,6 +181,9 @@ Rectangle {
onCanceled: {
root.pressed = false
root.hovered = false
if (tooltipText) {
tooltip.hide()
}
}
}
}