summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml
diff options
context:
space:
mode:
authorAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
committerAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
commit70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch)
treeab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml
parent5d94c0a7d44a2255b81815a52a7056a94a39842d (diff)
downloadRaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.tar.gz
RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.zip
Replaced file structures for themes in the correct format
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml332
1 files changed, 332 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml
new file mode 100644
index 0000000..0cad08c
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Details/BluetoothCodecSelector.qml
@@ -0,0 +1,332 @@
+import QtQuick
+import qs.Common
+import qs.Services
+import qs.Widgets
+
+Item {
+ id: root
+
+ LayoutMirroring.enabled: I18n.isRtl
+ LayoutMirroring.childrenInherit: true
+
+ property var device: null
+ property bool modalVisible: false
+ property var parentItem
+ property var availableCodecs: []
+ property string currentCodec: ""
+ property bool isLoading: false
+
+ readonly property bool deviceValid: device !== null && device.connected && BluetoothService.isAudioDevice(device)
+
+ signal codecSelected(string deviceAddress, string codecName)
+
+ function show(bluetoothDevice) {
+ if (!bluetoothDevice?.connected)
+ return;
+ if (!BluetoothService.isAudioDevice(bluetoothDevice))
+ return;
+ device = bluetoothDevice;
+ isLoading = true;
+ availableCodecs = [];
+ currentCodec = "";
+ visible = true;
+ modalVisible = true;
+ queryCodecs();
+ Qt.callLater(() => {
+ focusScope.forceActiveFocus();
+ });
+ }
+
+ function hide() {
+ modalVisible = false;
+ Qt.callLater(() => {
+ visible = false;
+ device = null;
+ });
+ }
+
+ function queryCodecs() {
+ if (!deviceValid) {
+ hide();
+ return;
+ }
+
+ const capturedDevice = device;
+ const capturedAddress = device.address;
+
+ BluetoothService.getAvailableCodecs(capturedDevice, function (codecs, current) {
+ if (!root.deviceValid || root.device?.address !== capturedAddress)
+ return;
+ availableCodecs = codecs;
+ currentCodec = current;
+ isLoading = false;
+ });
+ }
+
+ function selectCodec(profileName) {
+ if (!deviceValid || isLoading)
+ return;
+
+ const capturedDevice = device;
+ const capturedAddress = device.address;
+
+ const selectedCodec = availableCodecs.find(c => c.profile === profileName);
+ if (!selectedCodec)
+ return;
+
+ BluetoothService.updateDeviceCodec(capturedAddress, selectedCodec.name);
+ codecSelected(capturedAddress, selectedCodec.name);
+
+ isLoading = true;
+ BluetoothService.switchCodec(capturedDevice, profileName, function (success, message) {
+ if (!root.device || root.device.address !== capturedAddress)
+ return;
+
+ isLoading = false;
+ if (success) {
+ ToastService.showToast(message, ToastService.levelInfo);
+ Qt.callLater(root.hide);
+ return;
+ }
+ ToastService.showToast(message, ToastService.levelError);
+ });
+ }
+
+ onDeviceValidChanged: {
+ if (modalVisible && !deviceValid) {
+ hide();
+ }
+ }
+
+ visible: false
+ anchors.fill: parent
+ z: 2000
+
+ MouseArea {
+ id: modalBlocker
+ anchors.fill: parent
+ visible: modalVisible
+ enabled: modalVisible
+ hoverEnabled: true
+ preventStealing: true
+ propagateComposedEvents: false
+
+ onClicked: root.hide()
+ onWheel: wheel => {
+ wheel.accepted = true;
+ }
+ onPositionChanged: mouse => {
+ mouse.accepted = true;
+ }
+ }
+
+ Rectangle {
+ id: modalBackground
+ anchors.fill: parent
+ color: Qt.rgba(0, 0, 0, 0.5)
+ opacity: modalVisible ? 1 : 0
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: Theme.mediumDuration
+ easing.type: Theme.emphasizedEasing
+ }
+ }
+ }
+
+ FocusScope {
+ id: focusScope
+
+ anchors.fill: parent
+ focus: root.visible
+ enabled: root.visible
+
+ Keys.onEscapePressed: {
+ root.hide();
+ event.accepted = true;
+ }
+ }
+
+ Rectangle {
+ id: modalContent
+ anchors.centerIn: parent
+ width: 320
+ height: contentColumn.implicitHeight + Theme.spacingL * 2
+ radius: Theme.cornerRadius
+ color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
+ border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
+ border.width: 0
+ opacity: modalVisible ? 1 : 0
+ scale: modalVisible ? 1 : 0.9
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ preventStealing: true
+ propagateComposedEvents: false
+ onClicked: mouse => {
+ mouse.accepted = true;
+ }
+ onWheel: wheel => {
+ wheel.accepted = true;
+ }
+ onPositionChanged: mouse => {
+ mouse.accepted = true;
+ }
+ }
+
+ Column {
+ id: contentColumn
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.margins: Theme.spacingL
+ spacing: Theme.spacingM
+
+ Row {
+ width: parent.width
+ spacing: Theme.spacingM
+
+ DankIcon {
+ name: device ? BluetoothService.getDeviceIcon(device) : "headset"
+ size: Theme.iconSize + 4
+ color: Theme.primary
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Column {
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: 2
+
+ StyledText {
+ text: device ? (device.name || device.deviceName) : ""
+ font.pixelSize: Theme.fontSizeLarge
+ color: Theme.surfaceText
+ font.weight: Font.Medium
+ }
+
+ StyledText {
+ text: I18n.tr("Audio Codec Selection")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceTextMedium
+ }
+ }
+ }
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
+ }
+
+ StyledText {
+ text: isLoading ? I18n.tr("Loading codecs...") : I18n.tr("Current: %1").arg(currentCodec)
+ font.pixelSize: Theme.fontSizeSmall
+ color: isLoading ? Theme.primary : Theme.surfaceTextMedium
+ font.weight: Font.Medium
+ }
+
+ Column {
+ width: parent.width
+ spacing: Theme.spacingXS
+ visible: !isLoading
+
+ Repeater {
+ model: availableCodecs
+
+ Rectangle {
+ width: parent.width
+ height: 48
+ radius: Theme.cornerRadius
+ color: {
+ if (modelData.name === currentCodec)
+ return Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency);
+ else if (codecMouseArea.containsMouse)
+ return Theme.surfaceHover;
+ else
+ return "transparent";
+ }
+ border.color: "transparent"
+ border.width: 0
+
+ Row {
+ anchors.left: parent.left
+ anchors.leftMargin: Theme.spacingM
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: Theme.spacingS
+
+ Rectangle {
+ width: 6
+ height: 6
+ radius: 3
+ color: modelData.qualityColor
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Column {
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: 2
+
+ StyledText {
+ text: modelData.name
+ font.pixelSize: Theme.fontSizeMedium
+ color: modelData.name === currentCodec ? Theme.primary : Theme.surfaceText
+ font.weight: modelData.name === currentCodec ? Font.Medium : Font.Normal
+ }
+
+ StyledText {
+ text: modelData.description
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceTextMedium
+ }
+ }
+ }
+
+ DankIcon {
+ name: "check"
+ size: Theme.iconSize - 4
+ color: Theme.primary
+ anchors.right: parent.right
+ anchors.rightMargin: Theme.spacingM
+ anchors.verticalCenter: parent.verticalCenter
+ visible: modelData.name === currentCodec
+ }
+
+ DankRipple {
+ id: codecRipple
+ cornerRadius: parent.radius
+ }
+
+ MouseArea {
+ id: codecMouseArea
+
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ enabled: modelData.name !== currentCodec && !isLoading
+ onPressed: mouse => codecRipple.trigger(mouse.x, mouse.y)
+ onClicked: {
+ selectCodec(modelData.profile);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: Theme.mediumDuration
+ easing.type: Theme.emphasizedEasing
+ }
+ }
+
+ Behavior on scale {
+ NumberAnimation {
+ duration: Theme.mediumDuration
+ easing.type: Theme.emphasizedEasing
+ }
+ }
+ }
+}