diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index c99cfda..462b8c6 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -23,6 +23,10 @@ Variants { implicitHeight: Style.barHeight * scaling color: Color.transparent + Component.onCompleted: { + logWidgetLoadingSummary() + } + // If no bar activated in settings, then show them all visible: modelData ? (Settings.data.bar.monitors.includes(modelData.name) || (Settings.data.bar.monitors.length === 0)) : false @@ -66,9 +70,10 @@ Variants { anchors.verticalCenter: parent.verticalCenter onStatusChanged: { if (status === Loader.Error) { - console.warn(`Failed to load widget: ${modelData}`) + Logger.error("Bar", `Failed to load ${modelData} widget`) + onWidgetFailed() } else if (status === Loader.Ready) { - console.log(`Successfully loaded widget: ${modelData}`) + onWidgetLoaded() } } } @@ -93,9 +98,10 @@ Variants { anchors.verticalCenter: parent.verticalCenter onStatusChanged: { if (status === Loader.Error) { - console.warn(`Failed to load widget: ${modelData}`) + Logger.error("Bar", `Failed to load ${modelData} widget`) + onWidgetFailed() } else if (status === Loader.Ready) { - console.log(`Successfully loaded widget: ${modelData}`) + onWidgetLoaded() } } } @@ -121,9 +127,10 @@ Variants { anchors.verticalCenter: parent.verticalCenter onStatusChanged: { if (status === Loader.Error) { - console.warn(`Failed to load widget: ${modelData}`) + Logger.error("Bar", `Failed to load ${modelData} widget`) + onWidgetFailed() } else if (status === Loader.Ready) { - console.log(`Successfully loaded widget: ${modelData}`) + onWidgetLoaded() } } } @@ -137,19 +144,56 @@ Variants { return null } - console.log(`Attempting to load widget: ${widgetName}.qml`) + const widgetPath = `../Bar/Widgets/${widgetName}.qml` + Logger.log("Bar", `Attempting to load widget from: ${widgetPath}`) // Try to load the widget directly from file - const component = Qt.createComponent(`../Bar/Widgets/${widgetName}.qml`) + const component = Qt.createComponent(widgetPath) if (component.status === Component.Ready) { - console.log(`Successfully created component for: ${widgetName}.qml`) + Logger.log("Bar", `Successfully created component for: ${widgetName}.qml`) return component } - console.warn(`Failed to load widget: ${widgetName}.qml, status:`, component.status, "error:", component.errorString()) + Logger.error("Bar", `Failed to load ${widgetName}.qml widget, status: ${component.status}, error: ${component.errorString()}`) return null } + // Track widget loading status + property int totalWidgets: 0 + property int loadedWidgets: 0 + property int failedWidgets: 0 + + // Log widget loading summary + function logWidgetLoadingSummary() { + const allWidgets = [ + ...Settings.data.bar.widgets.left, + ...Settings.data.bar.widgets.center, + ...Settings.data.bar.widgets.right + ] + + totalWidgets = allWidgets.length + loadedWidgets = 0 + failedWidgets = 0 + + if (totalWidgets > 0) { + Logger.log("Bar", `Attempting to load ${totalWidgets} widgets`) + } + } + + function onWidgetLoaded() { + loadedWidgets++ + if (loadedWidgets + failedWidgets === totalWidgets) { + Logger.log("Bar", `Loaded ${loadedWidgets}/${totalWidgets} widgets`) + } + } + + function onWidgetFailed() { + failedWidgets++ + if (loadedWidgets + failedWidgets === totalWidgets) { + Logger.log("Bar", `Loaded ${loadedWidgets}/${totalWidgets} widgets`) + } + } + diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml index 09c5c60..90b8dee 100644 --- a/Modules/Bar/Widgets/Bluetooth.qml +++ b/Modules/Bar/Widgets/Bluetooth.qml @@ -7,6 +7,7 @@ import qs.Commons import qs.Services import qs.Widgets + NIconButton { id: root @@ -32,7 +33,30 @@ NIconButton { bluetoothPanel.toggle(screen) } - BluetoothPanel { + Loader { id: bluetoothPanel + source: "BluetoothPanel.qml" + active: false + + property var pendingToggleScreen: null + + onStatusChanged: { + if (status === Loader.Ready && item && pendingToggleScreen !== null) { + item.toggle(pendingToggleScreen) + pendingToggleScreen = null + } + } + + function toggle(screen) { + // Load the panel if it's not already loaded + if (!active) { + active = true + pendingToggleScreen = screen + } else if (status === Loader.Ready && item) { + item.toggle(screen) + } else { + pendingToggleScreen = screen + } + } } } diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml index cdae9be..61a6a13 100644 --- a/Modules/Bar/Widgets/WiFi.qml +++ b/Modules/Bar/Widgets/WiFi.qml @@ -7,34 +7,76 @@ import qs.Commons import qs.Services import qs.Widgets + NIconButton { id: root sizeMultiplier: 0.8 + Component.onCompleted: { + Logger.log("WiFi", "Widget component completed") + Logger.log("WiFi", "NetworkService available:", !!NetworkService) + if (NetworkService) { + Logger.log("WiFi", "NetworkService.networks available:", !!NetworkService.networks) + } + } + colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface colorBorder: Color.transparent colorBorderHover: Color.transparent icon: { - let connected = false - let signalStrength = 0 - for (const net in NetworkService.networks) { - if (NetworkService.networks[net].connected) { - connected = true - signalStrength = NetworkService.networks[net].signal - break + try { + let connected = false + let signalStrength = 0 + for (const net in NetworkService.networks) { + if (NetworkService.networks[net].connected) { + connected = true + signalStrength = NetworkService.networks[net].signal + break + } } + return connected ? NetworkService.signalIcon(signalStrength) : "wifi" + } catch (error) { + Logger.error("WiFi", "Error getting icon:", error) + return "wifi" } - return connected ? NetworkService.signalIcon(signalStrength) : "wifi" } tooltipText: "WiFi Networks" onClicked: { - wifiPanel.toggle(screen) + try { + Logger.log("WiFi", "Button clicked, toggling panel") + wifiPanel.toggle(screen) + } catch (error) { + Logger.error("WiFi", "Error toggling panel:", error) + } } - WiFiPanel { + Loader { id: wifiPanel + source: "WiFiPanel.qml" + active: false + + property var pendingToggleScreen: null + + onStatusChanged: { + if (status === Loader.Ready && item && pendingToggleScreen !== null) { + item.toggle(pendingToggleScreen) + pendingToggleScreen = null + } + } + + function toggle(screen) { + // Load the panel if it's not already loaded + if (!active) { + active = true + pendingToggleScreen = screen + } else if (status === Loader.Ready && item) { + item.toggle(screen) + } else { + pendingToggleScreen = screen + } + } } } diff --git a/Modules/SettingsPanel/Tabs/BarTab.qml b/Modules/SettingsPanel/Tabs/BarTab.qml index 307db25..a44e908 100644 --- a/Modules/SettingsPanel/Tabs/BarTab.qml +++ b/Modules/SettingsPanel/Tabs/BarTab.qml @@ -166,15 +166,15 @@ ColumnLayout { Layout.fillWidth: true Layout.minimumHeight: { var widgetCount = Settings.data.bar.widgets.left.length - if (widgetCount === 0) return 120 * scaling + if (widgetCount === 0) return 140 * scaling var availableWidth = scrollView.availableWidth - (Style.marginM * scaling * 2) // Card margins var avgWidgetWidth = 150 * scaling // Estimated widget width including spacing var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth)) var rows = Math.ceil(widgetCount / widgetsPerRow) - // Header (40) + spacing (16) + (rows * widget height) + (rows-1 * spacing) + bottom margin (16) - return (40 + 16 + (rows * 48) + ((rows - 1) * Style.marginS) + 16) * scaling + // Header (50) + spacing (20) + (rows * widget height) + (rows-1 * spacing) + bottom margin (20) + return (50 + 20 + (rows * 48) + ((rows - 1) * Style.marginS) + 20) * scaling } ColumnLayout { @@ -194,28 +194,14 @@ ColumnLayout { Item { Layout.fillWidth: true } - Rectangle { - width: 32 * scaling - height: 32 * scaling - radius: width * 0.5 - color: Color.mPrimary - border.color: Color.mPrimary - border.width: 2 * scaling - - NIcon { - anchors.centerIn: parent - text: "add" - color: Color.mOnPrimary - font.pointSize: Style.fontSizeM * scaling - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - addWidgetDialog.show("left") - } + NComboBox { + width: 120 * scaling + model: availableWidgets + label: "" + description: "" + placeholder: "Add widget to left section" + onSelected: key => { + addWidgetToSection(key, "left") } } } @@ -224,7 +210,7 @@ ColumnLayout { id: leftWidgetsFlow Layout.fillWidth: true Layout.fillHeight: true - Layout.minimumHeight: 52 * scaling + Layout.minimumHeight: 65 * scaling spacing: Style.marginS * scaling flow: Flow.LeftToRight @@ -303,15 +289,15 @@ ColumnLayout { Layout.fillWidth: true Layout.minimumHeight: { var widgetCount = Settings.data.bar.widgets.center.length - if (widgetCount === 0) return 120 * scaling + if (widgetCount === 0) return 140 * scaling var availableWidth = scrollView.availableWidth - (Style.marginM * scaling * 2) // Card margins var avgWidgetWidth = 150 * scaling // Estimated widget width including spacing var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth)) var rows = Math.ceil(widgetCount / widgetsPerRow) - // Header (40) + spacing (16) + (rows * widget height) + (rows-1 * spacing) + bottom margin (16) - return (40 + 16 + (rows * 48) + ((rows - 1) * Style.marginS) + 16) * scaling + // Header (50) + spacing (20) + (rows * widget height) + (rows-1 * spacing) + bottom margin (20) + return (50 + 20 + (rows * 48) + ((rows - 1) * Style.marginS) + 20) * scaling } ColumnLayout { @@ -331,28 +317,14 @@ ColumnLayout { Item { Layout.fillWidth: true } - Rectangle { - width: 32 * scaling - height: 32 * scaling - radius: width * 0.5 - color: Color.mPrimary - border.color: Color.mPrimary - border.width: 2 * scaling - - NIcon { - anchors.centerIn: parent - text: "add" - color: Color.mOnPrimary - font.pointSize: Style.fontSizeM * scaling - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - addWidgetDialog.show("center") - } + NComboBox { + width: 120 * scaling + model: availableWidgets + label: "" + description: "" + placeholder: "Add widget to center section" + onSelected: key => { + addWidgetToSection(key, "center") } } } @@ -361,7 +333,7 @@ ColumnLayout { id: centerWidgetsFlow Layout.fillWidth: true Layout.fillHeight: true - Layout.minimumHeight: 52 * scaling + Layout.minimumHeight: 65 * scaling spacing: Style.marginS * scaling flow: Flow.LeftToRight @@ -440,15 +412,15 @@ ColumnLayout { Layout.fillWidth: true Layout.minimumHeight: { var widgetCount = Settings.data.bar.widgets.right.length - if (widgetCount === 0) return 120 * scaling + if (widgetCount === 0) return 140 * scaling var availableWidth = scrollView.availableWidth - (Style.marginM * scaling * 2) // Card margins var avgWidgetWidth = 150 * scaling // Estimated widget width including spacing var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth)) var rows = Math.ceil(widgetCount / widgetsPerRow) - // Header (40) + spacing (16) + (rows * widget height) + (rows-1 * spacing) + bottom margin (16) - return (40 + 16 + (rows * 48) + ((rows - 1) * Style.marginS) + 16) * scaling + // Header (50) + spacing (20) + (rows * widget height) + (rows-1 * spacing) + bottom margin (20) + return (50 + 20 + (rows * 48) + ((rows - 1) * Style.marginS) + 20) * scaling } ColumnLayout { @@ -468,28 +440,14 @@ ColumnLayout { Item { Layout.fillWidth: true } - Rectangle { - width: 32 * scaling - height: 32 * scaling - radius: width * 0.5 - color: Color.mPrimary - border.color: Color.mPrimary - border.width: 2 * scaling - - NIcon { - anchors.centerIn: parent - text: "add" - color: Color.mOnPrimary - font.pointSize: Style.fontSizeM * scaling - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - addWidgetDialog.show("right") - } + NComboBox { + width: 120 * scaling + model: availableWidgets + label: "" + description: "" + placeholder: "Add widget to right section" + onSelected: key => { + addWidgetToSection(key, "right") } } } @@ -498,7 +456,7 @@ ColumnLayout { id: rightWidgetsFlow Layout.fillWidth: true Layout.fillHeight: true - Layout.minimumHeight: 52 * scaling + Layout.minimumHeight: 65 * scaling spacing: Style.marginS * scaling flow: Flow.LeftToRight @@ -577,144 +535,7 @@ ColumnLayout { } } - // Add Widget Dialog - Rectangle { - id: addWidgetDialog - anchors.fill: parent - color: Color.applyOpacity(Color.mShadow, "80") - visible: false - z: 1000 - property string targetSection: "" - - function show(section) { - targetSection = section - visible = true - } - - function hide() { - visible = false - targetSection = "" - } - - MouseArea { - anchors.fill: parent - onClicked: addWidgetDialog.hide() - } - - Rectangle { - anchors.centerIn: parent - width: 400 * scaling - height: 500 * scaling - radius: Style.radiusL * scaling - color: Color.mSurface - border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - - ColumnLayout { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.margins: Style.marginL * scaling - spacing: Style.marginM * scaling - - NText { - text: "Add Widget to " + (addWidgetDialog.targetSection === "left" ? "Left" : - addWidgetDialog.targetSection === "center" ? "Center" : "Right") + " Section" - font.pointSize: Style.fontSizeL * scaling - font.weight: Style.fontWeightBold - color: Color.mOnSurface - Layout.fillWidth: true - } - - ListView { - Layout.fillWidth: true - Layout.fillHeight: true - clip: true - spacing: Style.marginXS * scaling - - model: ListModel { - ListElement { name: "SystemMonitor"; icon: "memory"; description: "System statistics" } - ListElement { name: "ActiveWindow"; icon: "web_asset"; description: "Active window title" } - ListElement { name: "MediaMini"; icon: "music_note"; description: "Media controls" } - ListElement { name: "Workspace"; icon: "dashboard"; description: "Workspace switcher" } - ListElement { name: "ScreenRecorderIndicator"; icon: "videocam"; description: "Recording indicator" } - ListElement { name: "Tray"; icon: "apps"; description: "System tray" } - ListElement { name: "NotificationHistory"; icon: "notifications"; description: "Notification history" } - ListElement { name: "WiFi"; icon: "wifi"; description: "WiFi status" } - ListElement { name: "Bluetooth"; icon: "bluetooth"; description: "Bluetooth status" } - ListElement { name: "Battery"; icon: "battery_full"; description: "Battery status" } - ListElement { name: "Volume"; icon: "volume_up"; description: "Volume control" } - ListElement { name: "Brightness"; icon: "brightness_6"; description: "Brightness control" } - ListElement { name: "Clock"; icon: "schedule"; description: "Clock" } - ListElement { name: "SidePanelToggle"; icon: "widgets"; description: "Side panel toggle" } - } - - delegate: Rectangle { - width: ListView.view.width - height: 48 * scaling - radius: Style.radiusS * scaling - color: mouseArea.containsMouse ? Color.mTertiary : Color.mSurfaceVariant - border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - - RowLayout { - anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: Style.marginS * scaling - - NIcon { - text: model.icon - color: Color.mOnSurface - font.pointSize: Style.fontSizeM * scaling - } - - ColumnLayout { - Layout.fillWidth: true - spacing: 0 - - NText { - text: model.name - font.pointSize: Style.fontSizeS * scaling - font.weight: Style.fontWeightBold - color: Color.mOnSurface - } - - NText { - text: model.description - font.pointSize: Style.fontSizeXS * scaling - color: Color.mOnSurfaceVariant - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - addWidgetToSection(model.name, addWidgetDialog.targetSection) - addWidgetDialog.hide() - } - } - } - } - - RowLayout { - Layout.fillWidth: true - - Item { Layout.fillWidth: true } - - NIconButton { - icon: "close" - size: 20 * scaling - color: Color.mOnSurface - onClicked: addWidgetDialog.hide() - } - } - } - } - } // Helper functions function addWidgetToSection(widgetName, section) { @@ -762,4 +583,46 @@ ColumnLayout { Settings.data.bar.widgets[section] = newArray } } + + // Widget list for adding widgets + ListModel { + id: availableWidgets + ListElement { key: "SystemMonitor"; name: "SystemMonitor" } + ListElement { key: "ActiveWindow"; name: "ActiveWindow" } + ListElement { key: "MediaMini"; name: "MediaMini" } + ListElement { key: "Workspace"; name: "Workspace" } + ListElement { key: "ScreenRecorderIndicator"; name: "ScreenRecorderIndicator" } + ListElement { key: "Tray"; name: "Tray" } + ListElement { key: "NotificationHistory"; name: "NotificationHistory" } + ListElement { key: "WiFi"; name: "WiFi" } + ListElement { key: "Bluetooth"; name: "Bluetooth" } + ListElement { key: "Battery"; name: "Battery" } + ListElement { key: "Volume"; name: "Volume" } + ListElement { key: "Brightness"; name: "Brightness" } + ListElement { key: "Clock"; name: "Clock" } + ListElement { key: "SidePanelToggle"; name: "SidePanelToggle" } + } + + + + // Helper function to get widget icons + function getWidgetIcon(widgetKey) { + switch(widgetKey) { + case "SystemMonitor": return "memory" + case "ActiveWindow": return "web_asset" + case "MediaMini": return "music_note" + case "Workspace": return "dashboard" + case "ScreenRecorderIndicator": return "videocam" + case "Tray": return "apps" + case "NotificationHistory": return "notifications" + case "WiFi": return "wifi" + case "Bluetooth": return "bluetooth" + case "Battery": return "battery_full" + case "Volume": return "volume_up" + case "Brightness": return "brightness_6" + case "Clock": return "schedule" + case "SidePanelToggle": return "widgets" + default: return "widgets" + } + } } diff --git a/Widgets/NComboBox.qml b/Widgets/NComboBox.qml index 9ec2aaf..c82abb0 100644 --- a/Widgets/NComboBox.qml +++ b/Widgets/NComboBox.qml @@ -16,6 +16,7 @@ ColumnLayout { } property string currentKey: '' + property string placeholder: "" signal selected(string key) @@ -61,8 +62,9 @@ ColumnLayout { font.pointSize: Style.fontSizeM * scaling verticalAlignment: Text.AlignVCenter elide: Text.ElideRight + color: (combo.currentIndex >= 0 && combo.currentIndex < root.model.count) ? Color.mOnSurface : Color.mOnSurfaceVariant text: (combo.currentIndex >= 0 && combo.currentIndex < root.model.count) ? root.model.get( - combo.currentIndex).name : "" + combo.currentIndex).name : root.placeholder } indicator: NIcon {