Add animations everywhere

This commit is contained in:
Ly-sec 2025-08-13 15:09:49 +02:00
commit c3304818f1
16 changed files with 637 additions and 174 deletions

View file

@ -28,7 +28,7 @@ TEMP_SENSOR_TYPE=""
# --- Data Collection Functions --- # --- Data Collection Functions ---
# #
# Gets memory usage in GB and as a percentage. # Gets memory usage in GB, MB, and as a percentage.
# #
get_memory_info() { get_memory_info() {
awk ' awk '
@ -39,11 +39,10 @@ get_memory_info() {
usage_kb = total - available usage_kb = total - available
usage_gb = usage_kb / 1000000 usage_gb = usage_kb / 1000000
usage_percent = (usage_kb / total) * 100 usage_percent = (usage_kb / total) * 100
# MODIFIED: Round the memory percentage to the nearest integer.
printf "%.1f %.0f\n", usage_gb, usage_percent printf "%.1f %.0f\n", usage_gb, usage_percent
} else { } else {
# Fallback if /proc/meminfo is unreadable or empty. # Fallback if /proc/meminfo is unreadable or empty.
print "0.0 0.0" print "0.0 0 0"
} }
} }
' /proc/meminfo ' /proc/meminfo
@ -95,10 +94,8 @@ get_cpu_usage() {
if (total > 0) { if (total > 0) {
# Formula: 100 * (Total - Idle) / Total # Formula: 100 * (Total - Idle) / Total
usage = 100 * (total - idle) / total usage = 100 * (total - idle) / total
# MODIFIED: Changed format from "%.2f" back to "%.1f" for one decimal place.
printf "%.1f\n", usage printf "%.1f\n", usage
} else { } else {
# MODIFIED: Changed output back to "0.0" to match the precision.
print "0.0" print "0.0"
} }
}' }'
@ -171,7 +168,7 @@ get_cpu_temp() {
# This loop runs indefinitely, gathering and printing stats. # This loop runs indefinitely, gathering and printing stats.
while true; do while true; do
# Call the functions to gather all the data. # Call the functions to gather all the data.
# 'read' is used to capture the two output values from get_memory_info. # get_memory_info
read -r mem_gb mem_per <<< "$(get_memory_info)" read -r mem_gb mem_per <<< "$(get_memory_info)"
# Command substitution captures the single output from the other functions. # Command substitution captures the single output from the other functions.
@ -179,11 +176,11 @@ while true; do
cpu_usage=$(get_cpu_usage) cpu_usage=$(get_cpu_usage)
cpu_temp=$(get_cpu_temp) cpu_temp=$(get_cpu_temp)
# Use printf to format the final JSON output string, matching the Zig program. # Use printf to format the final JSON output string, adding the mem_mb key.
printf '{"mem":"%s", "cpu": "%s", "cputemp": "%s", "memper": "%s", "diskper": "%s"}\n' \ printf '{"cpu": "%s", "cputemp": "%s", "memgb":"%s", "memper": "%s", "diskper": "%s"}\n' \
"$mem_gb" \
"$cpu_usage" \ "$cpu_usage" \
"$cpu_temp" \ "$cpu_temp" \
"$mem_gb" \
"$mem_per" \ "$mem_per" \
"$disk_per" "$disk_per"

View file

@ -7,7 +7,7 @@ import qs.Widgets
NLoader { NLoader {
active: Workspaces.isNiri active: Workspaces.isNiri
Component.onCompleted: { Component.onCompleted: {
if (Workspaces.isNiri) { if (Workspaces.isNiri) {
console.log("[Overview] Loading Overview component (Niri detected)") console.log("[Overview] Loading Overview component (Niri detected)")
@ -15,55 +15,55 @@ NLoader {
console.log("[Overview] Skipping Overview component (Niri not detected)") console.log("[Overview] Skipping Overview component (Niri not detected)")
} }
} }
sourceComponent: Variants { sourceComponent: Variants {
model: Quickshell.screens model: Quickshell.screens
delegate: PanelWindow { delegate: PanelWindow {
required property ShellScreen modelData required property ShellScreen modelData
property string wallpaperSource: Wallpapers.currentWallpaper !== "" property string wallpaperSource: Wallpapers.currentWallpaper !== ""
&& !Settings.data.wallpaper.swww.enabled ? Wallpapers.currentWallpaper : "" && !Settings.data.wallpaper.swww.enabled ? Wallpapers.currentWallpaper : ""
visible: wallpaperSource !== "" && !Settings.data.wallpaper.swww.enabled visible: wallpaperSource !== "" && !Settings.data.wallpaper.swww.enabled
color: "transparent" color: "transparent"
screen: modelData screen: modelData
WlrLayershell.layer: WlrLayer.Background WlrLayershell.layer: WlrLayer.Background
WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.namespace: "quickshell-overview" WlrLayershell.namespace: "quickshell-overview"
anchors { anchors {
top: true top: true
bottom: true bottom: true
right: true right: true
left: true left: true
}
Image {
id: bgImage
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: wallpaperSource
cache: true
smooth: true
mipmap: false
visible: wallpaperSource !== ""
}
MultiEffect {
id: overviewBgBlur
anchors.fill: parent
source: bgImage
blurEnabled: true
blur: 0.48
blurMax: 128
}
Rectangle {
anchors.fill: parent
color: Qt.rgba(Colors.backgroundPrimary.r, Colors.backgroundPrimary.g, Colors.backgroundPrimary.b, 0.5)
}
} }
Image {
id: bgImage
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: wallpaperSource
cache: true
smooth: true
mipmap: false
visible: wallpaperSource !== ""
}
MultiEffect {
id: overviewBgBlur
anchors.fill: parent
source: bgImage
blurEnabled: true
blur: 0.48
blurMax: 128
}
Rectangle {
anchors.fill: parent
color: Qt.rgba(Colors.backgroundPrimary.r, Colors.backgroundPrimary.g, Colors.backgroundPrimary.b, 0.5)
}
}
} }
} }

View file

@ -15,8 +15,6 @@ Variants {
required property ShellScreen modelData required property ShellScreen modelData
readonly property real scaling: Scaling.scale(screen) readonly property real scaling: Scaling.scale(screen)
property var settingsPanel: null
screen: modelData screen: modelData
implicitHeight: Style.barHeight * scaling implicitHeight: Style.barHeight * scaling
color: "transparent" color: "transparent"
@ -52,11 +50,13 @@ Variants {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginSmall * scaling spacing: Style.marginSmall * scaling
NText { // Debug show monitor name
text: screen.name // NText {
anchors.verticalCenter: parent.verticalCenter // text: screen.name
font.weight: Style.fontWeightBold // anchors.verticalCenter: parent.verticalCenter
} // font.weight: Style.fontWeightBold
// }
SystemMonitor {}
} }
// Center // Center

View file

@ -36,4 +36,4 @@ NIconButton {
NotificationHistoryPanel { NotificationHistoryPanel {
id: notificationHistoryPanelLoader id: notificationHistoryPanelLoader
} }
} }

View file

@ -228,4 +228,4 @@ NLoader {
} }
} }
} }
} }

