extract BluetoothApplet, fold BluetoothMenu into BluetoothModule with hover+pin

This commit is contained in:
Damocles 2026-04-22 21:54:20 +02:00
parent c9c71c0e29
commit 5da7005ce7
4 changed files with 79 additions and 73 deletions

View file

@ -1,46 +1,10 @@
import QtQuick import QtQuick
import Quickshell
import "." as M
import "../services" as S import "../services" as S
M.HoverPanel { Column {
id: menuWindow id: root
contentWidth: 250 required property color accentColor
panelNamespace: "nova-bluetooth"
popupMode: true
panelTitle: "Bluetooth"
titleActionsComponent: Component {
Item {
width: 20
height: 20
Text {
anchors.centerIn: parent
text: "\uF011"
color: S.BluetoothService.enabled ? menuWindow.accentColor : S.Theme.base04
font.pixelSize: S.Theme.fontSize
font.family: S.Theme.iconFontFamily
Behavior on color {
ColorAnimation {
duration: 100
}
}
}
HoverHandler {
cursorShape: Qt.PointingHandCursor
}
TapHandler {
onTapped: S.BluetoothService.setPower(!S.BluetoothService.enabled)
}
}
}
onVisibleChanged: if (visible)
S.BluetoothService.refresh()
Repeater { Repeater {
model: S.BluetoothService.devices model: S.BluetoothService.devices
@ -52,7 +16,7 @@ M.HoverPanel {
readonly property bool _pending: S.BluetoothService.pendingMac === entry.modelData.mac readonly property bool _pending: S.BluetoothService.pendingMac === entry.modelData.mac
width: menuWindow.contentWidth width: root.width
height: 32 height: 32
Rectangle { Rectangle {
@ -69,7 +33,7 @@ M.HoverPanel {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "\uF294" text: "\uF294"
color: entry._pending ? menuWindow.accentColor : entry.modelData.connected ? menuWindow.accentColor : S.Theme.base04 color: entry._pending || entry.modelData.connected ? root.accentColor : S.Theme.base04
font.pixelSize: S.Theme.fontSize + 1 font.pixelSize: S.Theme.fontSize + 1
font.family: S.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
} }
@ -81,7 +45,7 @@ M.HoverPanel {
anchors.rightMargin: 4 anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.name text: entry.modelData.name
color: entry._pending ? menuWindow.accentColor : entry.modelData.connected ? menuWindow.accentColor : S.Theme.base05 color: entry._pending || entry.modelData.connected ? root.accentColor : S.Theme.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: S.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: entry.modelData.connected || entry._pending font.bold: entry.modelData.connected || entry._pending
@ -94,7 +58,7 @@ M.HoverPanel {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry._pending ? (entry.modelData.connected ? "disconnecting..." : "connecting...") : (entry.modelData.battery >= 0 ? entry.modelData.battery + "%" : "") text: entry._pending ? (entry.modelData.connected ? "disconnecting..." : "connecting...") : (entry.modelData.battery >= 0 ? entry.modelData.battery + "%" : "")
color: entry._pending ? S.Theme.base04 : S.Theme.base04 color: S.Theme.base04
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.family: S.Theme.fontFamily font.family: S.Theme.fontFamily
font.italic: entry._pending font.italic: entry._pending
@ -125,10 +89,8 @@ M.HoverPanel {
} }
TapHandler { TapHandler {
onTapped: { onTapped: {
if (!entry._pending) { if (!entry._pending)
S.BluetoothService.toggleDevice(entry.modelData.mac, !entry.modelData.connected); S.BluetoothService.toggleDevice(entry.modelData.mac, !entry.modelData.connected);
menuWindow.keepOpen(500);
}
} }
} }
} }
@ -136,7 +98,7 @@ M.HoverPanel {
Text { Text {
visible: S.BluetoothService.devices.length === 0 visible: S.BluetoothService.devices.length === 0
width: menuWindow.contentWidth width: root.width
height: 32 height: 32
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter

View file

@ -183,9 +183,7 @@ PanelWindow {
M.NetworkModule { M.NetworkModule {
visible: S.Modules.network.enable visible: S.Modules.network.enable
} }
M.BluetoothModule { M.BluetoothModule {}
bar: bar
}
} }
// Controls // Controls

View file

@ -2,18 +2,30 @@ import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C
M.BarSection { M.BarSection {
id: root id: root
spacing: S.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
opacity: S.Modules.bluetooth.enable && S.BluetoothService.state !== "unavailable" ? 1 : 0 opacity: S.Modules.bluetooth.enable && S.BluetoothService.state !== "unavailable" ? 1 : 0
visible: opacity > 0 visible: opacity > 0
tooltip: { tooltip: ""
if (S.BluetoothService.state === "off")
return "Bluetooth: off"; property bool _pinned: false
if (S.BluetoothService.state === "connected") readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
return "Bluetooth: " + S.BluetoothService.device + (S.BluetoothService.batteryPct >= 0 ? "\nBattery: " + S.BluetoothService.batteryPct + "%" : ""); readonly property bool _showPanel: _anyHover || _pinned
return "Bluetooth: on";
on_AnyHoverChanged: {
if (_anyHover)
_unpinTimer.stop();
else if (_pinned)
_unpinTimer.start();
}
Timer {
id: _unpinTimer
interval: 500
onTriggered: root._pinned = false
} }
M.BarIcon { M.BarIcon {
@ -21,10 +33,7 @@ M.BarSection {
color: S.BluetoothService.state === "off" ? S.Theme.base04 : root.accentColor color: S.BluetoothService.state === "off" ? S.Theme.base04 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
TapHandler { TapHandler {
onTapped: { onTapped: root._pinned = !root._pinned
M.FlyoutState.visible = false;
btLoader.active = true;
}
} }
} }
M.BarLabel { M.BarLabel {
@ -32,23 +41,61 @@ M.BarSection {
label: S.BluetoothService.device + (S.BluetoothService.batteryPct >= 0 ? " " + S.BluetoothService.batteryPct + "%" : "") label: S.BluetoothService.device + (S.BluetoothService.batteryPct >= 0 ? " " + S.BluetoothService.batteryPct + "%" : "")
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
TapHandler { TapHandler {
onTapped: { onTapped: root._pinned = !root._pinned
M.FlyoutState.visible = false;
btLoader.active = true;
}
} }
} }
required property var bar M.HoverPanel {
id: hoverPanel
showPanel: root._showPanel
screen: QsWindow.window?.screen ?? null
anchorItem: root
accentColor: root.accentColor
panelNamespace: "nova-bluetooth"
panelTitle: "Bluetooth"
contentWidth: 250
titleActionsComponent: Component {
Item {
width: 20
height: 20
LazyLoader { Text {
id: btLoader anchors.centerIn: parent
active: false text: "\uF011"
M.BluetoothMenu { color: S.BluetoothService.enabled ? hoverPanel.accentColor : S.Theme.base04
font.pixelSize: S.Theme.fontSize
font.family: S.Theme.iconFontFamily
Behavior on color {
ColorAnimation {
duration: 100
}
}
}
HoverHandler {
cursorShape: Qt.PointingHandCursor
}
TapHandler {
onTapped: S.BluetoothService.setPower(!S.BluetoothService.enabled)
}
}
}
onVisibleChanged: if (visible)
S.BluetoothService.refresh()
Connections {
target: S.BluetoothService
function onDevicesChanged() {
hoverPanel.keepOpen(500);
}
}
C.BluetoothApplet {
width: hoverPanel.contentWidth
accentColor: root.accentColor accentColor: root.accentColor
screen: QsWindow.window?.screen ?? null
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)
onDismissed: btLoader.active = false
} }
} }
} }

View file

@ -8,7 +8,6 @@ BarIcon 1.0 BarIcon.qml
BarLabel 1.0 BarLabel.qml BarLabel 1.0 BarLabel.qml
BarSection 1.0 BarSection.qml BarSection 1.0 BarSection.qml
BatteryModule 1.0 BatteryModule.qml BatteryModule 1.0 BatteryModule.qml
BluetoothMenu 1.0 BluetoothMenu.qml
BluetoothModule 1.0 BluetoothModule.qml BluetoothModule 1.0 BluetoothModule.qml
ClockModule 1.0 ClockModule.qml ClockModule 1.0 ClockModule.qml
CpuModule 1.0 CpuModule.qml CpuModule 1.0 CpuModule.qml