mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-06-08 12:52:24 +00:00
AudioVisualizer: basic implementation
This commit is contained in:
@@ -0,0 +1,140 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import qs.Commons
|
||||||
|
import qs.Modules.Audio
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property ShellScreen screen
|
||||||
|
|
||||||
|
// Widget properties passed from Bar.qml for per-instance settings
|
||||||
|
property string widgetId: ""
|
||||||
|
property string section: ""
|
||||||
|
property int sectionWidgetIndex: -1
|
||||||
|
property int sectionWidgetsCount: 0
|
||||||
|
|
||||||
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
|
property var widgetSettings: {
|
||||||
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
|
var widgets = Settings.data.bar.widgets[section]
|
||||||
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
|
return widgets[sectionWidgetIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve settings: try user settings or defaults from BarWidgetRegistry
|
||||||
|
readonly property int visualizerWidth: widgetSettings.width !== undefined ? widgetSettings.width : widgetMetadata.width
|
||||||
|
|
||||||
|
implicitWidth: visualizerWidth
|
||||||
|
implicitHeight: Style.capsuleHeight
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: background
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Style.radiusS
|
||||||
|
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store visualizer type to force re-evaluation
|
||||||
|
readonly property string currentVisualizerType: Settings.data.audio.visualizerType
|
||||||
|
|
||||||
|
// Timer to delay reload
|
||||||
|
Timer {
|
||||||
|
id: reloadTimer
|
||||||
|
interval: 50
|
||||||
|
onTriggered: {
|
||||||
|
visualizerLoader.active = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force reload when visualizer type changes
|
||||||
|
onCurrentVisualizerTypeChanged: {
|
||||||
|
visualizerLoader.active = false
|
||||||
|
reloadTimer.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Loader dynamically loads the appropriate visualizer based on settings
|
||||||
|
Loader {
|
||||||
|
id: visualizerLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Style.marginS
|
||||||
|
active: false
|
||||||
|
asynchronous: false
|
||||||
|
|
||||||
|
sourceComponent: {
|
||||||
|
switch (currentVisualizerType) {
|
||||||
|
case "linear":
|
||||||
|
return linearComponent
|
||||||
|
case "mirrored":
|
||||||
|
return mirroredComponent
|
||||||
|
case "wave":
|
||||||
|
return waveComponent
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click to cycle through visualizer types
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
|
||||||
|
onClicked: mouse => {
|
||||||
|
console.log("CavaVisualizer clicked! Current type:", currentVisualizerType)
|
||||||
|
const types = ["linear", "mirrored", "wave"]
|
||||||
|
const currentIndex = types.indexOf(currentVisualizerType)
|
||||||
|
const nextIndex = (currentIndex + 1) % types.length
|
||||||
|
const newType = types[nextIndex]
|
||||||
|
|
||||||
|
console.log("Switching from", currentVisualizerType, "to", newType)
|
||||||
|
|
||||||
|
// Update settings directly
|
||||||
|
Settings.data.audio.visualizerType = newType
|
||||||
|
|
||||||
|
console.log("Settings saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial activation on component complete
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (currentVisualizerType !== "" && currentVisualizerType !== "none") {
|
||||||
|
visualizerLoader.active = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: linearComponent
|
||||||
|
LinearSpectrum {
|
||||||
|
anchors.fill: parent
|
||||||
|
values: CavaService.values
|
||||||
|
fillColor: Color.mPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: mirroredComponent
|
||||||
|
MirroredSpectrum {
|
||||||
|
anchors.fill: parent
|
||||||
|
values: CavaService.values
|
||||||
|
fillColor: Color.mPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: waveComponent
|
||||||
|
WaveSpectrum {
|
||||||
|
anchors.fill: parent
|
||||||
|
values: CavaService.values
|
||||||
|
fillColor: Color.mPrimary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -123,6 +123,7 @@ Popup {
|
|||||||
function loadWidgetSettings() {
|
function loadWidgetSettings() {
|
||||||
const widgetSettingsMap = {
|
const widgetSettingsMap = {
|
||||||
"ActiveWindow": "WidgetSettings/ActiveWindowSettings.qml",
|
"ActiveWindow": "WidgetSettings/ActiveWindowSettings.qml",
|
||||||
|
"AudioVisualizer": "WidgetSettings/AudioVisualizerSettings.qml",
|
||||||
"Battery": "WidgetSettings/BatterySettings.qml",
|
"Battery": "WidgetSettings/BatterySettings.qml",
|
||||||
"Bluetooth": "WidgetSettings/BluetoothSettings.qml",
|
"Bluetooth": "WidgetSettings/BluetoothSettings.qml",
|
||||||
"Brightness": "WidgetSettings/BrightnessSettings.qml",
|
"Brightness": "WidgetSettings/BrightnessSettings.qml",
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Commons
|
||||||
|
import qs.Widgets
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
spacing: Style.marginM
|
||||||
|
|
||||||
|
// Properties to receive data from parent
|
||||||
|
property var widgetData: null
|
||||||
|
property var widgetMetadata: null
|
||||||
|
|
||||||
|
function saveSettings() {
|
||||||
|
var settings = Object.assign({}, widgetData || {})
|
||||||
|
settings.width = parseInt(widthInput.text) || widgetMetadata.width
|
||||||
|
return settings
|
||||||
|
}
|
||||||
|
|
||||||
|
NTextInput {
|
||||||
|
id: widthInput
|
||||||
|
Layout.fillWidth: true
|
||||||
|
label: I18n.tr("bar.widget-settings.audio-visualizer.width.label")
|
||||||
|
description: I18n.tr("bar.widget-settings.audio-visualizer.width.description")
|
||||||
|
text: widgetData.width || widgetMetadata.width
|
||||||
|
placeholderText: I18n.tr("placeholders.enter-width-pixels")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ Singleton {
|
|||||||
// Widget registry object mapping widget names to components
|
// Widget registry object mapping widget names to components
|
||||||
property var widgets: ({
|
property var widgets: ({
|
||||||
"ActiveWindow": activeWindowComponent,
|
"ActiveWindow": activeWindowComponent,
|
||||||
|
"AudioVisualizer": audioVisualizerComponent,
|
||||||
"Battery": batteryComponent,
|
"Battery": batteryComponent,
|
||||||
"Bluetooth": bluetoothComponent,
|
"Bluetooth": bluetoothComponent,
|
||||||
"Brightness": brightnessComponent,
|
"Brightness": brightnessComponent,
|
||||||
@@ -49,6 +50,10 @@ Singleton {
|
|||||||
"useFixedWidth": false,
|
"useFixedWidth": false,
|
||||||
"colorizeIcons": false
|
"colorizeIcons": false
|
||||||
},
|
},
|
||||||
|
"AudioVisualizer": {
|
||||||
|
"allowUserSettings": true,
|
||||||
|
"width": 200
|
||||||
|
},
|
||||||
"Battery": {
|
"Battery": {
|
||||||
"allowUserSettings": true,
|
"allowUserSettings": true,
|
||||||
"displayMode": "onhover",
|
"displayMode": "onhover",
|
||||||
@@ -159,6 +164,9 @@ Singleton {
|
|||||||
property Component activeWindowComponent: Component {
|
property Component activeWindowComponent: Component {
|
||||||
ActiveWindow {}
|
ActiveWindow {}
|
||||||
}
|
}
|
||||||
|
property Component audioVisualizerComponent: Component {
|
||||||
|
AudioVisualizer {}
|
||||||
|
}
|
||||||
property Component batteryComponent: Component {
|
property Component batteryComponent: Component {
|
||||||
Battery {}
|
Battery {}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user