View file

@ -0,0 +1,84 @@
import QtQuick
import Quickshell
import qs.Services
import qs.Widgets
Row {
id: layout
anchors.verticalCenter: parent.verticalCenter
spacing: Style.marginSmall * scaling
visible: Settings.data.bar.showSystemInfo
// Ensure our width is an integer
width: Math.floor(cpuUsageLayout.width + cpuTempLayout.width + memoryUsageLayout.width + (2 * 10))
Row {
id: cpuUsageLayout
spacing: Style.marginTiny * scaling
NText {
id: cpuUsageIcon
text: "speed"
font.family: "Material Symbols Outlined"
font.pointSize: Style.fontSizeLarge * scaling
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
color: Colors.accentPrimary
}
NText {
id: cpuUsageText
text: `${SystemStats.cpuUsage}%`
font.pointSize: Style.fontSizeSmall * scaling
font.weight: Style.fontWeightBold
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
}
}
// CPU Temperature Component
Row {
id: cpuTempLayout
spacing: Style.marginTiny * scaling
NText {
text: "thermometer"
font.family: "Material Symbols Outlined"
font.pointSize: Style.fontSizeLarge * scaling
color: Colors.accentPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
}
NText {
text: `${SystemStats.cpuTemp}°C`
font.pointSize: Style.fontSizeSmall * scaling
font.weight: Style.fontWeightBold
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
}
}
// Memory Usage Component
Row {
id: memoryUsageLayout
spacing: Style.marginTiny * scaling
NText {
text: "memory"
font.family: "Material Symbols Outlined"
font.pointSize: Style.fontSizeLarge * scaling
color: Colors.accentPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
}
NText {
text: `${SystemStats.memoryUsageGb}G`
font.pointSize: Style.fontSizeSmall * scaling
font.weight: Style.fontWeightBold
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
}
}
}

