From 3a6c032782a7e0fd1f887af66face060c3197f66 Mon Sep 17 00:00:00 2001 From: Runze Date: Tue, 5 Aug 2025 17:21:36 +0800 Subject: [PATCH 01/17] Added a small battery popup to show information --- .../ii/modules/bar/BatteryIndicator.qml | 26 +++- .../ii/modules/bar/BatteryPopup.qml | 125 ++++++++++++++++++ .config/quickshell/ii/services/Battery.qml | 39 ++++++ .config/quickshell/translations/en_US.json | 8 +- .config/quickshell/translations/zh_CN.json | 8 +- 5 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 .config/quickshell/ii/modules/bar/BatteryPopup.qml diff --git a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml index fa5d5daf4..ae907e42e 100644 --- a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml +++ b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml @@ -3,8 +3,9 @@ import qs.modules.common.widgets import qs.services import QtQuick import QtQuick.Layouts +import Quickshell -Item { +MouseArea { id: root property bool borderless: Config.options.bar.borderless readonly property var chargeState: Battery.chargeState @@ -18,6 +19,8 @@ Item { implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2 implicitHeight: 32 + hoverEnabled: true + RowLayout { id: rowLayout @@ -92,4 +95,25 @@ Item { } } + LazyLoader { + id: popupLoader + active: root.containsMouse + + component: PopupWindow { + id: popupWindow + visible: true + implicitWidth: batteryPopup.implicitWidth + implicitHeight: batteryPopup.implicitHeight + anchor.item: root + anchor.rect.x: (root.implicitWidth - popupWindow.implicitWidth) / 2 + anchor.rect.y: Config.options.bar.bottom + ? (-batteryPopup.implicitHeight - 15) + : (root.implicitHeight + 15) + color: "transparent" + BatteryPopup { + id: batteryPopup + } + } + } + } diff --git a/.config/quickshell/ii/modules/bar/BatteryPopup.qml b/.config/quickshell/ii/modules/bar/BatteryPopup.qml new file mode 100644 index 000000000..ae0264c20 --- /dev/null +++ b/.config/quickshell/ii/modules/bar/BatteryPopup.qml @@ -0,0 +1,125 @@ +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import qs +import QtQuick +import QtQuick.Layouts + +Rectangle { + id: root + readonly property real margin: 10 + implicitWidth: columnLayout.implicitWidth + margin * 2 + implicitHeight: columnLayout.implicitHeight + margin * 2 + color: Appearance.colors.colLayer0 + radius: Appearance.rounding.small + border.width: 1 + border.color: Appearance.colors.colLayer0Border + clip: true + + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 8 + + RowLayout { + spacing: 5 + Layout.fillWidth: true + MaterialSymbol { text: "thermostat"; color: Appearance.m3colors.m3onSecondaryContainer } + StyledText { text: Translation.tr("Temperature:"); color: Appearance.colors.colOnLayer1 } + StyledText { Layout.fillWidth: true; horizontalAlignment: Text.AlignRight; color: Appearance.colors.colOnLayer1; text: `${Battery.temperature}°C` } + } + + // This row is hidden when the battery is full. + RowLayout { + spacing: 5 + Layout.fillWidth: true + property bool rowVisible: { + let timeValue = Battery.isCharging ? Battery.timeToFull : Battery.timeToEmpty; + let power = Battery.energyRate; + return !(Battery.chargeState == 4 || timeValue <= 0 || power <= 0.01); + } + visible: rowVisible + opacity: rowVisible ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 500 } } + + MaterialSymbol { text: "schedule"; color: Appearance.m3colors.m3onSecondaryContainer } + StyledText { text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:"); color: Appearance.colors.colOnLayer1 } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnLayer1 + text: { + function formatTime(seconds) { + var h = Math.floor(seconds / 3600); + var m = Math.floor((seconds % 3600) / 60); + if (h > 0) + return `${h}h ${m}m`; + else + return `${m}m`; + } + if (Battery.isCharging) + return formatTime(Battery.timeToFull); + else + return formatTime(Battery.timeToEmpty); + } + } + } + + RowLayout { + spacing: 5 + Layout.fillWidth: true + + property bool rowVisible: !(Battery.chargeState != 4 && Battery.energyRate == 0) + visible: rowVisible + opacity: rowVisible ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 500 } } + + MaterialSymbol { + text: { + if (Battery.isCharging) { + return "power"; + } else if (Battery.percentage >= 0.8) { + return "battery_full"; + } else if (Battery.percentage >= 0.6) { + return "battery_5_bar"; + } else if (Battery.percentage >= 0.4) { + return "battery_4_bar"; + } else if (Battery.percentage >= 0.2) { + return "battery_2_bar"; + } else { + return "battery_0_bar"; + } + } + color: Appearance.m3colors.m3onSecondaryContainer + } + + + StyledText { + text: { + if (Battery.chargeState == 4) { + return Translation.tr("Fully charged"); + } else if (Battery.chargeState == 1) { + return Translation.tr("Charging:"); + } else { + return Translation.tr("Discharging:"); + } + } + color: Appearance.colors.colOnLayer1 + } + + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnLayer1 + text: { + if (Battery.chargeState == 4) { + return ""; + } else { + return `${Battery.energyRate.toFixed(2)}W`; + } + } + } + } + + } +} diff --git a/.config/quickshell/ii/services/Battery.qml b/.config/quickshell/ii/services/Battery.qml index 8a3cf3160..5193c19f5 100644 --- a/.config/quickshell/ii/services/Battery.qml +++ b/.config/quickshell/ii/services/Battery.qml @@ -4,6 +4,8 @@ import qs import qs.modules.common import Quickshell import Quickshell.Services.UPower +import QtQuick +import Quickshell.Io Singleton { property bool available: UPower.displayDevice.isLaptopBattery @@ -21,6 +23,43 @@ Singleton { property bool isCriticalAndNotCharging: isCritical && !isCharging property bool isSuspendingAndNotCharging: allowAutomaticSuspend && isSuspending && !isCharging + property real energyRate: UPower.displayDevice.changeRate + property real timeToEmpty: UPower.displayDevice.timeToEmpty + property real timeToFull: UPower.displayDevice.timeToFull + property real temperature: 0 + + Process { + id: tempProcess + command: ["bash", "-c", "cat /sys/class/thermal/thermal_zone0/temp"] + stdout: StdioCollector { + onStreamFinished: { + if (text && text.trim() !== "") { + Battery.temperature = parseInt(text.trim()) / 1000 + } else { + Battery.temperature = 0 + } + } + } + } + + Timer { + interval: 3000 + repeat: true + running: true + onTriggered: { + if (!tempProcess.running) { + tempProcess.running = true + } + } + } + + Component.onCompleted: { + if (!tempProcess.running) { + tempProcess.running = true; + } + } + + onIsLowAndNotChargingChanged: { if (available && isLowAndNotCharging) Quickshell.execDetached([ "notify-send", diff --git a/.config/quickshell/translations/en_US.json b/.config/quickshell/translations/en_US.json index fe8c64533..474d4a4f1 100644 --- a/.config/quickshell/translations/en_US.json +++ b/.config/quickshell/translations/en_US.json @@ -310,5 +310,11 @@ "Sunrise": "Sunrise", "Pressure": "Pressure", "Visibility": "Visibility", - "Precipitation": "Precipitation" + "Precipitation": "Precipitation", + "Temperature:": "Temperature:", + "Time to full:": "Time to full:", + "Time to empty:": "Time to empty:", + "Fully charged": "Fully charged", + "Charging:": "Charging:", + "Discharging:": "Discharging:" } \ No newline at end of file diff --git a/.config/quickshell/translations/zh_CN.json b/.config/quickshell/translations/zh_CN.json index 34dc54157..216e3f94b 100644 --- a/.config/quickshell/translations/zh_CN.json +++ b/.config/quickshell/translations/zh_CN.json @@ -310,5 +310,11 @@ "Sunset": "日落", "Humidity": "湿度", "Wind": "风", - "Precipitation": "降水量" + "Precipitation": "降水量", + "Temperature:": "温度:", + "Time to full:": "距离充满:", + "Time to empty:": "距离耗尽:", + "Fully charged": "已充满电", + "Charging:": "充电功率:", + "Discharging:": "放电功率:" } From 416146735641647511f1c88673e83ebdd323875c Mon Sep 17 00:00:00 2001 From: Runze Date: Wed, 6 Aug 2025 01:31:02 +0800 Subject: [PATCH 02/17] use PanelWindow instead to show animation --- .../ii/modules/bar/BatteryIndicator.qml | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml index ae907e42e..3cad9b2a5 100644 --- a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml +++ b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml @@ -95,23 +95,34 @@ MouseArea { } } - LazyLoader { + Loader { id: popupLoader active: root.containsMouse - component: PopupWindow { + sourceComponent: PanelWindow { id: popupWindow visible: true + color: "transparent" + exclusiveZone: 0 + + anchors.top: true + anchors.left: true + implicitWidth: batteryPopup.implicitWidth implicitHeight: batteryPopup.implicitHeight - anchor.item: root - anchor.rect.x: (root.implicitWidth - popupWindow.implicitWidth) / 2 - anchor.rect.y: Config.options.bar.bottom - ? (-batteryPopup.implicitHeight - 15) - : (root.implicitHeight + 15) - color: "transparent" + + margins { + left: root.mapToGlobal(Qt.point(0, 0)).x - batteryPopup.implicitWidth / 3 + top: root.mapToGlobal(Qt.point(0, root.height)).y - 30 + } + + mask: Region { + item: batteryPopup + } + BatteryPopup { id: batteryPopup + anchors.centerIn: parent } } } From 1dc46fa1048dd82b70436aee5d8120e6e9975a69 Mon Sep 17 00:00:00 2001 From: finjener Date: Wed, 6 Aug 2025 01:25:37 +0100 Subject: [PATCH 03/17] feat(bar): add hover popups for system resources and upcoming todos - Add detailed popups for memory, swap, and CPU resource icons - Add todo integration popup for date/time widget --- .../quickshell/ii/modules/bar/ClockWidget.qml | 77 +++++++++++++++++ .../quickshell/ii/modules/bar/Resource.qml | 83 ++++++++++++++++++- 2 files changed, 158 insertions(+), 2 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index 9f45aa0af..a2a70f6c2 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -1,8 +1,10 @@ +import qs import qs.modules.common import qs.modules.common.widgets import qs.services import QtQuick import QtQuick.Layouts +import Quickshell Item { id: root @@ -11,6 +13,81 @@ Item { implicitWidth: rowLayout.implicitWidth implicitHeight: 32 + // Helper function to get upcoming todos + function getUpcomingTodos() { + const unfinishedTodos = Todo.list.filter(function(item) { return !item.done; }) + if (unfinishedTodos.length === 0) { + return "No pending tasks" + } + + // Limit to first 5 todos to keep popup manageable + const limitedTodos = unfinishedTodos.slice(0, 5) + let todoText = limitedTodos.map(function(item, index) { + return `${index + 1}. ${item.content}` + }).join('\n') + + if (unfinishedTodos.length > 5) { + todoText += `\n... and ${unfinishedTodos.length - 5} more` + } + + return todoText + } + + // Generate popup content with date and upcoming todos + property string dateDetails: { + const todosSection = getUpcomingTodos() + return `${Qt.locale().toString(DateTime.clock.date, "dddd, MMMM dd, yyyy")} • ${DateTime.time} +Uptime: ${DateTime.uptime} + +📋 Upcoming Tasks: +${todosSection}` + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + + LazyLoader { + id: popupLoader + active: mouseArea.containsMouse + + component: PopupWindow { + id: popupWindow + visible: true + implicitWidth: datePopup.implicitWidth + implicitHeight: datePopup.implicitHeight + anchor.item: root + anchor.edges: Edges.Top + anchor.rect.x: (root.implicitWidth - popupWindow.implicitWidth) / 2 + anchor.rect.y: Config.options.bar.bottom ? + (-datePopup.implicitHeight - 15) : + (root.implicitHeight + 15) + color: "transparent" + + Rectangle { + id: datePopup + readonly property real margin: 12 + implicitWidth: popupText.implicitWidth + margin * 2 + implicitHeight: popupText.implicitHeight + margin * 2 + color: Appearance.colors.colLayer0 + radius: Appearance.rounding.small + border.width: 1 + border.color: Appearance.colors.colLayer0Border + + StyledText { + id: popupText + anchors.centerIn: parent + font.pixelSize: Appearance.font.pixelSize.small + color: Appearance.colors.colOnLayer0 + text: dateDetails + } + } + } + } + RowLayout { id: rowLayout anchors.centerIn: parent diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index 12c799111..e6965dff0 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -1,7 +1,10 @@ +import qs import qs.modules.common import qs.modules.common.widgets +import qs.services import QtQuick import QtQuick.Layouts +import Quickshell Item { required property string iconName @@ -9,8 +12,84 @@ Item { property bool shown: true clip: true visible: width > 0 && height > 0 - implicitWidth: resourceRowLayout.x < 0 ? 0 : childrenRect.width - implicitHeight: childrenRect.height + implicitWidth: resourceRowLayout.x < 0 ? 0 : resourceRowLayout.implicitWidth + implicitHeight: resourceRowLayout.implicitHeight + + // Helper function to format KB to GB + function formatKB(kb) { + return (kb / (1024 * 1024)).toFixed(1) + " GB" + } + + // Generate tooltip content based on resource type + property string tooltipContent: { + switch(iconName) { + case "memory": + return `Memory Usage +Used: ${formatKB(ResourceUsage.memoryUsed)} +Free: ${formatKB(ResourceUsage.memoryFree)} +Total: ${formatKB(ResourceUsage.memoryTotal)} +Usage: ${Math.round(ResourceUsage.memoryUsedPercentage * 100)}%` + case "swap_horiz": + return ResourceUsage.swapTotal > 0 ? + `Swap Usage +Used: ${formatKB(ResourceUsage.swapUsed)} +Free: ${formatKB(ResourceUsage.swapFree)} +Total: ${formatKB(ResourceUsage.swapTotal)} +Usage: ${Math.round(ResourceUsage.swapUsedPercentage * 100)}%` : + "Swap: Not configured" + case "settings_slow_motion": + return `CPU Usage +Current: ${Math.round(ResourceUsage.cpuUsage * 100)}% +Load: ${ResourceUsage.cpuUsage > 0.8 ? "High" : ResourceUsage.cpuUsage > 0.5 ? "Medium" : "Low"}` + default: + return "System Resource" + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + + LazyLoader { + id: popupLoader + active: mouseArea.containsMouse + + component: PopupWindow { + id: popupWindow + visible: true + implicitWidth: resourcePopup.implicitWidth + implicitHeight: resourcePopup.implicitHeight + anchor.item: root + anchor.edges: Edges.Top + anchor.rect.x: (root.implicitWidth - popupWindow.implicitWidth) / 2 + anchor.rect.y: Config.options.bar.bottom ? + (-resourcePopup.implicitHeight - 15) : + (root.implicitHeight + 15) + color: "transparent" + + Rectangle { + id: resourcePopup + readonly property real margin: 10 + implicitWidth: popupText.implicitWidth + margin * 2 + implicitHeight: popupText.implicitHeight + margin * 2 + color: Appearance.colors.colLayer0 + radius: Appearance.rounding.small + border.width: 1 + border.color: Appearance.colors.colLayer0Border + + StyledText { + id: popupText + anchors.centerIn: parent + font.pixelSize: Appearance.font.pixelSize.small + color: Appearance.colors.colOnLayer0 + text: tooltipContent + } + } + } + } RowLayout { spacing: 4 From 061bb2abeb58fb44cfe50b13d35b3b2eb28cf6e5 Mon Sep 17 00:00:00 2001 From: Runze Date: Wed, 6 Aug 2025 18:02:55 +0800 Subject: [PATCH 04/17] feat(bar): unify popup handling and improve layouts - Unified popup handling in ClockWidget, Resource, BatteryPopup, and WeatherBar using PanelWindow + LazyLoader for consistent positioning and compositor animations. - Replaced plain text with ColumnLayout and RowLayout where possible, adding MaterialSymbol icons for improved visual consistency with the overall desktop style. - Added Translation.tr() for bilingual (Chinese/English) support to avoid hardcoded strings. - Based on improvements from PR #1771 (mine) and PR #1773 (by @finjener), merged and refined into a more polished and practical solution. --- .../ii/modules/bar/BatteryIndicator.qml | 9 +- .../ii/modules/bar/BatteryPopup.qml | 2 +- .../quickshell/ii/modules/bar/ClockWidget.qml | 106 +++++++++++++---- .../quickshell/ii/modules/bar/Resource.qml | 111 ++++++++++++------ .../ii/modules/bar/weather/WeatherBar.qml | 26 ++-- .config/quickshell/translations/en_US.json | 21 +++- .config/quickshell/translations/zh_CN.json | 21 +++- 7 files changed, 224 insertions(+), 72 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml index 3cad9b2a5..6815d6d7e 100644 --- a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml +++ b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml @@ -95,11 +95,11 @@ MouseArea { } } - Loader { + LazyLoader { id: popupLoader active: root.containsMouse - sourceComponent: PanelWindow { + component: PanelWindow { id: popupWindow visible: true color: "transparent" @@ -112,7 +112,10 @@ MouseArea { implicitHeight: batteryPopup.implicitHeight margins { - left: root.mapToGlobal(Qt.point(0, 0)).x - batteryPopup.implicitWidth / 3 + left: root.mapToGlobal(Qt.point( + (root.width - batteryPopup.implicitWidth) / 2, + 0 + )).x top: root.mapToGlobal(Qt.point(0, root.height)).y - 30 } diff --git a/.config/quickshell/ii/modules/bar/BatteryPopup.qml b/.config/quickshell/ii/modules/bar/BatteryPopup.qml index ae0264c20..075b4bd5d 100644 --- a/.config/quickshell/ii/modules/bar/BatteryPopup.qml +++ b/.config/quickshell/ii/modules/bar/BatteryPopup.qml @@ -53,7 +53,7 @@ Rectangle { var h = Math.floor(seconds / 3600); var m = Math.floor((seconds % 3600) / 60); if (h > 0) - return `${h}h ${m}m`; + return `${h}h, ${m}m`; else return `${m}m`; } diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index a2a70f6c2..ac630ad5e 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -17,7 +17,7 @@ Item { function getUpcomingTodos() { const unfinishedTodos = Todo.list.filter(function(item) { return !item.done; }) if (unfinishedTodos.length === 0) { - return "No pending tasks" + return Translation.tr("No pending tasks") } // Limit to first 5 todos to keep popup manageable @@ -27,21 +27,17 @@ Item { }).join('\n') if (unfinishedTodos.length > 5) { - todoText += `\n... and ${unfinishedTodos.length - 5} more` + todoText += `\n${Translation.tr("... and %1 more").arg(unfinishedTodos.length - 5)}` } return todoText } - // Generate popup content with date and upcoming todos - property string dateDetails: { - const todosSection = getUpcomingTodos() - return `${Qt.locale().toString(DateTime.clock.date, "dddd, MMMM dd, yyyy")} • ${DateTime.time} -Uptime: ${DateTime.uptime} - -📋 Upcoming Tasks: -${todosSection}` - } + // Popup Data + property string formattedDate: Qt.locale().toString(DateTime.clock.date, "dddd, MMMM dd, yyyy") + property string formattedTime: DateTime.time + property string formattedUptime: DateTime.uptime + property string todosSection: getUpcomingTodos() MouseArea { id: mouseArea @@ -54,37 +50,95 @@ ${todosSection}` id: popupLoader active: mouseArea.containsMouse - component: PopupWindow { + component: PanelWindow { id: popupWindow visible: true implicitWidth: datePopup.implicitWidth implicitHeight: datePopup.implicitHeight - anchor.item: root - anchor.edges: Edges.Top - anchor.rect.x: (root.implicitWidth - popupWindow.implicitWidth) / 2 - anchor.rect.y: Config.options.bar.bottom ? - (-datePopup.implicitHeight - 15) : - (root.implicitHeight + 15) color: "transparent" + exclusiveZone: 0 + + anchors.top: true + anchors.left: true + + margins { + left: root.mapToGlobal(Qt.point( + (root.width - datePopup.implicitWidth) / 2, + 0 + )).x + top: root.mapToGlobal(Qt.point(0, root.height)).y - 30 + } + + mask: Region { + item: datePopup + } Rectangle { id: datePopup readonly property real margin: 12 - implicitWidth: popupText.implicitWidth + margin * 2 - implicitHeight: popupText.implicitHeight + margin * 2 + implicitWidth: columnLayout.implicitWidth + margin * 2 + implicitHeight: columnLayout.implicitHeight + margin * 2 color: Appearance.colors.colLayer0 radius: Appearance.rounding.small border.width: 1 border.color: Appearance.colors.colLayer0Border - - StyledText { - id: popupText + clip: true + + ColumnLayout { + id: columnLayout anchors.centerIn: parent - font.pixelSize: Appearance.font.pixelSize.small - color: Appearance.colors.colOnLayer0 - text: dateDetails + spacing: 8 + + // Date + Time row + RowLayout { + spacing: 5 + Layout.fillWidth: true + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignLeft + color: Appearance.colors.colOnLayer1 + text: `${root.formattedDate} • ${root.formattedTime}` + } + } + + // Uptime row + RowLayout { + spacing: 5 + Layout.fillWidth: true + MaterialSymbol { text: "timelapse"; color: Appearance.m3colors.m3onSecondaryContainer } + StyledText { text: Translation.tr("Uptime:"); color: Appearance.colors.colOnLayer1 } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnLayer1 + text: root.formattedUptime + } + } + + // Upcoming tasks row + ColumnLayout { + spacing: 2 + Layout.fillWidth: true + + RowLayout { + spacing: 5 + Layout.fillWidth: true + MaterialSymbol { text: "checklist"; color: Appearance.m3colors.m3onSecondaryContainer } + StyledText { text: Translation.tr("Upcoming Tasks:"); color: Appearance.colors.colOnLayer1 } + } + + StyledText { + Layout.fillWidth: true + topPadding: 5 + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + color: Appearance.colors.colOnLayer1 + text: root.todosSection + } + } } } + } } diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index e6965dff0..cf6a0365a 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -7,6 +7,7 @@ import QtQuick.Layouts import Quickshell Item { + id: root required property string iconName required property double percentage property bool shown: true @@ -21,28 +22,41 @@ Item { } // Generate tooltip content based on resource type - property string tooltipContent: { + property var tooltipData: { switch(iconName) { case "memory": - return `Memory Usage -Used: ${formatKB(ResourceUsage.memoryUsed)} -Free: ${formatKB(ResourceUsage.memoryFree)} -Total: ${formatKB(ResourceUsage.memoryTotal)} -Usage: ${Math.round(ResourceUsage.memoryUsedPercentage * 100)}%` + return [ + { icon: "memory", label: Translation.tr("Memory Usage"), value: "" }, + { icon: "storage", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.memoryUsed) }, + { icon: "check_circle", label: Translation.tr("Free:"), value: formatKB(ResourceUsage.memoryFree) }, + { icon: "dns", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.memoryTotal) }, + { icon: "percent", label: Translation.tr("Usage:"), value: `${Math.round(ResourceUsage.memoryUsedPercentage * 100)}%` } + ] case "swap_horiz": - return ResourceUsage.swapTotal > 0 ? - `Swap Usage -Used: ${formatKB(ResourceUsage.swapUsed)} -Free: ${formatKB(ResourceUsage.swapFree)} -Total: ${formatKB(ResourceUsage.swapTotal)} -Usage: ${Math.round(ResourceUsage.swapUsedPercentage * 100)}%` : - "Swap: Not configured" + return ResourceUsage.swapTotal > 0 ? + [ + { icon: "swap_horiz", label: Translation.tr("Swap Usage"), value: "" }, + { icon: "storage", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.swapUsed) }, + { icon: "check_circle", label: Translation.tr("Free:"), value: formatKB(ResourceUsage.swapFree) }, + { icon: "dns", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.swapTotal) }, + { icon: "percent", label: Translation.tr("Usage:"), value: `${Math.round(ResourceUsage.swapUsedPercentage * 100)}%` } + ] : + [ + { icon: "swap_horiz", label: Translation.tr("Swap:"), value: Translation.tr("Not configured") } + ] case "settings_slow_motion": - return `CPU Usage -Current: ${Math.round(ResourceUsage.cpuUsage * 100)}% -Load: ${ResourceUsage.cpuUsage > 0.8 ? "High" : ResourceUsage.cpuUsage > 0.5 ? "Medium" : "Low"}` + return [ + { icon: "settings_slow_motion", label: Translation.tr("CPU Usage"), value: "" }, + { icon: "bolt", label: Translation.tr("Current:"), value: `${Math.round(ResourceUsage.cpuUsage * 100)}%` }, + { icon: "speed", label: Translation.tr("Load:"), value: ResourceUsage.cpuUsage > 0.8 ? + Translation.tr("High") : + ResourceUsage.cpuUsage > 0.5 ? Translation.tr("Medium") : Translation.tr("Low") + } + ] default: - return "System Resource" + return [ + { icon: "info", label: Translation.tr("System Resource"), value: "" } + ] } } @@ -57,35 +71,66 @@ Load: ${ResourceUsage.cpuUsage > 0.8 ? "High" : ResourceUsage.cpuUsage > 0.5 ? " id: popupLoader active: mouseArea.containsMouse - component: PopupWindow { + component: PanelWindow { id: popupWindow visible: true + + color: "transparent" + exclusiveZone: 0 + anchors.top: true + anchors.left: true + implicitWidth: resourcePopup.implicitWidth implicitHeight: resourcePopup.implicitHeight - anchor.item: root - anchor.edges: Edges.Top - anchor.rect.x: (root.implicitWidth - popupWindow.implicitWidth) / 2 - anchor.rect.y: Config.options.bar.bottom ? - (-resourcePopup.implicitHeight - 15) : - (root.implicitHeight + 15) - color: "transparent" + + margins { + left: root.mapToGlobal(Qt.point( + (root.width - resourcePopup.implicitWidth) / 2, + 0 + )).x + top: root.mapToGlobal(Qt.point(0, root.height)).y - 30 + } + Rectangle { id: resourcePopup readonly property real margin: 10 - implicitWidth: popupText.implicitWidth + margin * 2 - implicitHeight: popupText.implicitHeight + margin * 2 + implicitWidth: columnLayout.implicitWidth + margin * 2 + implicitHeight: columnLayout.implicitHeight + margin * 2 color: Appearance.colors.colLayer0 radius: Appearance.rounding.small border.width: 1 border.color: Appearance.colors.colLayer0Border - - StyledText { - id: popupText + clip: true + + ColumnLayout { + id: columnLayout anchors.centerIn: parent - font.pixelSize: Appearance.font.pixelSize.small - color: Appearance.colors.colOnLayer0 - text: tooltipContent + spacing: 6 + + Repeater { + model: root.tooltipData + delegate: RowLayout { + spacing: 5 + Layout.fillWidth: true + + MaterialSymbol { + text: modelData.icon + color: Appearance.m3colors.m3onSecondaryContainer + } + StyledText { + text: modelData.label + color: Appearance.colors.colOnLayer1 + } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + visible: modelData.value !== "" + color: Appearance.colors.colOnLayer1 + text: modelData.value + } + } + } } } } diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml index 363d9ba53..d3ca95a7a 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml @@ -40,18 +40,30 @@ MouseArea { id: popupLoader active: root.containsMouse - component: PopupWindow { + component: PanelWindow { id: popupWindow visible: true implicitWidth: weatherPopup.implicitWidth implicitHeight: weatherPopup.implicitHeight - anchor.item: root - anchor.edges: Edges.Top - anchor.rect.x: (root.implicitWidth - popupWindow.implicitWidth) / 2 - anchor.rect.y: Config.options.bar.bottom ? - (-weatherPopup.implicitHeight - 15) : - (root.implicitHeight + 15 ) + color: "transparent" + exclusiveZone: 0 + + anchors.top: true + anchors.left: true + + margins { + left: root.mapToGlobal(Qt.point( + (root.width - weatherPopup.implicitWidth) / 2, + 0 + )).x + top: root.mapToGlobal(Qt.point(0, root.height)).y - 25 + } + + mask: Region { + item: weatherPopup + } + WeatherPopup { id: weatherPopup } diff --git a/.config/quickshell/translations/en_US.json b/.config/quickshell/translations/en_US.json index 474d4a4f1..9bfaeb9e7 100644 --- a/.config/quickshell/translations/en_US.json +++ b/.config/quickshell/translations/en_US.json @@ -316,5 +316,24 @@ "Time to empty:": "Time to empty:", "Fully charged": "Fully charged", "Charging:": "Charging:", - "Discharging:": "Discharging:" + "Discharging:": "Discharging:", + "Uptime:": "Uptime:", + "Upcoming Tasks:": "Upcoming Tasks:", + "No pending tasks": "No pending tasks", + "... and %1 more": "... and %1 more", + "Memory Usage": "Memory Usage", + "Used:": "Used:", + "Free:": "Free:", + "Total:": "Total:", + "Usage:": "Usage:", + "Swap Usage": "Swap Usage", + "Swap:": "Swap:", + "Not configured": "Not configured", + "CPU Usage": "CPU Usage", + "Current:": "Current:", + "Load:": "Load:", + "High": "High", + "Medium": "Medium", + "Low": "Low", + "System Resource": "System Resource" } \ No newline at end of file diff --git a/.config/quickshell/translations/zh_CN.json b/.config/quickshell/translations/zh_CN.json index 216e3f94b..02540dd7d 100644 --- a/.config/quickshell/translations/zh_CN.json +++ b/.config/quickshell/translations/zh_CN.json @@ -316,5 +316,24 @@ "Time to empty:": "距离耗尽:", "Fully charged": "已充满电", "Charging:": "充电功率:", - "Discharging:": "放电功率:" + "Discharging:": "放电功率:", + "Uptime:": "运行时间:", + "Upcoming Tasks:": "待办任务:", + "No pending tasks": "没有待办任务", + "... and %1 more": "... 还有 %1 个", + "Memory Usage": "内存使用情况", + "Used:": "已用:", + "Free:": "可用:", + "Total:": "总计:", + "Usage:": "占比:", + "Swap Usage": "交换区使用情况", + "Swap:": "交换区:", + "Not configured": "未配置", + "CPU Usage": "CPU 使用情况", + "Current:": "当前占比:", + "Load:": "负载:", + "High": "高", + "Medium": "中", + "Low": "低", + "System Resource": "系统资源" } From 627c8562f7318a82f49105d0f8eee93fc2354bdd Mon Sep 17 00:00:00 2001 From: Runze Date: Wed, 6 Aug 2025 19:28:37 +0800 Subject: [PATCH 05/17] fix(bar): prevent hover popup from appearing for hidden resource icons --- .config/quickshell/ii/modules/bar/Resource.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index cf6a0365a..76aca94a8 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -65,6 +65,7 @@ Item { anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.NoButton + enabled: resourceRowLayout.x >= 0 && root.width > 0 && root.visible } LazyLoader { From 94176fad836ff1dc609a913883a882e2a881863f Mon Sep 17 00:00:00 2001 From: Runze Date: Sat, 9 Aug 2025 14:02:56 +0800 Subject: [PATCH 06/17] feat(bar): unify extraction to StyledPopup and add namespace --- .../ii/modules/bar/BatteryIndicator.qml | 40 +----- .../quickshell/ii/modules/bar/ClockWidget.qml | 130 +++++++----------- .../quickshell/ii/modules/bar/Resource.qml | 94 +++++-------- .../ii/modules/bar/weather/WeatherBar.qml | 37 +---- .../ii/modules/common/widgets/StyledPopup.qml | 57 ++++++++ 5 files changed, 158 insertions(+), 200 deletions(-) create mode 100644 .config/quickshell/ii/modules/common/widgets/StyledPopup.qml diff --git a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml index 6815d6d7e..39388aafe 100644 --- a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml +++ b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml @@ -95,39 +95,13 @@ MouseArea { } } - LazyLoader { - id: popupLoader - active: root.containsMouse - - component: PanelWindow { - id: popupWindow - visible: true - color: "transparent" - exclusiveZone: 0 - - anchors.top: true - anchors.left: true - - implicitWidth: batteryPopup.implicitWidth - implicitHeight: batteryPopup.implicitHeight - - margins { - left: root.mapToGlobal(Qt.point( - (root.width - batteryPopup.implicitWidth) / 2, - 0 - )).x - top: root.mapToGlobal(Qt.point(0, root.height)).y - 30 - } - - mask: Region { - item: batteryPopup - } - - BatteryPopup { - id: batteryPopup - anchors.centerIn: parent - } + StyledPopup { + hoverTarget: root + offsetY: -30 + maskEnabled: true + contentComponent: BatteryPopup { + id: batteryPopup + anchors.centerIn: parent } } - } diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index ac630ad5e..25e5a5eb5 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -46,99 +46,73 @@ Item { acceptedButtons: Qt.NoButton } - LazyLoader { - id: popupLoader - active: mouseArea.containsMouse + StyledPopup { + hoverTarget: mouseArea + offsetY: -30 + contentComponent: Rectangle { + id: datePopup + readonly property real margin: 12 + implicitWidth: columnLayout.implicitWidth + margin * 2 + implicitHeight: columnLayout.implicitHeight + margin * 2 + color: Appearance.colors.colLayer0 + radius: Appearance.rounding.small + border.width: 1 + border.color: Appearance.colors.colLayer0Border + clip: true - component: PanelWindow { - id: popupWindow - visible: true - implicitWidth: datePopup.implicitWidth - implicitHeight: datePopup.implicitHeight - color: "transparent" - exclusiveZone: 0 + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 8 - anchors.top: true - anchors.left: true + // Date + Time row + RowLayout { + spacing: 5 + Layout.fillWidth: true + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignLeft + color: Appearance.colors.colOnLayer1 + text: `${root.formattedDate} • ${root.formattedTime}` + } + } - margins { - left: root.mapToGlobal(Qt.point( - (root.width - datePopup.implicitWidth) / 2, - 0 - )).x - top: root.mapToGlobal(Qt.point(0, root.height)).y - 30 - } - - mask: Region { - item: datePopup - } - - Rectangle { - id: datePopup - readonly property real margin: 12 - implicitWidth: columnLayout.implicitWidth + margin * 2 - implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colLayer0 - radius: Appearance.rounding.small - border.width: 1 - border.color: Appearance.colors.colLayer0Border - clip: true + // Uptime row + RowLayout { + spacing: 5 + Layout.fillWidth: true + MaterialSymbol { text: "timelapse"; color: Appearance.m3colors.m3onSecondaryContainer } + StyledText { text: Translation.tr("Uptime:"); color: Appearance.colors.colOnLayer1 } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnLayer1 + text: root.formattedUptime + } + } + // Upcoming tasks row ColumnLayout { - id: columnLayout - anchors.centerIn: parent - spacing: 8 + spacing: 2 + Layout.fillWidth: true - // Date + Time row RowLayout { spacing: 5 Layout.fillWidth: true - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignLeft - color: Appearance.colors.colOnLayer1 - text: `${root.formattedDate} • ${root.formattedTime}` - } + MaterialSymbol { text: "checklist"; color: Appearance.m3colors.m3onSecondaryContainer } + StyledText { text: Translation.tr("Upcoming Tasks:"); color: Appearance.colors.colOnLayer1 } } - // Uptime row - RowLayout { - spacing: 5 + StyledText { Layout.fillWidth: true - MaterialSymbol { text: "timelapse"; color: Appearance.m3colors.m3onSecondaryContainer } - StyledText { text: Translation.tr("Uptime:"); color: Appearance.colors.colOnLayer1 } - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnLayer1 - text: root.formattedUptime - } - } - - // Upcoming tasks row - ColumnLayout { - spacing: 2 - Layout.fillWidth: true - - RowLayout { - spacing: 5 - Layout.fillWidth: true - MaterialSymbol { text: "checklist"; color: Appearance.m3colors.m3onSecondaryContainer } - StyledText { text: Translation.tr("Upcoming Tasks:"); color: Appearance.colors.colOnLayer1 } - } - - StyledText { - Layout.fillWidth: true - topPadding: 5 - horizontalAlignment: Text.AlignLeft - wrapMode: Text.Wrap - color: Appearance.colors.colOnLayer1 - text: root.todosSection - } + topPadding: 5 + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + color: Appearance.colors.colOnLayer1 + text: root.todosSection } } } - } } diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index 76aca94a8..031a77ed3 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -68,71 +68,49 @@ Item { enabled: resourceRowLayout.x >= 0 && root.width > 0 && root.visible } - LazyLoader { - id: popupLoader - active: mouseArea.containsMouse + StyledPopup { + hoverTarget: mouseArea + offsetY: -30 + contentComponent: Rectangle { + id: resourcePopup + readonly property real margin: 10 + implicitWidth: columnLayout.implicitWidth + margin * 2 + implicitHeight: columnLayout.implicitHeight + margin * 2 + color: Appearance.colors.colLayer0 + radius: Appearance.rounding.small + border.width: 1 + border.color: Appearance.colors.colLayer0Border + clip: true - component: PanelWindow { - id: popupWindow - visible: true + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 6 - color: "transparent" - exclusiveZone: 0 - anchors.top: true - anchors.left: true + Repeater { + model: root.tooltipData + delegate: RowLayout { + spacing: 5 + Layout.fillWidth: true - implicitWidth: resourcePopup.implicitWidth - implicitHeight: resourcePopup.implicitHeight - - margins { - left: root.mapToGlobal(Qt.point( - (root.width - resourcePopup.implicitWidth) / 2, - 0 - )).x - top: root.mapToGlobal(Qt.point(0, root.height)).y - 30 - } - - - Rectangle { - id: resourcePopup - readonly property real margin: 10 - implicitWidth: columnLayout.implicitWidth + margin * 2 - implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colLayer0 - radius: Appearance.rounding.small - border.width: 1 - border.color: Appearance.colors.colLayer0Border - clip: true - - ColumnLayout { - id: columnLayout - anchors.centerIn: parent - spacing: 6 - - Repeater { - model: root.tooltipData - delegate: RowLayout { - spacing: 5 + MaterialSymbol { + text: modelData.icon + color: Appearance.m3colors.m3onSecondaryContainer + } + StyledText { + text: modelData.label + color: Appearance.colors.colOnLayer1 + } + StyledText { Layout.fillWidth: true - - MaterialSymbol { - text: modelData.icon - color: Appearance.m3colors.m3onSecondaryContainer - } - StyledText { - text: modelData.label - color: Appearance.colors.colOnLayer1 - } - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - visible: modelData.value !== "" - color: Appearance.colors.colOnLayer1 - text: modelData.value - } + horizontalAlignment: Text.AlignRight + visible: modelData.value !== "" + color: Appearance.colors.colOnLayer1 + text: modelData.value } } } + } } } diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml index d3ca95a7a..b547ad0ea 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml @@ -36,37 +36,12 @@ MouseArea { } } - LazyLoader { - id: popupLoader - active: root.containsMouse - - component: PanelWindow { - id: popupWindow - visible: true - implicitWidth: weatherPopup.implicitWidth - implicitHeight: weatherPopup.implicitHeight - - color: "transparent" - exclusiveZone: 0 - - anchors.top: true - anchors.left: true - - margins { - left: root.mapToGlobal(Qt.point( - (root.width - weatherPopup.implicitWidth) / 2, - 0 - )).x - top: root.mapToGlobal(Qt.point(0, root.height)).y - 25 - } - - mask: Region { - item: weatherPopup - } - - WeatherPopup { - id: weatherPopup - } + StyledPopup { + hoverTarget: root + offsetY: -25 + contentComponent: WeatherPopup { + id: weatherPopup + anchors.centerIn: parent } } } diff --git a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml new file mode 100644 index 000000000..69b664c0b --- /dev/null +++ b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml @@ -0,0 +1,57 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Wayland + +LazyLoader { + id: root + + property Item hoverTarget + property real offsetY: -30 + property bool maskEnabled: true + property Component contentComponent + + active: hoverTarget && hoverTarget.containsMouse + + component: PanelWindow { + id: popupWindow + visible: true + color: "transparent" + exclusiveZone: 0 + anchors.top: true + anchors.left: true + + implicitWidth: popupContent.implicitWidth + implicitHeight: popupContent.implicitHeight + + margins { + left: hoverTarget + ? hoverTarget.mapToGlobal(Qt.point( + (hoverTarget.width - popupContent.implicitWidth) / 2, + 0 + )).x + : 0 + top: hoverTarget + ? hoverTarget.mapToGlobal(Qt.point(0, hoverTarget.height)).y + offsetY + : 0 + } + + mask: maskEnabled ? popupMask : undefined + WlrLayershell.namespace: "quickshell:styledPopup" //maybe this can fix with the popups not showing ? + + Region { + id: popupMask + item: popupContent + } + + Loader { + id: popupContent + sourceComponent: root.contentComponent + anchors.centerIn: parent + } + } +} From 9b5713d6b4cc80fec950652bf3e125b57ed4eea8 Mon Sep 17 00:00:00 2001 From: Runze Date: Sat, 9 Aug 2025 14:08:39 +0800 Subject: [PATCH 07/17] chore(bar): delete temperature and related reading logic --- .../ii/modules/bar/BatteryPopup.qml | 8 ----- .config/quickshell/ii/services/Battery.qml | 33 ------------------- 2 files changed, 41 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BatteryPopup.qml b/.config/quickshell/ii/modules/bar/BatteryPopup.qml index 075b4bd5d..985873d85 100644 --- a/.config/quickshell/ii/modules/bar/BatteryPopup.qml +++ b/.config/quickshell/ii/modules/bar/BatteryPopup.qml @@ -21,14 +21,6 @@ Rectangle { anchors.centerIn: parent spacing: 8 - RowLayout { - spacing: 5 - Layout.fillWidth: true - MaterialSymbol { text: "thermostat"; color: Appearance.m3colors.m3onSecondaryContainer } - StyledText { text: Translation.tr("Temperature:"); color: Appearance.colors.colOnLayer1 } - StyledText { Layout.fillWidth: true; horizontalAlignment: Text.AlignRight; color: Appearance.colors.colOnLayer1; text: `${Battery.temperature}°C` } - } - // This row is hidden when the battery is full. RowLayout { spacing: 5 diff --git a/.config/quickshell/ii/services/Battery.qml b/.config/quickshell/ii/services/Battery.qml index 5193c19f5..3674cb287 100644 --- a/.config/quickshell/ii/services/Battery.qml +++ b/.config/quickshell/ii/services/Battery.qml @@ -26,39 +26,6 @@ Singleton { property real energyRate: UPower.displayDevice.changeRate property real timeToEmpty: UPower.displayDevice.timeToEmpty property real timeToFull: UPower.displayDevice.timeToFull - property real temperature: 0 - - Process { - id: tempProcess - command: ["bash", "-c", "cat /sys/class/thermal/thermal_zone0/temp"] - stdout: StdioCollector { - onStreamFinished: { - if (text && text.trim() !== "") { - Battery.temperature = parseInt(text.trim()) / 1000 - } else { - Battery.temperature = 0 - } - } - } - } - - Timer { - interval: 3000 - repeat: true - running: true - onTriggered: { - if (!tempProcess.running) { - tempProcess.running = true - } - } - } - - Component.onCompleted: { - if (!tempProcess.running) { - tempProcess.running = true; - } - } - onIsLowAndNotChargingChanged: { if (available && isLowAndNotCharging) Quickshell.execDetached([ From e39c1af5ae71299f24e76a17bdd4058b188e6e80 Mon Sep 17 00:00:00 2001 From: Runze Date: Sun, 10 Aug 2025 02:51:54 +0800 Subject: [PATCH 08/17] chore(bar): add WlrLayer.Overlay in StyledPopup and delete temperature translation --- .config/quickshell/ii/modules/common/widgets/StyledPopup.qml | 1 + .config/quickshell/translations/en_US.json | 1 - .config/quickshell/translations/zh_CN.json | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml index 69b664c0b..5a72d121b 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml @@ -42,6 +42,7 @@ LazyLoader { mask: maskEnabled ? popupMask : undefined WlrLayershell.namespace: "quickshell:styledPopup" //maybe this can fix with the popups not showing ? + WlrLayershell.layer: WlrLayer.Overlay Region { id: popupMask diff --git a/.config/quickshell/translations/en_US.json b/.config/quickshell/translations/en_US.json index 9bfaeb9e7..215aeca02 100644 --- a/.config/quickshell/translations/en_US.json +++ b/.config/quickshell/translations/en_US.json @@ -311,7 +311,6 @@ "Pressure": "Pressure", "Visibility": "Visibility", "Precipitation": "Precipitation", - "Temperature:": "Temperature:", "Time to full:": "Time to full:", "Time to empty:": "Time to empty:", "Fully charged": "Fully charged", diff --git a/.config/quickshell/translations/zh_CN.json b/.config/quickshell/translations/zh_CN.json index 02540dd7d..11d29dccd 100644 --- a/.config/quickshell/translations/zh_CN.json +++ b/.config/quickshell/translations/zh_CN.json @@ -311,7 +311,6 @@ "Humidity": "湿度", "Wind": "风", "Precipitation": "降水量", - "Temperature:": "温度:", "Time to full:": "距离充满:", "Time to empty:": "距离耗尽:", "Fully charged": "已充满电", From 0beee14cd88397aefab39561a68be57ff4fdd5e6 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Aug 2025 15:52:54 +0700 Subject: [PATCH 09/17] bar: popups: fix and simplify positioning --- .../ii/modules/bar/BatteryIndicator.qml | 2 -- .../quickshell/ii/modules/bar/ClockWidget.qml | 1 - .../quickshell/ii/modules/bar/Resource.qml | 1 - .../ii/modules/bar/weather/WeatherBar.qml | 1 - .../ii/modules/common/widgets/StyledPopup.qml | 30 +++++++------------ 5 files changed, 10 insertions(+), 25 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml index 39388aafe..d2f17e598 100644 --- a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml +++ b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml @@ -97,8 +97,6 @@ MouseArea { StyledPopup { hoverTarget: root - offsetY: -30 - maskEnabled: true contentComponent: BatteryPopup { id: batteryPopup anchors.centerIn: parent diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index 25e5a5eb5..c7ffeed38 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -48,7 +48,6 @@ Item { StyledPopup { hoverTarget: mouseArea - offsetY: -30 contentComponent: Rectangle { id: datePopup readonly property real margin: 12 diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index 031a77ed3..a352e0eb7 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -70,7 +70,6 @@ Item { StyledPopup { hoverTarget: mouseArea - offsetY: -30 contentComponent: Rectangle { id: resourcePopup readonly property real margin: 10 diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml index b547ad0ea..8339d4829 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml @@ -38,7 +38,6 @@ MouseArea { StyledPopup { hoverTarget: root - offsetY: -25 contentComponent: WeatherPopup { id: weatherPopup anchors.centerIn: parent diff --git a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml index 5a72d121b..df5bdec1a 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml @@ -11,8 +11,6 @@ LazyLoader { id: root property Item hoverTarget - property real offsetY: -30 - property bool maskEnabled: true property Component contentComponent active: hoverTarget && hoverTarget.containsMouse @@ -22,33 +20,25 @@ LazyLoader { visible: true color: "transparent" exclusiveZone: 0 - anchors.top: true + anchors.left: true + anchors.top: !Config.options.bar.bottom + anchors.bottom: Config.options.bar.bottom implicitWidth: popupContent.implicitWidth implicitHeight: popupContent.implicitHeight margins { - left: hoverTarget - ? hoverTarget.mapToGlobal(Qt.point( - (hoverTarget.width - popupContent.implicitWidth) / 2, - 0 - )).x - : 0 - top: hoverTarget - ? hoverTarget.mapToGlobal(Qt.point(0, hoverTarget.height)).y + offsetY - : 0 + left: root.QsWindow?.mapFromItem( + root.hoverTarget, + (root.hoverTarget.width - popupContent.implicitWidth) / 2, 0 + ).x + top: Appearance.sizes.hyprlandGapsOut + bottom: Appearance.sizes.hyprlandGapsOut } - - mask: maskEnabled ? popupMask : undefined - WlrLayershell.namespace: "quickshell:styledPopup" //maybe this can fix with the popups not showing ? + WlrLayershell.namespace: "quickshell:popup" //maybe this can fix with the popups not showing ? WlrLayershell.layer: WlrLayer.Overlay - Region { - id: popupMask - item: popupContent - } - Loader { id: popupContent sourceComponent: root.contentComponent From e7397f824bf2df4eca7887c7027d5f2fe048d0ae Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:03:29 +0700 Subject: [PATCH 10/17] bar tooltips: make em use tooltip color --- .../quickshell/ii/modules/bar/BatteryPopup.qml | 16 +++++++--------- .../quickshell/ii/modules/bar/ClockWidget.qml | 18 ++++++++---------- .config/quickshell/ii/modules/bar/Resource.qml | 10 ++++------ .../ii/modules/bar/weather/WeatherCard.qml | 13 +++++++------ .../ii/modules/bar/weather/WeatherPopup.qml | 7 +++---- .../ii/modules/common/widgets/StyledPopup.qml | 2 +- 6 files changed, 30 insertions(+), 36 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BatteryPopup.qml b/.config/quickshell/ii/modules/bar/BatteryPopup.qml index 985873d85..4138aad8c 100644 --- a/.config/quickshell/ii/modules/bar/BatteryPopup.qml +++ b/.config/quickshell/ii/modules/bar/BatteryPopup.qml @@ -10,10 +10,8 @@ Rectangle { readonly property real margin: 10 implicitWidth: columnLayout.implicitWidth + margin * 2 implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colLayer0 + color: Appearance.colors.colTooltip radius: Appearance.rounding.small - border.width: 1 - border.color: Appearance.colors.colLayer0Border clip: true ColumnLayout { @@ -34,12 +32,12 @@ Rectangle { opacity: rowVisible ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 500 } } - MaterialSymbol { text: "schedule"; color: Appearance.m3colors.m3onSecondaryContainer } - StyledText { text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:"); color: Appearance.colors.colOnLayer1 } + MaterialSymbol { text: "schedule"; color: Appearance.colors.colOnTooltip } + StyledText { text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:"); color: Appearance.colors.colOnTooltip } StyledText { Layout.fillWidth: true horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnLayer1 + color: Appearance.colors.colOnTooltip text: { function formatTime(seconds) { var h = Math.floor(seconds / 3600); @@ -82,7 +80,7 @@ Rectangle { return "battery_0_bar"; } } - color: Appearance.m3colors.m3onSecondaryContainer + color: Appearance.colors.colOnTooltip } @@ -96,13 +94,13 @@ Rectangle { return Translation.tr("Discharging:"); } } - color: Appearance.colors.colOnLayer1 + color: Appearance.colors.colOnTooltip } StyledText { Layout.fillWidth: true horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnLayer1 + color: Appearance.colors.colOnTooltip text: { if (Battery.chargeState == 4) { return ""; diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index c7ffeed38..9242519d7 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -53,10 +53,8 @@ Item { readonly property real margin: 12 implicitWidth: columnLayout.implicitWidth + margin * 2 implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colLayer0 + color: Appearance.colors.colTooltip radius: Appearance.rounding.small - border.width: 1 - border.color: Appearance.colors.colLayer0Border clip: true ColumnLayout { @@ -71,7 +69,7 @@ Item { StyledText { Layout.fillWidth: true horizontalAlignment: Text.AlignLeft - color: Appearance.colors.colOnLayer1 + color: Appearance.colors.colOnTooltip text: `${root.formattedDate} • ${root.formattedTime}` } } @@ -80,12 +78,12 @@ Item { RowLayout { spacing: 5 Layout.fillWidth: true - MaterialSymbol { text: "timelapse"; color: Appearance.m3colors.m3onSecondaryContainer } - StyledText { text: Translation.tr("Uptime:"); color: Appearance.colors.colOnLayer1 } + MaterialSymbol { text: "timelapse"; color: Appearance.colors.colOnTooltip } + StyledText { text: Translation.tr("Uptime:"); color: Appearance.colors.colOnTooltip } StyledText { Layout.fillWidth: true horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnLayer1 + color: Appearance.colors.colOnTooltip text: root.formattedUptime } } @@ -98,8 +96,8 @@ Item { RowLayout { spacing: 5 Layout.fillWidth: true - MaterialSymbol { text: "checklist"; color: Appearance.m3colors.m3onSecondaryContainer } - StyledText { text: Translation.tr("Upcoming Tasks:"); color: Appearance.colors.colOnLayer1 } + MaterialSymbol { text: "checklist"; color: Appearance.colors.colOnTooltip } + StyledText { text: Translation.tr("Upcoming Tasks:"); color: Appearance.colors.colOnTooltip } } StyledText { @@ -107,7 +105,7 @@ Item { topPadding: 5 horizontalAlignment: Text.AlignLeft wrapMode: Text.Wrap - color: Appearance.colors.colOnLayer1 + color: Appearance.colors.colOnTooltip text: root.todosSection } } diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index a352e0eb7..fbd259372 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -75,10 +75,8 @@ Item { readonly property real margin: 10 implicitWidth: columnLayout.implicitWidth + margin * 2 implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colLayer0 + color: Appearance.colors.colTooltip radius: Appearance.rounding.small - border.width: 1 - border.color: Appearance.colors.colLayer0Border clip: true ColumnLayout { @@ -94,17 +92,17 @@ Item { MaterialSymbol { text: modelData.icon - color: Appearance.m3colors.m3onSecondaryContainer + color: Appearance.colors.colOnTooltip } StyledText { text: modelData.label - color: Appearance.colors.colOnLayer1 + color: Appearance.colors.colOnTooltip } StyledText { Layout.fillWidth: true horizontalAlignment: Text.AlignRight visible: modelData.value !== "" - color: Appearance.colors.colOnLayer1 + color: Appearance.colors.colOnTooltip text: modelData.value } } diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherCard.qml b/.config/quickshell/ii/modules/bar/weather/WeatherCard.qml index a85ed8ca3..03b9a189c 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherCard.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherCard.qml @@ -7,9 +7,9 @@ import qs.modules.common.widgets Rectangle { id: root radius: Appearance.rounding.small - color: Appearance.colors.colLayer1 - implicitWidth: columnLayout.implicitWidth * 2 - implicitHeight: columnLayout.implicitHeight * 2 + color: Appearance.colors.colTooltip + implicitWidth: columnLayout.implicitWidth + 14 * 2 + implicitHeight: columnLayout.implicitHeight + 14 * 2 Layout.fillWidth: parent property alias title: title.text @@ -26,18 +26,19 @@ Rectangle { id: symbol fill: 0 iconSize: Appearance.font.pixelSize.normal + color: Appearance.colors.colOnTooltip } StyledText { id: title font.pixelSize: Appearance.font.pixelSize.smaller - color: Appearance.colors.colOnLayer1 + color: Appearance.colors.colOnTooltip } } StyledText { id: value Layout.alignment: Qt.AlignHCenter - font.pixelSize: Appearance.font.pixelSize.normal - color: Appearance.colors.colOnLayer1 + font.pixelSize: Appearance.font.pixelSize.small + color: Appearance.colors.colOnTooltip } } } diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml b/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml index 827abea4f..91269e2a2 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml @@ -11,10 +11,8 @@ Rectangle { readonly property real margin: 10 implicitWidth: columnLayout.implicitWidth + margin * 2 implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colLayer0 + color: Appearance.colors.colTooltip radius: Appearance.rounding.small - border.width: 1 - border.color: Appearance.colors.colLayer0Border clip: true ColumnLayout { @@ -34,13 +32,14 @@ Rectangle { fill: 0 text: "location_on" iconSize: Appearance.font.pixelSize.huge + color: Appearance.colors.colOnTooltip } StyledText { text: Weather.data.city font.pixelSize: Appearance.font.pixelSize.title font.family: Appearance.font.family.title - color: Appearance.colors.colOnLayer0 + color: Appearance.colors.colOnTooltip } } diff --git a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml index df5bdec1a..85ca0c532 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml @@ -36,7 +36,7 @@ LazyLoader { top: Appearance.sizes.hyprlandGapsOut bottom: Appearance.sizes.hyprlandGapsOut } - WlrLayershell.namespace: "quickshell:popup" //maybe this can fix with the popups not showing ? + WlrLayershell.namespace: "quickshell:popup" WlrLayershell.layer: WlrLayer.Overlay Loader { From 70a5520f47d5cf8ce94f8ffd037abcba102f0a35 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:33:35 +0700 Subject: [PATCH 11/17] bar tooltips: adjust icons --- .../quickshell/ii/modules/bar/ClockWidget.qml | 6 +++--- .config/quickshell/ii/modules/bar/Resource.qml | 18 ++++++++---------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index 9242519d7..9a4fce4f0 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -79,7 +79,7 @@ Item { spacing: 5 Layout.fillWidth: true MaterialSymbol { text: "timelapse"; color: Appearance.colors.colOnTooltip } - StyledText { text: Translation.tr("Uptime:"); color: Appearance.colors.colOnTooltip } + StyledText { text: Translation.tr("System uptime:"); color: Appearance.colors.colOnTooltip } StyledText { Layout.fillWidth: true horizontalAlignment: Text.AlignRight @@ -88,7 +88,7 @@ Item { } } - // Upcoming tasks row + // Tasks ColumnLayout { spacing: 2 Layout.fillWidth: true @@ -97,7 +97,7 @@ Item { spacing: 5 Layout.fillWidth: true MaterialSymbol { text: "checklist"; color: Appearance.colors.colOnTooltip } - StyledText { text: Translation.tr("Upcoming Tasks:"); color: Appearance.colors.colOnTooltip } + StyledText { text: Translation.tr("To Do:"); color: Appearance.colors.colOnTooltip } } StyledText { diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index fbd259372..bc60575dc 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -27,19 +27,17 @@ Item { case "memory": return [ { icon: "memory", label: Translation.tr("Memory Usage"), value: "" }, - { icon: "storage", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.memoryUsed) }, + { icon: "clock_loader_60", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.memoryUsed) }, { icon: "check_circle", label: Translation.tr("Free:"), value: formatKB(ResourceUsage.memoryFree) }, - { icon: "dns", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.memoryTotal) }, - { icon: "percent", label: Translation.tr("Usage:"), value: `${Math.round(ResourceUsage.memoryUsedPercentage * 100)}%` } + { icon: "empty_dashboard", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.memoryTotal) }, ] case "swap_horiz": return ResourceUsage.swapTotal > 0 ? [ { icon: "swap_horiz", label: Translation.tr("Swap Usage"), value: "" }, - { icon: "storage", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.swapUsed) }, + { icon: "clock_loader_60", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.swapUsed) }, { icon: "check_circle", label: Translation.tr("Free:"), value: formatKB(ResourceUsage.swapFree) }, - { icon: "dns", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.swapTotal) }, - { icon: "percent", label: Translation.tr("Usage:"), value: `${Math.round(ResourceUsage.swapUsedPercentage * 100)}%` } + { icon: "empty_dashboard", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.swapTotal) }, ] : [ { icon: "swap_horiz", label: Translation.tr("Swap:"), value: Translation.tr("Not configured") } @@ -47,10 +45,10 @@ Item { case "settings_slow_motion": return [ { icon: "settings_slow_motion", label: Translation.tr("CPU Usage"), value: "" }, - { icon: "bolt", label: Translation.tr("Current:"), value: `${Math.round(ResourceUsage.cpuUsage * 100)}%` }, - { icon: "speed", label: Translation.tr("Load:"), value: ResourceUsage.cpuUsage > 0.8 ? + { icon: "bolt", label: Translation.tr("Load:"), value: (ResourceUsage.cpuUsage > 0.8 ? Translation.tr("High") : - ResourceUsage.cpuUsage > 0.5 ? Translation.tr("Medium") : Translation.tr("Low") + ResourceUsage.cpuUsage > 0.4 ? Translation.tr("Medium") : Translation.tr("Low")) + + ` (${Math.round(ResourceUsage.cpuUsage * 100)}%)` } ] default: @@ -130,7 +128,7 @@ Item { anchors.centerIn: parent fill: 1 text: iconName - iconSize: Appearance.font.pixelSize.normal + iconSize: Appearance.font.pixelSize.large color: Appearance.m3colors.m3onSecondaryContainer } From 291b9979724bf128a00469a8428bb43146490901 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Aug 2025 20:12:20 +0700 Subject: [PATCH 12/17] bar tooltips: use correct color, add subhead text --- .../ii/modules/bar/BatteryPopup.qml | 77 +++++--- .../quickshell/ii/modules/bar/ClockWidget.qml | 154 ++++++++-------- .../quickshell/ii/modules/bar/Resource.qml | 169 +++++++++--------- .../quickshell/ii/modules/bar/Resources.qml | 29 +++ .../ii/modules/bar/weather/WeatherCard.qml | 8 +- .../ii/modules/bar/weather/WeatherPopup.qml | 17 +- .../ii/modules/common/Appearance.qml | 2 + 7 files changed, 255 insertions(+), 201 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BatteryPopup.qml b/.config/quickshell/ii/modules/bar/BatteryPopup.qml index 4138aad8c..cfe16ef73 100644 --- a/.config/quickshell/ii/modules/bar/BatteryPopup.qml +++ b/.config/quickshell/ii/modules/bar/BatteryPopup.qml @@ -10,14 +10,37 @@ Rectangle { readonly property real margin: 10 implicitWidth: columnLayout.implicitWidth + margin * 2 implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colTooltip + color: Appearance.colors.colSurfaceContainer radius: Appearance.rounding.small clip: true ColumnLayout { id: columnLayout anchors.centerIn: parent - spacing: 8 + spacing: 4 + + // Header + RowLayout { + id: header + spacing: 5 + + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: "battery_android_full" + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant + } + + StyledText { + text: "Battery" + font { + weight: Font.Medium + pixelSize: Appearance.font.pixelSize.normal + } + color: Appearance.colors.colOnSurfaceVariant + } + } // This row is hidden when the battery is full. RowLayout { @@ -30,14 +53,25 @@ Rectangle { } visible: rowVisible opacity: rowVisible ? 1 : 0 - Behavior on opacity { NumberAnimation { duration: 500 } } + Behavior on opacity { + NumberAnimation { + duration: 500 + } + } - MaterialSymbol { text: "schedule"; color: Appearance.colors.colOnTooltip } - StyledText { text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:"); color: Appearance.colors.colOnTooltip } + MaterialSymbol { + text: "schedule" + color: Appearance.colors.colOnSurfaceVariant + iconSize: Appearance.font.pixelSize.large + } + StyledText { + text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:") + color: Appearance.colors.colOnSurfaceVariant + } StyledText { Layout.fillWidth: true horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnTooltip + color: Appearance.colors.colOnSurfaceVariant text: { function formatTime(seconds) { var h = Math.floor(seconds / 3600); @@ -62,27 +96,17 @@ Rectangle { property bool rowVisible: !(Battery.chargeState != 4 && Battery.energyRate == 0) visible: rowVisible opacity: rowVisible ? 1 : 0 - Behavior on opacity { NumberAnimation { duration: 500 } } - - MaterialSymbol { - text: { - if (Battery.isCharging) { - return "power"; - } else if (Battery.percentage >= 0.8) { - return "battery_full"; - } else if (Battery.percentage >= 0.6) { - return "battery_5_bar"; - } else if (Battery.percentage >= 0.4) { - return "battery_4_bar"; - } else if (Battery.percentage >= 0.2) { - return "battery_2_bar"; - } else { - return "battery_0_bar"; - } + Behavior on opacity { + NumberAnimation { + duration: 500 } - color: Appearance.colors.colOnTooltip } + MaterialSymbol { + text: "bolt" + color: Appearance.colors.colOnSurfaceVariant + iconSize: Appearance.font.pixelSize.large + } StyledText { text: { @@ -94,13 +118,13 @@ Rectangle { return Translation.tr("Discharging:"); } } - color: Appearance.colors.colOnTooltip + color: Appearance.colors.colOnSurfaceVariant } StyledText { Layout.fillWidth: true horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnTooltip + color: Appearance.colors.colOnSurfaceVariant text: { if (Battery.chargeState == 4) { return ""; @@ -110,6 +134,5 @@ Rectangle { } } } - } } diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index 9a4fce4f0..1523cebd2 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -39,80 +39,6 @@ Item { property string formattedUptime: DateTime.uptime property string todosSection: getUpcomingTodos() - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.NoButton - } - - StyledPopup { - hoverTarget: mouseArea - contentComponent: Rectangle { - id: datePopup - readonly property real margin: 12 - implicitWidth: columnLayout.implicitWidth + margin * 2 - implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colTooltip - radius: Appearance.rounding.small - clip: true - - ColumnLayout { - id: columnLayout - anchors.centerIn: parent - spacing: 8 - - // Date + Time row - RowLayout { - spacing: 5 - Layout.fillWidth: true - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignLeft - color: Appearance.colors.colOnTooltip - text: `${root.formattedDate} • ${root.formattedTime}` - } - } - - // Uptime row - RowLayout { - spacing: 5 - Layout.fillWidth: true - MaterialSymbol { text: "timelapse"; color: Appearance.colors.colOnTooltip } - StyledText { text: Translation.tr("System uptime:"); color: Appearance.colors.colOnTooltip } - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnTooltip - text: root.formattedUptime - } - } - - // Tasks - ColumnLayout { - spacing: 2 - Layout.fillWidth: true - - RowLayout { - spacing: 5 - Layout.fillWidth: true - MaterialSymbol { text: "checklist"; color: Appearance.colors.colOnTooltip } - StyledText { text: Translation.tr("To Do:"); color: Appearance.colors.colOnTooltip } - } - - StyledText { - Layout.fillWidth: true - topPadding: 5 - horizontalAlignment: Text.AlignLeft - wrapMode: Text.Wrap - color: Appearance.colors.colOnTooltip - text: root.todosSection - } - } - } - } - } - RowLayout { id: rowLayout anchors.centerIn: parent @@ -140,4 +66,84 @@ Item { } + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + + StyledPopup { + hoverTarget: mouseArea + contentComponent: Rectangle { + id: datePopup + readonly property real margin: 12 + implicitWidth: columnLayout.implicitWidth + margin * 2 + implicitHeight: columnLayout.implicitHeight + margin * 2 + color: Appearance.colors.colSurfaceContainer + radius: Appearance.rounding.small + clip: true + + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 4 + + // Date + Time row + RowLayout { + spacing: 5 + + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: "calendar_month" + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant + } + StyledText { + horizontalAlignment: Text.AlignLeft + color: Appearance.colors.colOnSurfaceVariant + text: `${root.formattedDate} • ${root.formattedTime}` + font.weight: Font.Medium + } + } + + // Uptime row + RowLayout { + spacing: 5 + Layout.fillWidth: true + MaterialSymbol { text: "timelapse"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large } + StyledText { text: Translation.tr("System uptime:"); color: Appearance.colors.colOnSurfaceVariant } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnSurfaceVariant + text: root.formattedUptime + } + } + + // Tasks + ColumnLayout { + spacing: 0 + Layout.fillWidth: true + + RowLayout { + spacing: 4 + Layout.fillWidth: true + MaterialSymbol { text: "checklist"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large } + StyledText { text: Translation.tr("To Do:"); color: Appearance.colors.colOnSurfaceVariant } + } + + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + color: Appearance.colors.colOnSurfaceVariant + text: root.todosSection + } + } + } + } + } + } diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index bc60575dc..8b0eb1633 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -10,6 +10,9 @@ Item { id: root required property string iconName required property double percentage + property var tooltipData: [{ icon: "info", label: "System resource", value: "" }] + property var tooltipHeaderIcon + property var tooltipHeaderText property bool shown: true clip: true visible: width > 0 && height > 0 @@ -21,95 +24,6 @@ Item { return (kb / (1024 * 1024)).toFixed(1) + " GB" } - // Generate tooltip content based on resource type - property var tooltipData: { - switch(iconName) { - case "memory": - return [ - { icon: "memory", label: Translation.tr("Memory Usage"), value: "" }, - { icon: "clock_loader_60", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.memoryUsed) }, - { icon: "check_circle", label: Translation.tr("Free:"), value: formatKB(ResourceUsage.memoryFree) }, - { icon: "empty_dashboard", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.memoryTotal) }, - ] - case "swap_horiz": - return ResourceUsage.swapTotal > 0 ? - [ - { icon: "swap_horiz", label: Translation.tr("Swap Usage"), value: "" }, - { icon: "clock_loader_60", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.swapUsed) }, - { icon: "check_circle", label: Translation.tr("Free:"), value: formatKB(ResourceUsage.swapFree) }, - { icon: "empty_dashboard", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.swapTotal) }, - ] : - [ - { icon: "swap_horiz", label: Translation.tr("Swap:"), value: Translation.tr("Not configured") } - ] - case "settings_slow_motion": - return [ - { icon: "settings_slow_motion", label: Translation.tr("CPU Usage"), value: "" }, - { icon: "bolt", label: Translation.tr("Load:"), value: (ResourceUsage.cpuUsage > 0.8 ? - Translation.tr("High") : - ResourceUsage.cpuUsage > 0.4 ? Translation.tr("Medium") : Translation.tr("Low")) - + ` (${Math.round(ResourceUsage.cpuUsage * 100)}%)` - } - ] - default: - return [ - { icon: "info", label: Translation.tr("System Resource"), value: "" } - ] - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.NoButton - enabled: resourceRowLayout.x >= 0 && root.width > 0 && root.visible - } - - StyledPopup { - hoverTarget: mouseArea - contentComponent: Rectangle { - id: resourcePopup - readonly property real margin: 10 - implicitWidth: columnLayout.implicitWidth + margin * 2 - implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colTooltip - radius: Appearance.rounding.small - clip: true - - ColumnLayout { - id: columnLayout - anchors.centerIn: parent - spacing: 6 - - Repeater { - model: root.tooltipData - delegate: RowLayout { - spacing: 5 - Layout.fillWidth: true - - MaterialSymbol { - text: modelData.icon - color: Appearance.colors.colOnTooltip - } - StyledText { - text: modelData.label - color: Appearance.colors.colOnTooltip - } - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - visible: modelData.value !== "" - color: Appearance.colors.colOnTooltip - text: modelData.value - } - } - } - - } - } - } - RowLayout { spacing: 4 id: resourceRowLayout @@ -146,6 +60,83 @@ Item { } + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + enabled: resourceRowLayout.x >= 0 && root.width > 0 && root.visible + } + + StyledPopup { + hoverTarget: mouseArea + contentComponent: Rectangle { + id: resourcePopup + readonly property real margin: 10 + implicitWidth: columnLayout.implicitWidth + margin * 2 + implicitHeight: columnLayout.implicitHeight + margin * 2 + color: Appearance.colors.colSurfaceContainer + radius: Appearance.rounding.small + clip: true + + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 4 + + // Header + RowLayout { + id: header + spacing: 5 + + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: root.tooltipHeaderIcon + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant + } + + StyledText { + text: root.tooltipHeaderText + font { + weight: Font.Medium + pixelSize: Appearance.font.pixelSize.normal + } + color: Appearance.colors.colOnSurfaceVariant + } + } + + // Info rows + Repeater { + model: root.tooltipData + delegate: RowLayout { + spacing: 5 + Layout.fillWidth: true + + MaterialSymbol { + text: modelData.icon + color: Appearance.colors.colOnSurfaceVariant + iconSize: Appearance.font.pixelSize.large + } + StyledText { + text: modelData.label + color: Appearance.colors.colOnSurfaceVariant + } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + visible: modelData.value !== "" + color: Appearance.colors.colOnSurfaceVariant + text: modelData.value + } + } + } + + } + } + } + Behavior on implicitWidth { NumberAnimation { duration: Appearance.animation.elementMove.duration diff --git a/.config/quickshell/ii/modules/bar/Resources.qml b/.config/quickshell/ii/modules/bar/Resources.qml index f57372a18..8d39de037 100644 --- a/.config/quickshell/ii/modules/bar/Resources.qml +++ b/.config/quickshell/ii/modules/bar/Resources.qml @@ -1,6 +1,7 @@ import qs.modules.common import qs.modules.common.widgets import qs.services +import qs import QtQuick import QtQuick.Layouts @@ -22,6 +23,14 @@ Item { Resource { iconName: "memory" percentage: ResourceUsage.memoryUsedPercentage + + tooltipHeaderIcon: "memory" + tooltipHeaderText: Translation.tr("Memory usage") + tooltipData: [ + { icon: "clock_loader_60", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.memoryUsed) }, + { icon: "check_circle", label: Translation.tr("Free:"), value: formatKB(ResourceUsage.memoryFree) }, + { icon: "empty_dashboard", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.memoryTotal) }, + ] } Resource { @@ -31,6 +40,16 @@ Item { (MprisController.activePlayer?.trackTitle == null) || root.alwaysShowAllResources Layout.leftMargin: shown ? 4 : 0 + + tooltipHeaderIcon: "swap_horiz" + tooltipHeaderText: Translation.tr("Swap usage") + tooltipData: ResourceUsage.swapTotal > 0 ? [ + { icon: "clock_loader_60", label: Translation.tr("Used:"), value: formatKB(ResourceUsage.swapUsed) }, + { icon: "check_circle", label: Translation.tr("Free:"), value: formatKB(ResourceUsage.swapFree) }, + { icon: "empty_dashboard", label: Translation.tr("Total:"), value: formatKB(ResourceUsage.swapTotal) }, + ] : [ + { icon: "swap_horiz", label: Translation.tr("Swap:"), value: Translation.tr("Not configured") } + ] } Resource { @@ -40,6 +59,16 @@ Item { !(MprisController.activePlayer?.trackTitle?.length > 0) || root.alwaysShowAllResources Layout.leftMargin: shown ? 4 : 0 + + tooltipHeaderIcon: "settings_slow_motion" + tooltipHeaderText: Translation.tr("CPU usage") + tooltipData: [ + { icon: "bolt", label: Translation.tr("Load:"), value: (ResourceUsage.cpuUsage > 0.8 ? + Translation.tr("High") : + ResourceUsage.cpuUsage > 0.4 ? Translation.tr("Medium") : Translation.tr("Low")) + + ` (${Math.round(ResourceUsage.cpuUsage * 100)}%)` + } + ] } } diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherCard.qml b/.config/quickshell/ii/modules/bar/weather/WeatherCard.qml index 03b9a189c..e75dda32f 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherCard.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherCard.qml @@ -7,7 +7,7 @@ import qs.modules.common.widgets Rectangle { id: root radius: Appearance.rounding.small - color: Appearance.colors.colTooltip + color: Appearance.colors.colSurfaceContainerHigh implicitWidth: columnLayout.implicitWidth + 14 * 2 implicitHeight: columnLayout.implicitHeight + 14 * 2 Layout.fillWidth: parent @@ -26,19 +26,19 @@ Rectangle { id: symbol fill: 0 iconSize: Appearance.font.pixelSize.normal - color: Appearance.colors.colOnTooltip + color: Appearance.colors.colOnSurfaceVariant } StyledText { id: title font.pixelSize: Appearance.font.pixelSize.smaller - color: Appearance.colors.colOnTooltip + color: Appearance.colors.colOnSurfaceVariant } } StyledText { id: value Layout.alignment: Qt.AlignHCenter font.pixelSize: Appearance.font.pixelSize.small - color: Appearance.colors.colOnTooltip + color: Appearance.colors.colOnSurfaceVariant } } } diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml b/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml index 91269e2a2..1e7c39504 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml @@ -11,7 +11,7 @@ Rectangle { readonly property real margin: 10 implicitWidth: columnLayout.implicitWidth + margin * 2 implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colTooltip + color: Appearance.colors.colSurfaceContainer radius: Appearance.rounding.small clip: true @@ -26,20 +26,23 @@ Rectangle { RowLayout { id: header spacing: 5 - Layout.fillWidth: parent Layout.alignment: Qt.AlignHCenter + MaterialSymbol { fill: 0 + font.weight: Font.Medium text: "location_on" - iconSize: Appearance.font.pixelSize.huge - color: Appearance.colors.colOnTooltip + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant } StyledText { text: Weather.data.city - font.pixelSize: Appearance.font.pixelSize.title - font.family: Appearance.font.family.title - color: Appearance.colors.colOnTooltip + font { + weight: Font.Medium + pixelSize: Appearance.font.pixelSize.normal + } + color: Appearance.colors.colOnSurfaceVariant } } diff --git a/.config/quickshell/ii/modules/common/Appearance.qml b/.config/quickshell/ii/modules/common/Appearance.qml index 9c9374860..e71eb4274 100644 --- a/.config/quickshell/ii/modules/common/Appearance.qml +++ b/.config/quickshell/ii/modules/common/Appearance.qml @@ -141,6 +141,8 @@ Singleton { property color colSurfaceContainerHighest: ColorUtils.transparentize(m3colors.m3surfaceContainerHighest, root.contentTransparency) property color colSurfaceContainerHighestHover: ColorUtils.mix(m3colors.m3surfaceContainerHighest, m3colors.m3onSurface, 0.95) property color colSurfaceContainerHighestActive: ColorUtils.mix(m3colors.m3surfaceContainerHighest, m3colors.m3onSurface, 0.85) + property color colOnSurface: m3colors.m3onSurface + property color colOnSurfaceVariant: m3colors.m3onSurfaceVariant property color colTooltip: m3colors.m3inverseSurface property color colOnTooltip: m3colors.m3inverseOnSurface property color colScrim: ColorUtils.transparentize(m3colors.m3scrim, 0.5) From 6a8a9172b1a98580390a28564908691273871e11 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Aug 2025 20:33:01 +0700 Subject: [PATCH 13/17] bar tooltips: refractor tooltip bg to StyledPopup --- .../ii/modules/bar/BatteryIndicator.qml | 3 +- .../ii/modules/bar/BatteryPopup.qml | 214 +++++++++--------- .../quickshell/ii/modules/bar/ClockWidget.qml | 109 ++++----- .../quickshell/ii/modules/bar/Resource.qml | 91 ++++---- .../ii/modules/bar/weather/WeatherBar.qml | 3 +- .../ii/modules/bar/weather/WeatherPopup.qml | 155 ++++++------- .../ii/modules/common/widgets/StyledPopup.qml | 24 +- 7 files changed, 284 insertions(+), 315 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml index d2f17e598..5172b5891 100644 --- a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml +++ b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml @@ -97,7 +97,8 @@ MouseArea { StyledPopup { hoverTarget: root - contentComponent: BatteryPopup { + + BatteryPopup { id: batteryPopup anchors.centerIn: parent } diff --git a/.config/quickshell/ii/modules/bar/BatteryPopup.qml b/.config/quickshell/ii/modules/bar/BatteryPopup.qml index cfe16ef73..9b9edc5a1 100644 --- a/.config/quickshell/ii/modules/bar/BatteryPopup.qml +++ b/.config/quickshell/ii/modules/bar/BatteryPopup.qml @@ -5,134 +5,124 @@ import qs import QtQuick import QtQuick.Layouts -Rectangle { - id: root - readonly property real margin: 10 - implicitWidth: columnLayout.implicitWidth + margin * 2 - implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colSurfaceContainer - radius: Appearance.rounding.small - clip: true +ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 4 - ColumnLayout { - id: columnLayout - anchors.centerIn: parent - spacing: 4 + // Header + RowLayout { + id: header + spacing: 5 - // Header - RowLayout { - id: header - spacing: 5 + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: "battery_android_full" + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant + } - MaterialSymbol { - fill: 0 - font.weight: Font.Medium - text: "battery_android_full" - iconSize: Appearance.font.pixelSize.large - color: Appearance.colors.colOnSurfaceVariant + StyledText { + text: "Battery" + font { + weight: Font.Medium + pixelSize: Appearance.font.pixelSize.normal } + color: Appearance.colors.colOnSurfaceVariant + } + } - StyledText { - text: "Battery" - font { - weight: Font.Medium - pixelSize: Appearance.font.pixelSize.normal - } - color: Appearance.colors.colOnSurfaceVariant + // This row is hidden when the battery is full. + RowLayout { + spacing: 5 + Layout.fillWidth: true + property bool rowVisible: { + let timeValue = Battery.isCharging ? Battery.timeToFull : Battery.timeToEmpty; + let power = Battery.energyRate; + return !(Battery.chargeState == 4 || timeValue <= 0 || power <= 0.01); + } + visible: rowVisible + opacity: rowVisible ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: 500 } } - // This row is hidden when the battery is full. - RowLayout { - spacing: 5 + MaterialSymbol { + text: "schedule" + color: Appearance.colors.colOnSurfaceVariant + iconSize: Appearance.font.pixelSize.large + } + StyledText { + text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:") + color: Appearance.colors.colOnSurfaceVariant + } + StyledText { Layout.fillWidth: true - property bool rowVisible: { - let timeValue = Battery.isCharging ? Battery.timeToFull : Battery.timeToEmpty; - let power = Battery.energyRate; - return !(Battery.chargeState == 4 || timeValue <= 0 || power <= 0.01); - } - visible: rowVisible - opacity: rowVisible ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: 500 - } - } - - MaterialSymbol { - text: "schedule" - color: Appearance.colors.colOnSurfaceVariant - iconSize: Appearance.font.pixelSize.large - } - StyledText { - text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:") - color: Appearance.colors.colOnSurfaceVariant - } - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnSurfaceVariant - text: { - function formatTime(seconds) { - var h = Math.floor(seconds / 3600); - var m = Math.floor((seconds % 3600) / 60); - if (h > 0) - return `${h}h, ${m}m`; - else - return `${m}m`; - } - if (Battery.isCharging) - return formatTime(Battery.timeToFull); + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnSurfaceVariant + text: { + function formatTime(seconds) { + var h = Math.floor(seconds / 3600); + var m = Math.floor((seconds % 3600) / 60); + if (h > 0) + return `${h}h, ${m}m`; else - return formatTime(Battery.timeToEmpty); + return `${m}m`; } + if (Battery.isCharging) + return formatTime(Battery.timeToFull); + else + return formatTime(Battery.timeToEmpty); + } + } + } + + RowLayout { + spacing: 5 + Layout.fillWidth: true + + property bool rowVisible: !(Battery.chargeState != 4 && Battery.energyRate == 0) + visible: rowVisible + opacity: rowVisible ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: 500 } } - RowLayout { - spacing: 5 + MaterialSymbol { + text: "bolt" + color: Appearance.colors.colOnSurfaceVariant + iconSize: Appearance.font.pixelSize.large + } + + StyledText { + text: { + if (Battery.chargeState == 4) { + return Translation.tr("Fully charged"); + } else if (Battery.chargeState == 1) { + return Translation.tr("Charging:"); + } else { + return Translation.tr("Discharging:"); + } + } + color: Appearance.colors.colOnSurfaceVariant + } + + StyledText { Layout.fillWidth: true - - property bool rowVisible: !(Battery.chargeState != 4 && Battery.energyRate == 0) - visible: rowVisible - opacity: rowVisible ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: 500 - } - } - - MaterialSymbol { - text: "bolt" - color: Appearance.colors.colOnSurfaceVariant - iconSize: Appearance.font.pixelSize.large - } - - StyledText { - text: { - if (Battery.chargeState == 4) { - return Translation.tr("Fully charged"); - } else if (Battery.chargeState == 1) { - return Translation.tr("Charging:"); - } else { - return Translation.tr("Discharging:"); - } - } - color: Appearance.colors.colOnSurfaceVariant - } - - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnSurfaceVariant - text: { - if (Battery.chargeState == 4) { - return ""; - } else { - return `${Battery.energyRate.toFixed(2)}W`; - } + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnSurfaceVariant + text: { + if (Battery.chargeState == 4) { + return ""; + } else { + return `${Battery.energyRate.toFixed(2)}W`; } } } } -} +} \ No newline at end of file diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index 1523cebd2..973039116 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -75,72 +75,63 @@ Item { StyledPopup { hoverTarget: mouseArea - contentComponent: Rectangle { - id: datePopup - readonly property real margin: 12 - implicitWidth: columnLayout.implicitWidth + margin * 2 - implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colSurfaceContainer - radius: Appearance.rounding.small - clip: true + + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 4 + // Date + Time row + RowLayout { + spacing: 5 + + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: "calendar_month" + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant + } + StyledText { + horizontalAlignment: Text.AlignLeft + color: Appearance.colors.colOnSurfaceVariant + text: `${root.formattedDate} • ${root.formattedTime}` + font.weight: Font.Medium + } + } + + // Uptime row + RowLayout { + spacing: 5 + Layout.fillWidth: true + MaterialSymbol { text: "timelapse"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large } + StyledText { text: Translation.tr("System uptime:"); color: Appearance.colors.colOnSurfaceVariant } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnSurfaceVariant + text: root.formattedUptime + } + } + + // Tasks ColumnLayout { - id: columnLayout - anchors.centerIn: parent - spacing: 4 + spacing: 0 + Layout.fillWidth: true - // Date + Time row RowLayout { - spacing: 5 - - MaterialSymbol { - fill: 0 - font.weight: Font.Medium - text: "calendar_month" - iconSize: Appearance.font.pixelSize.large - color: Appearance.colors.colOnSurfaceVariant - } - StyledText { - horizontalAlignment: Text.AlignLeft - color: Appearance.colors.colOnSurfaceVariant - text: `${root.formattedDate} • ${root.formattedTime}` - font.weight: Font.Medium - } + spacing: 4 + Layout.fillWidth: true + MaterialSymbol { text: "checklist"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large } + StyledText { text: Translation.tr("To Do:"); color: Appearance.colors.colOnSurfaceVariant } } - // Uptime row - RowLayout { - spacing: 5 + StyledText { Layout.fillWidth: true - MaterialSymbol { text: "timelapse"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large } - StyledText { text: Translation.tr("System uptime:"); color: Appearance.colors.colOnSurfaceVariant } - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnSurfaceVariant - text: root.formattedUptime - } - } - - // Tasks - ColumnLayout { - spacing: 0 - Layout.fillWidth: true - - RowLayout { - spacing: 4 - Layout.fillWidth: true - MaterialSymbol { text: "checklist"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large } - StyledText { text: Translation.tr("To Do:"); color: Appearance.colors.colOnSurfaceVariant } - } - - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignLeft - wrapMode: Text.Wrap - color: Appearance.colors.colOnSurfaceVariant - text: root.todosSection - } + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + color: Appearance.colors.colOnSurfaceVariant + text: root.todosSection } } } diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index 8b0eb1633..a57501335 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -70,70 +70,61 @@ Item { StyledPopup { hoverTarget: mouseArea - contentComponent: Rectangle { - id: resourcePopup - readonly property real margin: 10 - implicitWidth: columnLayout.implicitWidth + margin * 2 - implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colSurfaceContainer - radius: Appearance.rounding.small - clip: true + + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 4 - ColumnLayout { - id: columnLayout - anchors.centerIn: parent - spacing: 4 + // Header + RowLayout { + id: header + spacing: 5 - // Header - RowLayout { - id: header + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: root.tooltipHeaderIcon + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant + } + + StyledText { + text: root.tooltipHeaderText + font { + weight: Font.Medium + pixelSize: Appearance.font.pixelSize.normal + } + color: Appearance.colors.colOnSurfaceVariant + } + } + + // Info rows + Repeater { + model: root.tooltipData + delegate: RowLayout { spacing: 5 + Layout.fillWidth: true MaterialSymbol { - fill: 0 - font.weight: Font.Medium - text: root.tooltipHeaderIcon + text: modelData.icon + color: Appearance.colors.colOnSurfaceVariant iconSize: Appearance.font.pixelSize.large - color: Appearance.colors.colOnSurfaceVariant } - StyledText { - text: root.tooltipHeaderText - font { - weight: Font.Medium - pixelSize: Appearance.font.pixelSize.normal - } + text: modelData.label color: Appearance.colors.colOnSurfaceVariant } - } - - // Info rows - Repeater { - model: root.tooltipData - delegate: RowLayout { - spacing: 5 + StyledText { Layout.fillWidth: true - - MaterialSymbol { - text: modelData.icon - color: Appearance.colors.colOnSurfaceVariant - iconSize: Appearance.font.pixelSize.large - } - StyledText { - text: modelData.label - color: Appearance.colors.colOnSurfaceVariant - } - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - visible: modelData.value !== "" - color: Appearance.colors.colOnSurfaceVariant - text: modelData.value - } + horizontalAlignment: Text.AlignRight + visible: modelData.value !== "" + color: Appearance.colors.colOnSurfaceVariant + text: modelData.value } } - } + } } diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml index 8339d4829..42fe8b195 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml @@ -38,7 +38,8 @@ MouseArea { StyledPopup { hoverTarget: root - contentComponent: WeatherPopup { + + WeatherPopup { id: weatherPopup anchors.centerIn: parent } diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml b/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml index 1e7c39504..6297ea8cc 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml @@ -6,94 +6,83 @@ import qs.modules.common.widgets import QtQuick import QtQuick.Layouts -Rectangle { - id: root - readonly property real margin: 10 - implicitWidth: columnLayout.implicitWidth + margin * 2 - implicitHeight: columnLayout.implicitHeight + margin * 2 - color: Appearance.colors.colSurfaceContainer - radius: Appearance.rounding.small - clip: true +ColumnLayout { + id: columnLayout + spacing: 5 + implicitWidth: Math.max(header.implicitWidth, gridLayout.implicitWidth) + implicitHeight: gridLayout.implicitHeight - ColumnLayout { - id: columnLayout + // Header + RowLayout { + id: header spacing: 5 - anchors.centerIn: root - implicitWidth: Math.max(header.implicitWidth, gridLayout.implicitWidth) - implicitHeight: gridLayout.implicitHeight + Layout.alignment: Qt.AlignHCenter - // Header - RowLayout { - id: header - spacing: 5 - Layout.alignment: Qt.AlignHCenter - - MaterialSymbol { - fill: 0 - font.weight: Font.Medium - text: "location_on" - iconSize: Appearance.font.pixelSize.large - color: Appearance.colors.colOnSurfaceVariant - } - - StyledText { - text: Weather.data.city - font { - weight: Font.Medium - pixelSize: Appearance.font.pixelSize.normal - } - color: Appearance.colors.colOnSurfaceVariant - } + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: "location_on" + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant } - // Metrics grid - GridLayout { - id: gridLayout - columns: 2 - rowSpacing: 5 - columnSpacing: 5 - uniformCellWidths: true - - WeatherCard { - title: Translation.tr("UV Index") - symbol: "wb_sunny" - value: Weather.data.uv - } - WeatherCard { - title: Translation.tr("Wind") - symbol: "air" - value: `(${Weather.data.windDir}) ${Weather.data.wind}` - } - WeatherCard { - title: Translation.tr("Precipitation") - symbol: "rainy_light" - value: Weather.data.precip - } - WeatherCard { - title: Translation.tr("Humidity") - symbol: "humidity_low" - value: Weather.data.humidity - } - WeatherCard { - title: Translation.tr("Visibility") - symbol: "visibility" - value: Weather.data.visib - } - WeatherCard { - title: Translation.tr("Pressure") - symbol: "readiness_score" - value: Weather.data.press - } - WeatherCard { - title: Translation.tr("Sunrise") - symbol: "wb_twilight" - value: Weather.data.sunrise - } - WeatherCard { - title: Translation.tr("Sunset") - symbol: "bedtime" - value: Weather.data.sunset + StyledText { + text: Weather.data.city + font { + weight: Font.Medium + pixelSize: Appearance.font.pixelSize.normal } + color: Appearance.colors.colOnSurfaceVariant } } -} + + // Metrics grid + GridLayout { + id: gridLayout + columns: 2 + rowSpacing: 5 + columnSpacing: 5 + uniformCellWidths: true + + WeatherCard { + title: Translation.tr("UV Index") + symbol: "wb_sunny" + value: Weather.data.uv + } + WeatherCard { + title: Translation.tr("Wind") + symbol: "air" + value: `(${Weather.data.windDir}) ${Weather.data.wind}` + } + WeatherCard { + title: Translation.tr("Precipitation") + symbol: "rainy_light" + value: Weather.data.precip + } + WeatherCard { + title: Translation.tr("Humidity") + symbol: "humidity_low" + value: Weather.data.humidity + } + WeatherCard { + title: Translation.tr("Visibility") + symbol: "visibility" + value: Weather.data.visib + } + WeatherCard { + title: Translation.tr("Pressure") + symbol: "readiness_score" + value: Weather.data.press + } + WeatherCard { + title: Translation.tr("Sunrise") + symbol: "wb_twilight" + value: Weather.data.sunrise + } + WeatherCard { + title: Translation.tr("Sunset") + symbol: "bedtime" + value: Weather.data.sunset + } + } +} \ No newline at end of file diff --git a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml index 85ca0c532..028e0033d 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml @@ -10,8 +10,8 @@ import Quickshell.Wayland LazyLoader { id: root - property Item hoverTarget - property Component contentComponent + property MouseArea hoverTarget + default property Item contentItem active: hoverTarget && hoverTarget.containsMouse @@ -25,13 +25,13 @@ LazyLoader { anchors.top: !Config.options.bar.bottom anchors.bottom: Config.options.bar.bottom - implicitWidth: popupContent.implicitWidth - implicitHeight: popupContent.implicitHeight + implicitWidth: popupBackground.implicitWidth + implicitHeight: popupBackground.implicitHeight margins { left: root.QsWindow?.mapFromItem( root.hoverTarget, - (root.hoverTarget.width - popupContent.implicitWidth) / 2, 0 + (root.hoverTarget.width - popupBackground.implicitWidth) / 2, 0 ).x top: Appearance.sizes.hyprlandGapsOut bottom: Appearance.sizes.hyprlandGapsOut @@ -39,10 +39,16 @@ LazyLoader { WlrLayershell.namespace: "quickshell:popup" WlrLayershell.layer: WlrLayer.Overlay - Loader { - id: popupContent - sourceComponent: root.contentComponent - anchors.centerIn: parent + Rectangle { + id: popupBackground + readonly property real margin: 10 + color: Appearance.colors.colSurfaceContainer + radius: Appearance.rounding.small + + implicitWidth: root.contentItem.implicitWidth + margin * 2 + implicitHeight: root.contentItem.implicitHeight + margin * 2 + + children: [root.contentItem] } } } From af111a4be9b6274a04ec96045815ba3a1d5eb32a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Aug 2025 21:17:53 +0700 Subject: [PATCH 14/17] bar tooltips: format --- .../ii/modules/bar/BatteryIndicator.qml | 11 ++-- .../quickshell/ii/modules/bar/ClockWidget.qml | 50 ++++++++++++------- .../quickshell/ii/modules/bar/Resource.qml | 21 ++++---- .../ii/modules/bar/weather/WeatherBar.qml | 4 +- 4 files changed, 51 insertions(+), 35 deletions(-) diff --git a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml index 5172b5891..91d811a4b 100644 --- a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml +++ b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml @@ -58,9 +58,7 @@ MouseArea { iconSize: Appearance.font.pixelSize.normal color: (isLow && !isCharging) ? batteryLowOnBackground : Appearance.m3colors.m3onSecondaryContainer } - } - } Loader { @@ -72,7 +70,8 @@ MouseArea { Connections { target: root function onIsChargingChanged() { - if (isCharging) boltIconLoader.active = true + if (isCharging) + boltIconLoader.active = true; } } @@ -85,19 +84,19 @@ MouseArea { visible: opacity > 0 // Only show when charging opacity: isCharging ? 1 : 0 // Keep opacity for visibility onVisibleChanged: { - if (!visible) boltIconLoader.active = false + if (!visible) + boltIconLoader.active = false; } Behavior on opacity { animation: Appearance.animation.elementMove.numberAnimation.createObject(this) } - } } StyledPopup { hoverTarget: root - + BatteryPopup { id: batteryPopup anchors.centerIn: parent diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index 973039116..5c60141a1 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -15,22 +15,24 @@ Item { // Helper function to get upcoming todos function getUpcomingTodos() { - const unfinishedTodos = Todo.list.filter(function(item) { return !item.done; }) + const unfinishedTodos = Todo.list.filter(function (item) { + return !item.done; + }); if (unfinishedTodos.length === 0) { - return Translation.tr("No pending tasks") + return Translation.tr("No pending tasks"); } - + // Limit to first 5 todos to keep popup manageable - const limitedTodos = unfinishedTodos.slice(0, 5) - let todoText = limitedTodos.map(function(item, index) { - return `${index + 1}. ${item.content}` - }).join('\n') - + const limitedTodos = unfinishedTodos.slice(0, 5); + let todoText = limitedTodos.map(function (item, index) { + return `${index + 1}. ${item.content}`; + }).join('\n'); + if (unfinishedTodos.length > 5) { - todoText += `\n${Translation.tr("... and %1 more").arg(unfinishedTodos.length - 5)}` + todoText += `\n${Translation.tr("... and %1 more").arg(unfinishedTodos.length - 5)}`; } - - return todoText + + return todoText; } // Popup Data @@ -63,7 +65,6 @@ Item { color: Appearance.colors.colOnLayer1 text: DateTime.date } - } MouseArea { @@ -75,7 +76,7 @@ Item { StyledPopup { hoverTarget: mouseArea - + ColumnLayout { id: columnLayout anchors.centerIn: parent @@ -104,8 +105,15 @@ Item { RowLayout { spacing: 5 Layout.fillWidth: true - MaterialSymbol { text: "timelapse"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large } - StyledText { text: Translation.tr("System uptime:"); color: Appearance.colors.colOnSurfaceVariant } + MaterialSymbol { + text: "timelapse" + color: Appearance.colors.colOnSurfaceVariant + font.pixelSize: Appearance.font.pixelSize.large + } + StyledText { + text: Translation.tr("System uptime:") + color: Appearance.colors.colOnSurfaceVariant + } StyledText { Layout.fillWidth: true horizontalAlignment: Text.AlignRight @@ -122,8 +130,15 @@ Item { RowLayout { spacing: 4 Layout.fillWidth: true - MaterialSymbol { text: "checklist"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large } - StyledText { text: Translation.tr("To Do:"); color: Appearance.colors.colOnSurfaceVariant } + MaterialSymbol { + text: "checklist" + color: Appearance.colors.colOnSurfaceVariant + font.pixelSize: Appearance.font.pixelSize.large + } + StyledText { + text: Translation.tr("To Do:") + color: Appearance.colors.colOnSurfaceVariant + } } StyledText { @@ -136,5 +151,4 @@ Item { } } } - } diff --git a/.config/quickshell/ii/modules/bar/Resource.qml b/.config/quickshell/ii/modules/bar/Resource.qml index a57501335..65b22e15d 100644 --- a/.config/quickshell/ii/modules/bar/Resource.qml +++ b/.config/quickshell/ii/modules/bar/Resource.qml @@ -10,7 +10,13 @@ Item { id: root required property string iconName required property double percentage - property var tooltipData: [{ icon: "info", label: "System resource", value: "" }] + property var tooltipData: [ + { + icon: "info", + label: "System resource", + value: "" + } + ] property var tooltipHeaderIcon property var tooltipHeaderText property bool shown: true @@ -19,14 +25,14 @@ Item { implicitWidth: resourceRowLayout.x < 0 ? 0 : resourceRowLayout.implicitWidth implicitHeight: resourceRowLayout.implicitHeight - // Helper function to format KB to GB + // Helper function to format KB to GB function formatKB(kb) { - return (kb / (1024 * 1024)).toFixed(1) + " GB" + return (kb / (1024 * 1024)).toFixed(1) + " GB"; } RowLayout { - spacing: 4 id: resourceRowLayout + spacing: 4 x: shown ? 0 : -resourceRowLayout.width CircularProgress { @@ -45,7 +51,6 @@ Item { iconSize: Appearance.font.pixelSize.large color: Appearance.m3colors.m3onSecondaryContainer } - } StyledText { @@ -57,7 +62,6 @@ Item { Behavior on x { animation: Appearance.animation.elementMove.numberAnimation.createObject(this) } - } MouseArea { @@ -70,7 +74,7 @@ Item { StyledPopup { hoverTarget: mouseArea - + ColumnLayout { id: columnLayout anchors.centerIn: parent @@ -124,7 +128,6 @@ Item { } } } - } } @@ -135,4 +138,4 @@ Item { easing.bezierCurve: Appearance.animation.elementMove.bezierCurve } } -} \ No newline at end of file +} diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml index 42fe8b195..ed49b4b5c 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml @@ -18,7 +18,7 @@ MouseArea { RowLayout { id: rowLayout anchors.centerIn: parent - + MaterialSymbol { fill: 0 text: WeatherIcons.codeToName[Weather.data.wCode] @@ -38,7 +38,7 @@ MouseArea { StyledPopup { hoverTarget: root - + WeatherPopup { id: weatherPopup anchors.centerIn: parent From b0deecc0aadf9d4b62bba7889ee53774f52f2526 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Aug 2025 21:18:01 +0700 Subject: [PATCH 15/17] bar tooltips: add shadow --- .../ii/modules/common/widgets/StyledPopup.qml | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml index 028e0033d..abe080451 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml @@ -4,6 +4,7 @@ import qs.modules.common.widgets import qs.services import QtQuick import QtQuick.Layouts +import QtQuick.Effects import Quickshell import Quickshell.Wayland @@ -25,29 +26,37 @@ LazyLoader { anchors.top: !Config.options.bar.bottom anchors.bottom: Config.options.bar.bottom - implicitWidth: popupBackground.implicitWidth - implicitHeight: popupBackground.implicitHeight + implicitWidth: popupBackground.implicitWidth + Appearance.sizes.hyprlandGapsOut * 2 + implicitHeight: popupBackground.implicitHeight + Appearance.sizes.hyprlandGapsOut * 2 margins { left: root.QsWindow?.mapFromItem( root.hoverTarget, (root.hoverTarget.width - popupBackground.implicitWidth) / 2, 0 ).x - top: Appearance.sizes.hyprlandGapsOut - bottom: Appearance.sizes.hyprlandGapsOut } WlrLayershell.namespace: "quickshell:popup" WlrLayershell.layer: WlrLayer.Overlay + RectangularShadow { + property var target: popupBackground + anchors.fill: target + radius: target.radius + blur: 0.9 * Appearance.sizes.hyprlandGapsOut + offset: Qt.vector2d(0.0, 1.0) + spread: 0.7 + color: Appearance.colors.colShadow + cached: true + } + Rectangle { id: popupBackground readonly property real margin: 10 - color: Appearance.colors.colSurfaceContainer - radius: Appearance.rounding.small - + anchors.centerIn: parent implicitWidth: root.contentItem.implicitWidth + margin * 2 implicitHeight: root.contentItem.implicitHeight + margin * 2 - + color: Appearance.colors.colSurfaceContainer + radius: Appearance.rounding.small children: [root.contentItem] } } From 8eac9338fe941319c08e5c72bb961e7422b98011 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Aug 2025 21:18:55 +0700 Subject: [PATCH 16/17] bar tooltips: add border --- .config/quickshell/ii/modules/common/widgets/StyledPopup.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml index abe080451..baa37cce9 100644 --- a/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml +++ b/.config/quickshell/ii/modules/common/widgets/StyledPopup.qml @@ -58,6 +58,9 @@ LazyLoader { color: Appearance.colors.colSurfaceContainer radius: Appearance.rounding.small children: [root.contentItem] + + border.width: 1 + border.color: Appearance.colors.colLayer0Border } } } From aa025e4face2cb3846620d316cc022c3a6cedd87 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Aug 2025 22:05:19 +0700 Subject: [PATCH 17/17] bar tooltips: refractor more --- .../ii/modules/bar/BatteryIndicator.qml | 8 +- .../ii/modules/bar/BatteryPopup.qml | 210 +++++++++--------- .../quickshell/ii/modules/bar/ClockWidget.qml | 106 +-------- .../ii/modules/bar/ClockWidgetTooltip.qml | 109 +++++++++ .../ii/modules/bar/ResourcePopup.qml | 65 ++++++ .../ii/modules/bar/weather/WeatherBar.qml | 10 +- .../ii/modules/bar/weather/WeatherPopup.qml | 145 ++++++------ 7 files changed, 363 insertions(+), 290 deletions(-) create mode 100644 .config/quickshell/ii/modules/bar/ClockWidgetTooltip.qml create mode 100644 .config/quickshell/ii/modules/bar/ResourcePopup.qml diff --git a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml index 91d811a4b..e437f1d42 100644 --- a/.config/quickshell/ii/modules/bar/BatteryIndicator.qml +++ b/.config/quickshell/ii/modules/bar/BatteryIndicator.qml @@ -94,12 +94,8 @@ MouseArea { } } - StyledPopup { + BatteryPopup { + id: batteryPopup hoverTarget: root - - BatteryPopup { - id: batteryPopup - anchors.centerIn: parent - } } } diff --git a/.config/quickshell/ii/modules/bar/BatteryPopup.qml b/.config/quickshell/ii/modules/bar/BatteryPopup.qml index 9b9edc5a1..c697bfbda 100644 --- a/.config/quickshell/ii/modules/bar/BatteryPopup.qml +++ b/.config/quickshell/ii/modules/bar/BatteryPopup.qml @@ -5,124 +5,128 @@ import qs import QtQuick import QtQuick.Layouts -ColumnLayout { - id: columnLayout - anchors.centerIn: parent - spacing: 4 +StyledPopup { + id: root + + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 4 - // Header - RowLayout { - id: header - spacing: 5 + // Header + RowLayout { + id: header + spacing: 5 - MaterialSymbol { - fill: 0 - font.weight: Font.Medium - text: "battery_android_full" - iconSize: Appearance.font.pixelSize.large - color: Appearance.colors.colOnSurfaceVariant - } - - StyledText { - text: "Battery" - font { - weight: Font.Medium - pixelSize: Appearance.font.pixelSize.normal + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: "battery_android_full" + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant } - color: Appearance.colors.colOnSurfaceVariant - } - } - // This row is hidden when the battery is full. - RowLayout { - spacing: 5 - Layout.fillWidth: true - property bool rowVisible: { - let timeValue = Battery.isCharging ? Battery.timeToFull : Battery.timeToEmpty; - let power = Battery.energyRate; - return !(Battery.chargeState == 4 || timeValue <= 0 || power <= 0.01); - } - visible: rowVisible - opacity: rowVisible ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: 500 + StyledText { + text: "Battery" + font { + weight: Font.Medium + pixelSize: Appearance.font.pixelSize.normal + } + color: Appearance.colors.colOnSurfaceVariant } } - MaterialSymbol { - text: "schedule" - color: Appearance.colors.colOnSurfaceVariant - iconSize: Appearance.font.pixelSize.large - } - StyledText { - text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:") - color: Appearance.colors.colOnSurfaceVariant - } - StyledText { + // This row is hidden when the battery is full. + RowLayout { + spacing: 5 Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnSurfaceVariant - text: { - function formatTime(seconds) { - var h = Math.floor(seconds / 3600); - var m = Math.floor((seconds % 3600) / 60); - if (h > 0) - return `${h}h, ${m}m`; + property bool rowVisible: { + let timeValue = Battery.isCharging ? Battery.timeToFull : Battery.timeToEmpty; + let power = Battery.energyRate; + return !(Battery.chargeState == 4 || timeValue <= 0 || power <= 0.01); + } + visible: rowVisible + opacity: rowVisible ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: 500 + } + } + + MaterialSymbol { + text: "schedule" + color: Appearance.colors.colOnSurfaceVariant + iconSize: Appearance.font.pixelSize.large + } + StyledText { + text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:") + color: Appearance.colors.colOnSurfaceVariant + } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnSurfaceVariant + text: { + function formatTime(seconds) { + var h = Math.floor(seconds / 3600); + var m = Math.floor((seconds % 3600) / 60); + if (h > 0) + return `${h}h, ${m}m`; + else + return `${m}m`; + } + if (Battery.isCharging) + return formatTime(Battery.timeToFull); else - return `${m}m`; - } - if (Battery.isCharging) - return formatTime(Battery.timeToFull); - else - return formatTime(Battery.timeToEmpty); - } - } - } - - RowLayout { - spacing: 5 - Layout.fillWidth: true - - property bool rowVisible: !(Battery.chargeState != 4 && Battery.energyRate == 0) - visible: rowVisible - opacity: rowVisible ? 1 : 0 - Behavior on opacity { - NumberAnimation { - duration: 500 - } - } - - MaterialSymbol { - text: "bolt" - color: Appearance.colors.colOnSurfaceVariant - iconSize: Appearance.font.pixelSize.large - } - - StyledText { - text: { - if (Battery.chargeState == 4) { - return Translation.tr("Fully charged"); - } else if (Battery.chargeState == 1) { - return Translation.tr("Charging:"); - } else { - return Translation.tr("Discharging:"); + return formatTime(Battery.timeToEmpty); } } - color: Appearance.colors.colOnSurfaceVariant } - StyledText { + RowLayout { + spacing: 5 Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnSurfaceVariant - text: { - if (Battery.chargeState == 4) { - return ""; - } else { - return `${Battery.energyRate.toFixed(2)}W`; + + property bool rowVisible: !(Battery.chargeState != 4 && Battery.energyRate == 0) + visible: rowVisible + opacity: rowVisible ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: 500 + } + } + + MaterialSymbol { + text: "bolt" + color: Appearance.colors.colOnSurfaceVariant + iconSize: Appearance.font.pixelSize.large + } + + StyledText { + text: { + if (Battery.chargeState == 4) { + return Translation.tr("Fully charged"); + } else if (Battery.chargeState == 1) { + return Translation.tr("Charging:"); + } else { + return Translation.tr("Discharging:"); + } + } + color: Appearance.colors.colOnSurfaceVariant + } + + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnSurfaceVariant + text: { + if (Battery.chargeState == 4) { + return ""; + } else { + return `${Battery.energyRate.toFixed(2)}W`; + } } } } } -} \ No newline at end of file +} diff --git a/.config/quickshell/ii/modules/bar/ClockWidget.qml b/.config/quickshell/ii/modules/bar/ClockWidget.qml index 5c60141a1..6f335de23 100644 --- a/.config/quickshell/ii/modules/bar/ClockWidget.qml +++ b/.config/quickshell/ii/modules/bar/ClockWidget.qml @@ -13,34 +13,6 @@ Item { implicitWidth: rowLayout.implicitWidth implicitHeight: 32 - // Helper function to get upcoming todos - function getUpcomingTodos() { - const unfinishedTodos = Todo.list.filter(function (item) { - return !item.done; - }); - if (unfinishedTodos.length === 0) { - return Translation.tr("No pending tasks"); - } - - // Limit to first 5 todos to keep popup manageable - const limitedTodos = unfinishedTodos.slice(0, 5); - let todoText = limitedTodos.map(function (item, index) { - return `${index + 1}. ${item.content}`; - }).join('\n'); - - if (unfinishedTodos.length > 5) { - todoText += `\n${Translation.tr("... and %1 more").arg(unfinishedTodos.length - 5)}`; - } - - return todoText; - } - - // Popup Data - property string formattedDate: Qt.locale().toString(DateTime.clock.date, "dddd, MMMM dd, yyyy") - property string formattedTime: DateTime.time - property string formattedUptime: DateTime.uptime - property string todosSection: getUpcomingTodos() - RowLayout { id: rowLayout anchors.centerIn: parent @@ -72,83 +44,9 @@ Item { anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.NoButton - } - StyledPopup { - hoverTarget: mouseArea - - ColumnLayout { - id: columnLayout - anchors.centerIn: parent - spacing: 4 - - // Date + Time row - RowLayout { - spacing: 5 - - MaterialSymbol { - fill: 0 - font.weight: Font.Medium - text: "calendar_month" - iconSize: Appearance.font.pixelSize.large - color: Appearance.colors.colOnSurfaceVariant - } - StyledText { - horizontalAlignment: Text.AlignLeft - color: Appearance.colors.colOnSurfaceVariant - text: `${root.formattedDate} • ${root.formattedTime}` - font.weight: Font.Medium - } - } - - // Uptime row - RowLayout { - spacing: 5 - Layout.fillWidth: true - MaterialSymbol { - text: "timelapse" - color: Appearance.colors.colOnSurfaceVariant - font.pixelSize: Appearance.font.pixelSize.large - } - StyledText { - text: Translation.tr("System uptime:") - color: Appearance.colors.colOnSurfaceVariant - } - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - color: Appearance.colors.colOnSurfaceVariant - text: root.formattedUptime - } - } - - // Tasks - ColumnLayout { - spacing: 0 - Layout.fillWidth: true - - RowLayout { - spacing: 4 - Layout.fillWidth: true - MaterialSymbol { - text: "checklist" - color: Appearance.colors.colOnSurfaceVariant - font.pixelSize: Appearance.font.pixelSize.large - } - StyledText { - text: Translation.tr("To Do:") - color: Appearance.colors.colOnSurfaceVariant - } - } - - StyledText { - Layout.fillWidth: true - horizontalAlignment: Text.AlignLeft - wrapMode: Text.Wrap - color: Appearance.colors.colOnSurfaceVariant - text: root.todosSection - } - } + ClockWidgetTooltip { + hoverTarget: mouseArea } } } diff --git a/.config/quickshell/ii/modules/bar/ClockWidgetTooltip.qml b/.config/quickshell/ii/modules/bar/ClockWidgetTooltip.qml new file mode 100644 index 000000000..ea11336a9 --- /dev/null +++ b/.config/quickshell/ii/modules/bar/ClockWidgetTooltip.qml @@ -0,0 +1,109 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import QtQuick.Layouts + +StyledPopup { + id: root + property string formattedDate: Qt.locale().toString(DateTime.clock.date, "dddd, MMMM dd, yyyy") + property string formattedTime: DateTime.time + property string formattedUptime: DateTime.uptime + property string todosSection: getUpcomingTodos() + + function getUpcomingTodos() { + const unfinishedTodos = Todo.list.filter(function (item) { + return !item.done; + }); + if (unfinishedTodos.length === 0) { + return Translation.tr("No pending tasks"); + } + + // Limit to first 5 todos to keep popup manageable + const limitedTodos = unfinishedTodos.slice(0, 5); + let todoText = limitedTodos.map(function (item, index) { + return `${index + 1}. ${item.content}`; + }).join('\n'); + + if (unfinishedTodos.length > 5) { + todoText += `\n${Translation.tr("... and %1 more").arg(unfinishedTodos.length - 5)}`; + } + + return todoText; + } + + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 4 + + // Date + Time row + RowLayout { + spacing: 5 + + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: "calendar_month" + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant + } + StyledText { + horizontalAlignment: Text.AlignLeft + color: Appearance.colors.colOnSurfaceVariant + text: `${root.formattedDate} • ${root.formattedTime}` + font.weight: Font.Medium + } + } + + // Uptime row + RowLayout { + spacing: 5 + Layout.fillWidth: true + MaterialSymbol { + text: "timelapse" + color: Appearance.colors.colOnSurfaceVariant + font.pixelSize: Appearance.font.pixelSize.large + } + StyledText { + text: Translation.tr("System uptime:") + color: Appearance.colors.colOnSurfaceVariant + } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + color: Appearance.colors.colOnSurfaceVariant + text: root.formattedUptime + } + } + + // Tasks + ColumnLayout { + spacing: 0 + Layout.fillWidth: true + + RowLayout { + spacing: 4 + Layout.fillWidth: true + MaterialSymbol { + text: "checklist" + color: Appearance.colors.colOnSurfaceVariant + font.pixelSize: Appearance.font.pixelSize.large + } + StyledText { + text: Translation.tr("To Do:") + color: Appearance.colors.colOnSurfaceVariant + } + } + + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignLeft + wrapMode: Text.Wrap + color: Appearance.colors.colOnSurfaceVariant + text: root.todosSection + } + } + } +} diff --git a/.config/quickshell/ii/modules/bar/ResourcePopup.qml b/.config/quickshell/ii/modules/bar/ResourcePopup.qml new file mode 100644 index 000000000..71fd02443 --- /dev/null +++ b/.config/quickshell/ii/modules/bar/ResourcePopup.qml @@ -0,0 +1,65 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import QtQuick.Layouts + +StyledPopup { + hoverTarget: mouseArea + + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + spacing: 4 + + // Header + RowLayout { + id: header + spacing: 5 + + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: root.tooltipHeaderIcon + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant + } + + StyledText { + text: root.tooltipHeaderText + font { + weight: Font.Medium + pixelSize: Appearance.font.pixelSize.normal + } + color: Appearance.colors.colOnSurfaceVariant + } + } + + // Info rows + Repeater { + model: root.tooltipData + delegate: RowLayout { + spacing: 5 + Layout.fillWidth: true + + MaterialSymbol { + text: modelData.icon + color: Appearance.colors.colOnSurfaceVariant + iconSize: Appearance.font.pixelSize.large + } + StyledText { + text: modelData.label + color: Appearance.colors.colOnSurfaceVariant + } + StyledText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + visible: modelData.value !== "" + color: Appearance.colors.colOnSurfaceVariant + text: modelData.value + } + } + } + } +} \ No newline at end of file diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml index ed49b4b5c..c49a1b7d1 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherBar.qml @@ -21,7 +21,7 @@ MouseArea { MaterialSymbol { fill: 0 - text: WeatherIcons.codeToName[Weather.data.wCode] + text: WeatherIcons.codeToName[Weather.data.wCode] ?? "cloud" iconSize: Appearance.font.pixelSize.large color: Appearance.colors.colOnLayer1 Layout.alignment: Qt.AlignVCenter @@ -36,12 +36,8 @@ MouseArea { } } - StyledPopup { + WeatherPopup { + id: weatherPopup hoverTarget: root - - WeatherPopup { - id: weatherPopup - anchors.centerIn: parent - } } } diff --git a/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml b/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml index 6297ea8cc..aa61359d7 100644 --- a/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml +++ b/.config/quickshell/ii/modules/bar/weather/WeatherPopup.qml @@ -6,83 +6,88 @@ import qs.modules.common.widgets import QtQuick import QtQuick.Layouts -ColumnLayout { - id: columnLayout - spacing: 5 - implicitWidth: Math.max(header.implicitWidth, gridLayout.implicitWidth) - implicitHeight: gridLayout.implicitHeight +StyledPopup { + id: root - // Header - RowLayout { - id: header + ColumnLayout { + id: columnLayout + anchors.centerIn: parent + implicitWidth: Math.max(header.implicitWidth, gridLayout.implicitWidth) + implicitHeight: gridLayout.implicitHeight spacing: 5 - Layout.alignment: Qt.AlignHCenter - MaterialSymbol { - fill: 0 - font.weight: Font.Medium - text: "location_on" - iconSize: Appearance.font.pixelSize.large - color: Appearance.colors.colOnSurfaceVariant - } + // Header + RowLayout { + id: header + spacing: 5 + Layout.alignment: Qt.AlignHCenter - StyledText { - text: Weather.data.city - font { - weight: Font.Medium - pixelSize: Appearance.font.pixelSize.normal + MaterialSymbol { + fill: 0 + font.weight: Font.Medium + text: "location_on" + iconSize: Appearance.font.pixelSize.large + color: Appearance.colors.colOnSurfaceVariant } - color: Appearance.colors.colOnSurfaceVariant - } - } - // Metrics grid - GridLayout { - id: gridLayout - columns: 2 - rowSpacing: 5 - columnSpacing: 5 - uniformCellWidths: true + StyledText { + text: Weather.data.city + font { + weight: Font.Medium + pixelSize: Appearance.font.pixelSize.normal + } + color: Appearance.colors.colOnSurfaceVariant + } + } - WeatherCard { - title: Translation.tr("UV Index") - symbol: "wb_sunny" - value: Weather.data.uv - } - WeatherCard { - title: Translation.tr("Wind") - symbol: "air" - value: `(${Weather.data.windDir}) ${Weather.data.wind}` - } - WeatherCard { - title: Translation.tr("Precipitation") - symbol: "rainy_light" - value: Weather.data.precip - } - WeatherCard { - title: Translation.tr("Humidity") - symbol: "humidity_low" - value: Weather.data.humidity - } - WeatherCard { - title: Translation.tr("Visibility") - symbol: "visibility" - value: Weather.data.visib - } - WeatherCard { - title: Translation.tr("Pressure") - symbol: "readiness_score" - value: Weather.data.press - } - WeatherCard { - title: Translation.tr("Sunrise") - symbol: "wb_twilight" - value: Weather.data.sunrise - } - WeatherCard { - title: Translation.tr("Sunset") - symbol: "bedtime" - value: Weather.data.sunset + // Metrics grid + GridLayout { + id: gridLayout + columns: 2 + rowSpacing: 5 + columnSpacing: 5 + uniformCellWidths: true + + WeatherCard { + title: Translation.tr("UV Index") + symbol: "wb_sunny" + value: Weather.data.uv + } + WeatherCard { + title: Translation.tr("Wind") + symbol: "air" + value: `(${Weather.data.windDir}) ${Weather.data.wind}` + } + WeatherCard { + title: Translation.tr("Precipitation") + symbol: "rainy_light" + value: Weather.data.precip + } + WeatherCard { + title: Translation.tr("Humidity") + symbol: "humidity_low" + value: Weather.data.humidity + } + WeatherCard { + title: Translation.tr("Visibility") + symbol: "visibility" + value: Weather.data.visib + } + WeatherCard { + title: Translation.tr("Pressure") + symbol: "readiness_score" + value: Weather.data.press + } + WeatherCard { + title: Translation.tr("Sunrise") + symbol: "wb_twilight" + value: Weather.data.sunrise + } + WeatherCard { + title: Translation.tr("Sunset") + symbol: "bedtime" + value: Weather.data.sunset + } } } } \ No newline at end of file