diff --git a/Apps/QsDebugger/shell.qml b/Apps/QsDebugger/shell.qml index f656bd9..78fb300 100644 --- a/Apps/QsDebugger/shell.qml +++ b/Apps/QsDebugger/shell.qml @@ -2,6 +2,7 @@ import QtQuick import Quickshell import Quickshell.Widgets import Quickshell.Services.Mpris +import Quickshell.Bluetooth FloatingWindow { title: "Quickshell debugger" @@ -43,6 +44,29 @@ FloatingWindow { font.pixelSize: 32 } + Repeater { + model: Bluetooth.devices + Item { + y: 16 * index + Text { + text: "bt" + index + modelData.name + color: "#04047C" + font.family: "Determination Mono" + font.pixelSize: 16 + y: 64 + 128 + 1 + x: 64 + 1 + 512 + } + Text { + text: "bt" + index + modelData.name + color: "#ff0000" + font.family: "Determination Mono" + font.pixelSize: 16 + y: 64 + 128 + x: 64 + 512 + } + } + } + Repeater { model: Mpris.players Item { @@ -54,7 +78,7 @@ FloatingWindow { asynchronous: true } Text { - text: "mpris" + index + JSON.stringify(modelData.metadata, undefined, "\t") + text: "mpris" + index + JSON.stringify(modelData, undefined, "\t") color: "#04047C" font.family: "Determination Mono" font.pixelSize: 16 @@ -62,7 +86,7 @@ FloatingWindow { x: 64 + 1 } Text { - text: "mpris" + index + JSON.stringify(modelData.metadata, undefined, "\t") + text: "mpris" + index + JSON.stringify(modelData, undefined, "\t") color: "#ff0000" font.family: "Determination Mono" font.pixelSize: 16 diff --git a/Shell/Windows/QuickSettings/QuickSettingsApp.qml b/Shell/Windows/QuickSettings/QuickSettingsApp.qml index 326886d..246bfa0 100644 --- a/Shell/Windows/QuickSettings/QuickSettingsApp.qml +++ b/Shell/Windows/QuickSettings/QuickSettingsApp.qml @@ -1,4 +1,5 @@ import QtQuick +import Quickshell.Bluetooth import Quickshell.Services.Pipewire import "../.." @@ -28,6 +29,7 @@ Item { property ShellStateManager manager: null property int activeSelection: 0 + property bool inBluetoothMenu: false property bool isSelected: false @@ -35,20 +37,75 @@ Item { return Math.max(lo, Math.min(hi, v)); } - function wrapIndex(i) { - if (actions.length === 0) + function menuLength() { + if (!menuModel) return 0; - return (i + actions.length) % actions.length; + if (menuModel.count !== undefined) + return menuModel.count; + if (menuModel.length !== undefined) + return menuModel.length; + return 0; + } + + function menuAt(index) { + if (!menuModel) + return null; + if (menuModel.get) + return menuModel.get(index); + if (menuModel.length !== undefined) + return menuModel[index]; + return null; + } + + function wrapIndex(i) { + const length = menuLength(); + if (length === 0) + return 0; + return (i + length) % length; } function currentAction() { - return actions.length > 0 ? actions[activeSelection] : null; + if (root.inBluetoothMenu) + return null; + return menuLength() > 0 ? menuAt(activeSelection) : null; + } + + function clampSelection() { + const length = menuLength(); + if (length === 0) { + activeSelection = 0; + return; + } + activeSelection = clamp(activeSelection, 0, length - 1); + } + + function bluetoothDisplayName(device) { + if (!device) + return ""; + if (device.name && device.name.length > 0) + return device.name; + return device.deviceName || ""; + } + + function bluetoothDisplayState(device) { + if (!device) + return ""; + // dont change symbols + return device.connected ? "✓" : ""; + } + + function bluetoothDeviceAt(index) { + const item = bluetoothRepeater.itemAt(index); + if (!item) + return null; + return item.device || null; } PwObjectTracker { objects: [Pipewire.defaultAudioSink] } + property int bluetoothActionIndex: 1 property var actions: [ { name: "Master Volume", @@ -68,17 +125,44 @@ Item { } }, { - name: "Controls", - ent: function () {}, + name: "Bluetooth", + ent: function () { + root.inBluetoothMenu = true; + root.isSelected = false; + root.activeSelection = 0; + root.clampSelection(); + }, getState: function () { - console.log("deltarune tommorow"); return ""; } } ] + property var menuModel: root.inBluetoothMenu ? Bluetooth.devices : actions + + Connections { + target: Bluetooth.devices + ignoreUnknownSignals: true + function onCountChanged() { + if (root.inBluetoothMenu) + root.clampSelection(); + } + function onModelReset() { + if (root.inBluetoothMenu) + root.clampSelection(); + } + function onRowsInserted() { + if (root.inBluetoothMenu) + root.clampSelection(); + } + function onRowsRemoved() { + if (root.inBluetoothMenu) + root.clampSelection(); + } + } + Text { - text: "CONFIG" + text: root.inBluetoothMenu ? "BLUETOOTH" : "CONFIG" font.family: "8bitoperator JVE" font.pixelSize: 71 renderType: Text.NativeRendering @@ -91,7 +175,8 @@ Item { } Repeater { - model: root.actions + id: bluetoothRepeater + model: root.menuModel delegate: Item { width: root.width @@ -99,6 +184,8 @@ Item { x: 0 y: menuTop + index * lineHeight + property var device: root.inBluetoothMenu ? modelData : null + Image { source: "./soul.png" width: 36 @@ -111,7 +198,7 @@ Item { Text { x: 239 y: 0 - text: modelData.name + text: root.inBluetoothMenu ? root.bluetoothDisplayName(modelData) : modelData.name font.family: "8bitoperator JVE" font.pixelSize: 71 font.letterSpacing: 1 @@ -126,7 +213,7 @@ Item { Text { x: menuLeft + stateColumnX y: 4 - text: modelData.getState ? modelData.getState() : "" + text: root.inBluetoothMenu ? root.bluetoothDisplayState(modelData) : (modelData.getState ? modelData.getState() : "") font.family: "8bitoperator JVE" font.pixelSize: 71 font.letterSpacing: 1 @@ -146,11 +233,11 @@ Item { function handleKey(key) { switch (key) { case Qt.Key_Up: - if (root.isSelected === false) + if (root.inBluetoothMenu || root.isSelected === false) activeSelection = wrapIndex(activeSelection - 1); return true; case Qt.Key_Down: - if (root.isSelected === false) + if (root.inBluetoothMenu || root.isSelected === false) activeSelection = wrapIndex(activeSelection + 1); return true; case Qt.Key_Left: @@ -171,18 +258,36 @@ Item { case Qt.Key_Return: case Qt.Key_Enter: { - const a = currentAction(); - if (a && a.ent) { - a.ent(); + if (root.inBluetoothMenu) { + const device = bluetoothDeviceAt(activeSelection); + console.log(root.inBluetoothMenu, activeSelection, device); + if (device) { + if (!device.connected) { + device.connect(); + } else { + device.disconnect(); + } + // device.connected = !device.connected; + } } else { - root.isSelected = !root.isSelected; + const a = currentAction(); + if (a && a.ent) { + a.ent(); + } else { + root.isSelected = !root.isSelected; + } } return true; } case Qt.Key_X: case Qt.Key_Shift: case Qt.Key_Escape: - if (root.isSelected === true) { + if (root.inBluetoothMenu) { + root.inBluetoothMenu = false; + root.isSelected = false; + root.activeSelection = root.bluetoothActionIndex; + root.clampSelection(); + } else if (root.isSelected === true) { root.isSelected = false; } else { if (manager && manager.closeQuickSettings) { @@ -197,6 +302,7 @@ Item { Component.onCompleted: { root.activeSelection = 0; root.isSelected = false; + root.inBluetoothMenu = false; ShellInputManager.registerHandler("quickSettings", handleKey); }