View file

@ -10,9 +10,6 @@ Item {
width: pill.width width: pill.width
height: pill.height height: pill.height
// Reference to settings panel
property var settingsPanel: null
Component.onCompleted: { Component.onCompleted: {
console.log("[Volume] settingsPanel received:", !!settingsPanel) console.log("[Volume] settingsPanel received:", !!settingsPanel)
} }
@ -87,15 +84,8 @@ Item {
} }
} }
onClicked: { onClicked: {
// Open settings panel and navigate to Audio tab settingsPanel.currentTabIndex = 5 // Audio tab index
console.log("[Volume] Attempting to open settings panel...") settingsPanel.isLoaded = true
try {
settingsPanel.isLoaded = true
settingsPanel.content.currentTabIndex = 5 // Audio tab index
console.log("[Volume] Settings panel opened successfully")
} catch (error) {
console.log("[Volume] Error opening settings panel:", error)
}
} }
} }
} }

View file

@ -10,6 +10,8 @@ import qs.Widgets
NLoader { NLoader {
id: root id: root
property int currentTabIndex: 0
content: Component { content: Component {
NPanel { NPanel {
id: panel id: panel
@ -52,7 +54,6 @@ NLoader {
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
property int currentTabIndex: 0
property var tabsModel: [{ property var tabsModel: [{
"label": "General", "label": "General",
"icon": "tune", "icon": "tune",
@ -89,11 +90,12 @@ NLoader {
"label": "Wallpaper Selector", "label": "Wallpaper Selector",
"icon": "wallpaper_slideshow", "icon": "wallpaper_slideshow",
"source": "Tabs/WallpaperSelector.qml" "source": "Tabs/WallpaperSelector.qml"
}, { }, // {
"label": "Misc", // "label": "Misc",
"icon": "more_horiz", // "icon": "more_horiz",
"source": "Tabs/Misc.qml" // "source": "Tabs/Misc.qml"
}, { // },
{
"label": "About", "label": "About",
"icon": "info", "icon": "info",
"source": "Tabs/About.qml" "source": "Tabs/About.qml"
@ -186,7 +188,7 @@ NLoader {
delegate: Rectangle { delegate: Rectangle {
id: tabItem id: tabItem
readonly property bool selected: index === panel.currentTabIndex
width: parent.width width: parent.width
height: 32 * scaling // Back to original height height: 32 * scaling // Back to original height
radius: Style.radiusSmall * scaling radius: Style.radiusSmall * scaling
@ -194,6 +196,8 @@ NLoader {
border.color: "transparent" border.color: "transparent"
border.width: 0 border.width: 0
readonly property bool selected: index === currentTabIndex
// Subtle hover effect: only icon/text color tint on hover // Subtle hover effect: only icon/text color tint on hover
property bool hovering: false property bool hovering: false
@ -227,7 +231,7 @@ NLoader {
onEntered: tabItem.hovering = true onEntered: tabItem.hovering = true
onExited: tabItem.hovering = false onExited: tabItem.hovering = false
onCanceled: tabItem.hovering = false onCanceled: tabItem.hovering = false
onClicked: panel.currentTabIndex = index onClicked: currentTabIndex = index
} }
} }
} }
@ -258,7 +262,7 @@ NLoader {
// Tab label on the main right // Tab label on the main right
NText { NText {
text: panel.tabsModel[panel.currentTabIndex].label text: panel.tabsModel[currentTabIndex].label
font.pointSize: Style.fontSizeLarge * scaling font.pointSize: Style.fontSizeLarge * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Colors.accentPrimary color: Colors.accentPrimary
@ -282,7 +286,7 @@ NLoader {
id: stack id: stack
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
currentIndex: panel.currentTabIndex currentIndex: currentTabIndex
Tabs.General {} Tabs.General {}
Tabs.Bar {} Tabs.Bar {}

View file

@ -88,14 +88,14 @@ ColumnLayout {
} }
} }
NToggle { NToggle {
id: allowOverdrive id: allowOverdrive
label: "Allow Volume Overdrive" label: "Allow Volume Overdrive"
description: "Enable volume levels above 100% (up to 200%)" description: "Enable volume levels above 100% (up to 200%)"
value: Settings.data.audio ? Settings.data.audio.volumeOverdrive : false value: Settings.data.audio ? Settings.data.audio.volumeOverdrive : false
onToggled: function (checked) { onToggled: function (checked) {
Settings.data.audio.volumeOverdrive = checked Settings.data.audio.volumeOverdrive = checked
// If overdrive is disabled and current volume is above 100%, cap it // If overdrive is disabled and current volume is above 100%, cap it
if (!checked && Audio.volume > 1.0) { if (!checked && Audio.volume > 1.0) {
Audio.volumeSet(1.0) Audio.volumeSet(1.0)
@ -140,58 +140,56 @@ ColumnLayout {
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Colors.textPrimary color: Colors.textPrimary
Layout.bottomMargin: Style.marginSmall * scaling Layout.bottomMargin: Style.marginSmall * scaling
}
// Output Device
NComboBox {
id: outputDeviceCombo
label: "Output Device"
description: "Default audio output device"
optionsKeys: outputDeviceKeys
optionsLabels: outputDeviceLabels
currentKey: Audio.sink ? Audio.sink.id.toString() : ""
onSelected: function (key) {
// Find the node by ID and set it as preferred
for (let i = 0; i < Pipewire.nodes.count; i++) {
let node = Pipewire.nodes.get(i)
if (node.id.toString() === key && node.isSink) {
Pipewire.preferredDefaultAudioSink = node
break
}
}
}
}
// Input Device
NComboBox {
id: inputDeviceCombo
label: "Input Device"
description: "Default audio input device"
optionsKeys: inputDeviceKeys
optionsLabels: inputDeviceLabels
currentKey: Audio.source ? Audio.source.id.toString() : ""
onSelected: function (key) {
// Find the node by ID and set it as preferred
for (let i = 0; i < Pipewire.nodes.count; i++) {
let node = Pipewire.nodes.get(i)
if (node.id.toString() === key && !node.isSink) {
Pipewire.preferredDefaultAudioSource = node
break
}
}
}
}
}
// Divider
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginLarge * scaling
Layout.bottomMargin: Style.marginMedium * scaling
} }
// Output Device
NComboBox {
id: outputDeviceCombo
label: "Output Device"
description: "Default audio output device"
optionsKeys: outputDeviceKeys
optionsLabels: outputDeviceLabels
currentKey: Audio.sink ? Audio.sink.id.toString() : ""
onSelected: function (key) {
// Find the node by ID and set it as preferred
for (var i = 0; i < Pipewire.nodes.count; i++) {
let node = Pipewire.nodes.get(i)
if (node.id.toString() === key && node.isSink) {
Pipewire.preferredDefaultAudioSink = node
break
}
}
}
}
// Input Device
NComboBox {
id: inputDeviceCombo
label: "Input Device"
description: "Default audio input device"
optionsKeys: inputDeviceKeys
optionsLabels: inputDeviceLabels
currentKey: Audio.source ? Audio.source.id.toString() : ""
onSelected: function (key) {
// Find the node by ID and set it as preferred
for (var i = 0; i < Pipewire.nodes.count; i++) {
let node = Pipewire.nodes.get(i)
if (node.id.toString() === key && !node.isSink) {
Pipewire.preferredDefaultAudioSource = node
break
}
}
}
}
}
// Divider
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginLarge * scaling
Layout.bottomMargin: Style.marginMedium * scaling
}
// Audio Visualizer Category // Audio Visualizer Category
ColumnLayout { ColumnLayout {
spacing: Style.marginSmall * scaling spacing: Style.marginSmall * scaling
@ -298,11 +296,11 @@ ColumnLayout {
outputDeviceCombo.optionsKeys = outputDeviceKeys outputDeviceCombo.optionsKeys = outputDeviceKeys
outputDeviceCombo.optionsLabels = outputDeviceLabels outputDeviceCombo.optionsLabels = outputDeviceLabels
} }
if (inputDeviceCombo) { if (inputDeviceCombo) {
inputDeviceCombo.optionsKeys = inputDeviceKeys inputDeviceCombo.optionsKeys = inputDeviceKeys
inputDeviceCombo.optionsLabels = inputDeviceLabels inputDeviceCombo.optionsLabels = inputDeviceLabels
} }
} }
} }
} }

View file

@ -39,8 +39,6 @@ ColumnLayout {
color: Colors.textPrimary color: Colors.textPrimary
Layout.bottomMargin: Style.marginSmall * scaling Layout.bottomMargin: Style.marginSmall * scaling
} }
} }
} }
} }

View file

@ -62,11 +62,18 @@ NBox {
} }
} }
NIconButton { NIconButton {
id: powerButton
icon: "power_settings_new" icon: "power_settings_new"
onClicked: {
//settingsPanel.isLoaded = !settingsPanel.isLoaded
powerMenu.show()
}
} }
} }
} }
// ----------------------------------
// Uptime
Timer { Timer {
interval: 60000 interval: 60000
repeat: true repeat: true
@ -99,4 +106,378 @@ NBox {
} }
} }
} }
// ----------------------------------
// Logout menu
function logout() {
if (WorkspaceManager.isNiri) {
logoutProcessNiri.running = true
} else if (WorkspaceManager.isHyprland) {
logoutProcessHyprland.running = true
} else {
console.warn("No supported compositor detected for logout")
}
}
function suspend() {
suspendProcess.running = true
}
function shutdown() {
shutdownProcess.running = true
}
function reboot() {
rebootProcess.running = true
}
function updateSystemInfo() {
uptimeProcess.running = true
}
Process {
id: shutdownProcess
command: ["shutdown", "-h", "now"]
running: false
}
Process {
id: rebootProcess
command: ["reboot"]
running: false
}
Process {
id: suspendProcess
command: ["systemctl", "suspend"]
running: false
}
Process {
id: logoutProcessNiri
command: ["niri", "msg", "action", "quit", "--skip-confirmation"]
running: false
}
Process {
id: logoutProcessHyprland
command: ["hyprctl", "dispatch", "exit"]
running: false
}
Process {
id: logoutProcess
command: ["loginctl", "terminate-user", Quickshell.env("USER")]
running: false
}
NPanel {
id: powerMenu
anchors.top: powerButton.bottom
anchors.right: powerButton.right
Rectangle {
width: 160 * scaling
height: 220 * scaling
color: Colors.surface
radius: 8 * scaling
border.color: Colors.outline
border.width: 1 * scaling
visible: true
z: 9999
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin: 32 * scaling
anchors.topMargin: powerButton.y + powerButton.height + 48 * scaling
// Prevent closing when clicking in the panel bg
MouseArea {
anchors.fill: parent
}
ColumnLayout {
anchors.fill: parent
anchors.margins: 8 * scaling
spacing: 4 * scaling
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 36 * scaling
radius: 6 * scaling
color: lockButtonArea.containsMouse ? Colors.accentPrimary : "transparent"
Item {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 12 * scaling
anchors.rightMargin: 12 * scaling
Row {
id: lockRow
spacing: 8 * scaling
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Text {
text: "lock_outline"
font.family: "Material Symbols Outlined"
font.pixelSize: 16 * scaling
color: lockButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
Text {
text: "Lock Screen"
font.pixelSize: 14 * scaling
color: lockButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
}
}
MouseArea {
id: lockButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
lockScreen.locked = true
systemMenu.visible = false
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 36 * scaling
radius: 6 * scaling
color: suspendButtonArea.containsMouse ? Colors.accentPrimary : "transparent"
Item {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 12 * scaling
anchors.rightMargin: 12 * scaling
Row {
id: suspendRow
spacing: 8 * scaling
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Text {
text: "bedtime"
font.family: "Material Symbols Outlined"
font.pixelSize: 16 * scaling
color: suspendButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
Text {
text: "Suspend"
font.pixelSize: 14 * scaling
color: suspendButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
}
}
MouseArea {
id: suspendButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
suspend()
systemMenu.visible = false
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 36 * scaling
radius: 6 * scaling
color: rebootButtonArea.containsMouse ? Colors.accentPrimary : "transparent"
Item {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 12 * scaling
anchors.rightMargin: 12 * scaling
Row {
id: rebootRow
spacing: 8 * scaling
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Text {
text: "refresh"
font.family: "Material Symbols Outlined"
font.pixelSize: 16 * scaling
color: rebootButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
Text {
text: "Reboot"
font.pixelSize: 14 * scaling
color: rebootButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
}
}
MouseArea {
id: rebootButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
reboot()
systemMenu.visible = false
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 36 * scaling
radius: 6 * scaling
color: logoutButtonArea.containsMouse ? Colors.accentPrimary : "transparent"
Item {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 12 * scaling
anchors.rightMargin: 12 * scaling
Row {
id: logoutRow
spacing: 8 * scaling
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Text {
text: "exit_to_app"
font.family: "Material Symbols Outlined"
font.pixelSize: 16 * scaling
color: logoutButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
Text {
text: "Logout"
font.pixelSize: 14 * scaling
color: logoutButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
}
}
MouseArea {
id: logoutButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
logout()
systemMenu.visible = false
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 36 * scaling
radius: 6 * scaling
color: shutdownButtonArea.containsMouse ? Colors.accentPrimary : "transparent"
Item {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 12 * scaling
anchors.rightMargin: 12 * scaling
Row {
id: shutdownRow
spacing: 8 * scaling
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Text {
text: "power_settings_new"
font.family: "Material Symbols Outlined"
font.pixelSize: 16 * scaling
color: shutdownButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
Text {
text: "Shutdown"
font.pixelSize: 14 * scaling
color: shutdownButtonArea.containsMouse ? Colors.onAccent : Colors.textPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
}
}
}
MouseArea {
id: shutdownButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
shutdown()
systemMenu.visible = false
}
}
}
}
}
}
} }

View file

@ -30,6 +30,10 @@ NBox {
// Wallpaper // Wallpaper
NIconButton { NIconButton {
icon: "image" icon: "image"
onClicked: {
settingsPanel.currentTabIndex = 8 // Audio tab index
settingsPanel.isLoaded = true
}
} }
Item { Item {

View file

@ -57,7 +57,8 @@ QtObject {
property int maxHistory: 100 property int maxHistory: 100
// Cached history file path // Cached history file path
property string historyFile: Quickshell.env("NOCTALIA_NOTIF_HISTORY_FILE") || (Settings.cacheDir + "notifications.json") property string historyFile: Quickshell.env("NOCTALIA_NOTIF_HISTORY_FILE")
|| (Settings.cacheDir + "notifications.json")
// Persisted storage for history // Persisted storage for history
property FileView historyFileView: FileView { property FileView historyFileView: FileView {
@ -130,12 +131,12 @@ QtObject {
// Add a simplified copy into persistent history // Add a simplified copy into persistent history
function addToHistory(notification) { function addToHistory(notification) {
historyModel.insert(0, { historyModel.insert(0, {
"summary": notification.summary, "summary": notification.summary,
"body": notification.body, "body": notification.body,
"appName": notification.appName, "appName": notification.appName,
"urgency": notification.urgency, "urgency": notification.urgency,
"timestamp": new Date() "timestamp": new Date()
}) })
while (historyModel.count > maxHistory) { while (historyModel.count > maxHistory) {
historyModel.remove(historyModel.count - 1) historyModel.remove(historyModel.count - 1)
} }
@ -155,12 +156,12 @@ QtObject {
for (var i = 0; i < items.length; i++) { for (var i = 0; i < items.length; i++) {
const it = items[i] const it = items[i]
historyModel.append({ historyModel.append({
"summary": it.summary || "", "summary": it.summary || "",
"body": it.body || "", "body": it.body || "",
"appName": it.appName || "", "appName": it.appName || "",
"urgency": it.urgency, "urgency": it.urgency,
"timestamp": it.timestamp ? new Date(it.timestamp) : new Date() "timestamp": it.timestamp ? new Date(it.timestamp) : new Date()
}) })
} }
} catch (e) { } catch (e) {
console.error("[Notifications] Failed to load history:", e) console.error("[Notifications] Failed to load history:", e)
@ -174,11 +175,11 @@ QtObject {
for (var i = 0; i < historyModel.count; i++) { for (var i = 0; i < historyModel.count; i++) {
const n = historyModel.get(i) const n = historyModel.get(i)
arr.push({ arr.push({
summary: n.summary, "summary": n.summary,
body: n.body, "body": n.body,
appName: n.appName, "appName": n.appName,
urgency: n.urgency, "urgency": n.urgency,
timestamp: (n.timestamp instanceof Date) ? n.timestamp.getTime() : n.timestamp "timestamp": (n.timestamp instanceof Date) ? n.timestamp.getTime() : n.timestamp
}) })
} }
historyAdapter.history = arr historyAdapter.history = arr

View file

@ -53,7 +53,7 @@ Singleton {
onLoaded: function () { onLoaded: function () {
Qt.callLater(function () { Qt.callLater(function () {
if (adapter.wallpaper.current !== "") { if (adapter.wallpaper.current !== "") {
console.log("Settings: Initializing wallpaper to:", adapter.wallpaper.current) console.log("[Settings] Set current wallpaper")
Wallpapers.setCurrentWallpaper(adapter.wallpaper.current, true) Wallpapers.setCurrentWallpaper(adapter.wallpaper.current, true)
} }
}) })
@ -193,8 +193,14 @@ Singleton {
Connections { Connections {
target: adapter.wallpaper target: adapter.wallpaper
function onIsRandomChanged() { Wallpapers.toggleRandomWallpaper() } function onIsRandomChanged() {
function onRandomIntervalChanged() { Wallpapers.restartRandomWallpaperTimer() } Wallpapers.toggleRandomWallpaper()
function onDirectoryChanged() { Wallpapers.loadWallpapers() } }
function onRandomIntervalChanged() {
Wallpapers.restartRandomWallpaperTimer()
}
function onDirectoryChanged() {
Wallpapers.loadWallpapers()
}
} }
} }

View file

@ -11,6 +11,7 @@ Singleton {
// Public values // Public values
property real cpuUsage: 0 property real cpuUsage: 0
property real cpuTemp: 0 property real cpuTemp: 0
property real memoryUsageGb: 0
property real memoryUsagePer: 0 property real memoryUsagePer: 0
property real diskUsage: 0 property real diskUsage: 0
@ -25,6 +26,7 @@ Singleton {
const data = JSON.parse(line) const data = JSON.parse(line)
root.cpuUsage = data.cpu root.cpuUsage = data.cpu
root.cpuTemp = data.cputemp root.cpuTemp = data.cputemp
root.memoryUsageGb = data.memgb
root.memoryUsagePer = data.memper root.memoryUsagePer = data.memper
root.diskUsage = data.diskper root.diskUsage = data.diskper
} catch (e) { } catch (e) {

View file

@ -69,9 +69,8 @@ ColumnLayout {
font.pointSize: Style.fontSizeMedium * scaling font.pointSize: Style.fontSizeMedium * scaling
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight elide: Text.ElideRight
text: { text: (combo.currentIndex >= 0
return root.optionsLabels[combo.currentIndex] && combo.currentIndex < root.optionsLabels.length) ? root.optionsLabels[combo.currentIndex] : ""
}
} }
// Drop down indicator // Drop down indicator
@ -110,9 +109,8 @@ ColumnLayout {
highlighted: combo.highlightedIndex === index highlighted: combo.highlightedIndex === index
contentItem: NText { contentItem: NText {
text: { text: (combo.model.indexOf(modelData) >= 0 && combo.model.indexOf(
return root.optionsLabels[combo.model.indexOf(modelData)] modelData) < root.optionsLabels.length) ? root.optionsLabels[combo.model.indexOf(modelData)] : ""
}
font.pointSize: Style.fontSizeMedium * scaling font.pointSize: Style.fontSizeMedium * scaling
color: highlighted ? Colors.backgroundPrimary : Colors.textPrimary color: highlighted ? Colors.backgroundPrimary : Colors.textPrimary
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter