Add animations everywhere
This commit is contained in:
commit
c3304818f1
16 changed files with 637 additions and 174 deletions
|
|
@ -28,7 +28,7 @@ TEMP_SENSOR_TYPE=""
|
|||
# --- 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() {
|
||||
awk '
|
||||
|
|
@ -39,11 +39,10 @@ get_memory_info() {
|
|||
usage_kb = total - available
|
||||
usage_gb = usage_kb / 1000000
|
||||
usage_percent = (usage_kb / total) * 100
|
||||
# MODIFIED: Round the memory percentage to the nearest integer.
|
||||
printf "%.1f %.0f\n", usage_gb, usage_percent
|
||||
} else {
|
||||
# Fallback if /proc/meminfo is unreadable or empty.
|
||||
print "0.0 0.0"
|
||||
print "0.0 0 0"
|
||||
}
|
||||
}
|
||||
' /proc/meminfo
|
||||
|
|
@ -95,10 +94,8 @@ get_cpu_usage() {
|
|||
if (total > 0) {
|
||||
# Formula: 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
|
||||
} else {
|
||||
# MODIFIED: Changed output back to "0.0" to match the precision.
|
||||
print "0.0"
|
||||
}
|
||||
}'
|
||||
|
|
@ -171,7 +168,7 @@ get_cpu_temp() {
|
|||
# This loop runs indefinitely, gathering and printing stats.
|
||||
while true; do
|
||||
# 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)"
|
||||
|
||||
# Command substitution captures the single output from the other functions.
|
||||
|
|
@ -179,11 +176,11 @@ while true; do
|
|||
cpu_usage=$(get_cpu_usage)
|
||||
cpu_temp=$(get_cpu_temp)
|
||||
|
||||
# Use printf to format the final JSON output string, matching the Zig program.
|
||||
printf '{"mem":"%s", "cpu": "%s", "cputemp": "%s", "memper": "%s", "diskper": "%s"}\n' \
|
||||
"$mem_gb" \
|
||||
# Use printf to format the final JSON output string, adding the mem_mb key.
|
||||
printf '{"cpu": "%s", "cputemp": "%s", "memgb":"%s", "memper": "%s", "diskper": "%s"}\n' \
|
||||
"$cpu_usage" \
|
||||
"$cpu_temp" \
|
||||
"$mem_gb" \
|
||||
"$mem_per" \
|
||||
"$disk_per"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import qs.Widgets
|
|||
|
||||
NLoader {
|
||||
active: Workspaces.isNiri
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
if (Workspaces.isNiri) {
|
||||
console.log("[Overview] Loading Overview component (Niri detected)")
|
||||
|
|
@ -15,55 +15,55 @@ NLoader {
|
|||
console.log("[Overview] Skipping Overview component (Niri not detected)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sourceComponent: Variants {
|
||||
model: Quickshell.screens
|
||||
|
||||
delegate: PanelWindow {
|
||||
required property ShellScreen modelData
|
||||
property string wallpaperSource: Wallpapers.currentWallpaper !== ""
|
||||
&& !Settings.data.wallpaper.swww.enabled ? Wallpapers.currentWallpaper : ""
|
||||
required property ShellScreen modelData
|
||||
property string wallpaperSource: Wallpapers.currentWallpaper !== ""
|
||||
&& !Settings.data.wallpaper.swww.enabled ? Wallpapers.currentWallpaper : ""
|
||||
|
||||
visible: wallpaperSource !== "" && !Settings.data.wallpaper.swww.enabled
|
||||
color: "transparent"
|
||||
screen: modelData
|
||||
WlrLayershell.layer: WlrLayer.Background
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.namespace: "quickshell-overview"
|
||||
visible: wallpaperSource !== "" && !Settings.data.wallpaper.swww.enabled
|
||||
color: "transparent"
|
||||
screen: modelData
|
||||
WlrLayershell.layer: WlrLayer.Background
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.namespace: "quickshell-overview"
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
right: true
|
||||
left: true
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
right: 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ Variants {
|
|||
required property ShellScreen modelData
|
||||
readonly property real scaling: Scaling.scale(screen)
|
||||
|
||||
property var settingsPanel: null
|
||||
|
||||
screen: modelData
|
||||
implicitHeight: Style.barHeight * scaling
|
||||
color: "transparent"
|
||||
|
|
@ -52,11 +50,13 @@ Variants {
|
|||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginSmall * scaling
|
||||
|
||||
NText {
|
||||
text: screen.name
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.weight: Style.fontWeightBold
|
||||
}
|
||||
// Debug show monitor name
|
||||
// NText {
|
||||
// text: screen.name
|
||||
// anchors.verticalCenter: parent.verticalCenter
|
||||
// font.weight: Style.fontWeightBold
|
||||
// }
|
||||
SystemMonitor {}
|
||||
}
|
||||
|
||||
// Center
|
||||
|
|
|
|||
|
|
@ -36,4 +36,4 @@ NIconButton {
|
|||
NotificationHistoryPanel {
|
||||
id: notificationHistoryPanelLoader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,4 +228,4 @@ NLoader {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
84
Modules/Bar/SystemMonitor.qml
Normal file
84
Modules/Bar/SystemMonitor.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,9 +10,6 @@ Item {
|
|||
width: pill.width
|
||||
height: pill.height
|
||||
|
||||
// Reference to settings panel
|
||||
property var settingsPanel: null
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("[Volume] settingsPanel received:", !!settingsPanel)
|
||||
}
|
||||
|
|
@ -87,15 +84,8 @@ Item {
|
|||
}
|
||||
}
|
||||
onClicked: {
|
||||
// Open settings panel and navigate to Audio tab
|
||||
console.log("[Volume] Attempting to open settings panel...")
|
||||
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)
|
||||
}
|
||||
settingsPanel.currentTabIndex = 5 // Audio tab index
|
||||
settingsPanel.isLoaded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import qs.Widgets
|
|||
NLoader {
|
||||
id: root
|
||||
|
||||
property int currentTabIndex: 0
|
||||
|
||||
content: Component {
|
||||
NPanel {
|
||||
id: panel
|
||||
|
|
@ -52,7 +54,6 @@ NLoader {
|
|||
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
|
||||
property int currentTabIndex: 0
|
||||
property var tabsModel: [{
|
||||
"label": "General",
|
||||
"icon": "tune",
|
||||
|
|
@ -89,11 +90,12 @@ NLoader {
|
|||
"label": "Wallpaper Selector",
|
||||
"icon": "wallpaper_slideshow",
|
||||
"source": "Tabs/WallpaperSelector.qml"
|
||||
}, {
|
||||
"label": "Misc",
|
||||
"icon": "more_horiz",
|
||||
"source": "Tabs/Misc.qml"
|
||||
}, {
|
||||
}, // {
|
||||
// "label": "Misc",
|
||||
// "icon": "more_horiz",
|
||||
// "source": "Tabs/Misc.qml"
|
||||
// },
|
||||
{
|
||||
"label": "About",
|
||||
"icon": "info",
|
||||
"source": "Tabs/About.qml"
|
||||
|
|
@ -186,7 +188,7 @@ NLoader {
|
|||
|
||||
delegate: Rectangle {
|
||||
id: tabItem
|
||||
readonly property bool selected: index === panel.currentTabIndex
|
||||
|
||||
width: parent.width
|
||||
height: 32 * scaling // Back to original height
|
||||
radius: Style.radiusSmall * scaling
|
||||
|
|
@ -194,6 +196,8 @@ NLoader {
|
|||
border.color: "transparent"
|
||||
border.width: 0
|
||||
|
||||
readonly property bool selected: index === currentTabIndex
|
||||
|
||||
// Subtle hover effect: only icon/text color tint on hover
|
||||
property bool hovering: false
|
||||
|
||||
|
|
@ -227,7 +231,7 @@ NLoader {
|
|||
onEntered: tabItem.hovering = true
|
||||
onExited: 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
|
||||
NText {
|
||||
text: panel.tabsModel[panel.currentTabIndex].label
|
||||
text: panel.tabsModel[currentTabIndex].label
|
||||
font.pointSize: Style.fontSizeLarge * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Colors.accentPrimary
|
||||
|
|
@ -282,7 +286,7 @@ NLoader {
|
|||
id: stack
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
currentIndex: panel.currentTabIndex
|
||||
currentIndex: currentTabIndex
|
||||
|
||||
Tabs.General {}
|
||||
Tabs.Bar {}
|
||||
|
|
|
|||
|
|
@ -88,14 +88,14 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: allowOverdrive
|
||||
label: "Allow Volume Overdrive"
|
||||
description: "Enable volume levels above 100% (up to 200%)"
|
||||
value: Settings.data.audio ? Settings.data.audio.volumeOverdrive : false
|
||||
onToggled: function (checked) {
|
||||
Settings.data.audio.volumeOverdrive = checked
|
||||
|
||||
NToggle {
|
||||
id: allowOverdrive
|
||||
label: "Allow Volume Overdrive"
|
||||
description: "Enable volume levels above 100% (up to 200%)"
|
||||
value: Settings.data.audio ? Settings.data.audio.volumeOverdrive : false
|
||||
onToggled: function (checked) {
|
||||
Settings.data.audio.volumeOverdrive = checked
|
||||
|
||||
// If overdrive is disabled and current volume is above 100%, cap it
|
||||
if (!checked && Audio.volume > 1.0) {
|
||||
Audio.volumeSet(1.0)
|
||||
|
|
@ -140,58 +140,56 @@ ColumnLayout {
|
|||
font.weight: Style.fontWeightBold
|
||||
color: Colors.textPrimary
|
||||
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
|
||||
ColumnLayout {
|
||||
spacing: Style.marginSmall * scaling
|
||||
|
|
@ -298,11 +296,11 @@ ColumnLayout {
|
|||
outputDeviceCombo.optionsKeys = outputDeviceKeys
|
||||
outputDeviceCombo.optionsLabels = outputDeviceLabels
|
||||
}
|
||||
|
||||
|
||||
if (inputDeviceCombo) {
|
||||
inputDeviceCombo.optionsKeys = inputDeviceKeys
|
||||
inputDeviceCombo.optionsLabels = inputDeviceLabels
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,8 +39,6 @@ ColumnLayout {
|
|||
color: Colors.textPrimary
|
||||
Layout.bottomMargin: Style.marginSmall * scaling
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,11 +62,18 @@ NBox {
|
|||
}
|
||||
}
|
||||
NIconButton {
|
||||
id: powerButton
|
||||
icon: "power_settings_new"
|
||||
onClicked: {
|
||||
//settingsPanel.isLoaded = !settingsPanel.isLoaded
|
||||
powerMenu.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// Uptime
|
||||
Timer {
|
||||
interval: 60000
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ NBox {
|
|||
// Wallpaper
|
||||
NIconButton {
|
||||
icon: "image"
|
||||
onClicked: {
|
||||
settingsPanel.currentTabIndex = 8 // Audio tab index
|
||||
settingsPanel.isLoaded = true
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ QtObject {
|
|||
property int maxHistory: 100
|
||||
|
||||
// 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
|
||||
property FileView historyFileView: FileView {
|
||||
|
|
@ -130,12 +131,12 @@ QtObject {
|
|||
// Add a simplified copy into persistent history
|
||||
function addToHistory(notification) {
|
||||
historyModel.insert(0, {
|
||||
"summary": notification.summary,
|
||||
"body": notification.body,
|
||||
"appName": notification.appName,
|
||||
"urgency": notification.urgency,
|
||||
"timestamp": new Date()
|
||||
})
|
||||
"summary": notification.summary,
|
||||
"body": notification.body,
|
||||
"appName": notification.appName,
|
||||
"urgency": notification.urgency,
|
||||
"timestamp": new Date()
|
||||
})
|
||||
while (historyModel.count > maxHistory) {
|
||||
historyModel.remove(historyModel.count - 1)
|
||||
}
|
||||
|
|
@ -155,12 +156,12 @@ QtObject {
|
|||
for (var i = 0; i < items.length; i++) {
|
||||
const it = items[i]
|
||||
historyModel.append({
|
||||
"summary": it.summary || "",
|
||||
"body": it.body || "",
|
||||
"appName": it.appName || "",
|
||||
"urgency": it.urgency,
|
||||
"timestamp": it.timestamp ? new Date(it.timestamp) : new Date()
|
||||
})
|
||||
"summary": it.summary || "",
|
||||
"body": it.body || "",
|
||||
"appName": it.appName || "",
|
||||
"urgency": it.urgency,
|
||||
"timestamp": it.timestamp ? new Date(it.timestamp) : new Date()
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Notifications] Failed to load history:", e)
|
||||
|
|
@ -174,11 +175,11 @@ QtObject {
|
|||
for (var i = 0; i < historyModel.count; i++) {
|
||||
const n = historyModel.get(i)
|
||||
arr.push({
|
||||
summary: n.summary,
|
||||
body: n.body,
|
||||
appName: n.appName,
|
||||
urgency: n.urgency,
|
||||
timestamp: (n.timestamp instanceof Date) ? n.timestamp.getTime() : n.timestamp
|
||||
"summary": n.summary,
|
||||
"body": n.body,
|
||||
"appName": n.appName,
|
||||
"urgency": n.urgency,
|
||||
"timestamp": (n.timestamp instanceof Date) ? n.timestamp.getTime() : n.timestamp
|
||||
})
|
||||
}
|
||||
historyAdapter.history = arr
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ Singleton {
|
|||
onLoaded: function () {
|
||||
Qt.callLater(function () {
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
|
@ -193,8 +193,14 @@ Singleton {
|
|||
|
||||
Connections {
|
||||
target: adapter.wallpaper
|
||||
function onIsRandomChanged() { Wallpapers.toggleRandomWallpaper() }
|
||||
function onRandomIntervalChanged() { Wallpapers.restartRandomWallpaperTimer() }
|
||||
function onDirectoryChanged() { Wallpapers.loadWallpapers() }
|
||||
function onIsRandomChanged() {
|
||||
Wallpapers.toggleRandomWallpaper()
|
||||
}
|
||||
function onRandomIntervalChanged() {
|
||||
Wallpapers.restartRandomWallpaperTimer()
|
||||
}
|
||||
function onDirectoryChanged() {
|
||||
Wallpapers.loadWallpapers()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ Singleton {
|
|||
// Public values
|
||||
property real cpuUsage: 0
|
||||
property real cpuTemp: 0
|
||||
property real memoryUsageGb: 0
|
||||
property real memoryUsagePer: 0
|
||||
property real diskUsage: 0
|
||||
|
||||
|
|
@ -25,6 +26,7 @@ Singleton {
|
|||
const data = JSON.parse(line)
|
||||
root.cpuUsage = data.cpu
|
||||
root.cpuTemp = data.cputemp
|
||||
root.memoryUsageGb = data.memgb
|
||||
root.memoryUsagePer = data.memper
|
||||
root.diskUsage = data.diskper
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -69,9 +69,8 @@ ColumnLayout {
|
|||
font.pointSize: Style.fontSizeMedium * scaling
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
text: {
|
||||
return root.optionsLabels[combo.currentIndex]
|
||||
}
|
||||
text: (combo.currentIndex >= 0
|
||||
&& combo.currentIndex < root.optionsLabels.length) ? root.optionsLabels[combo.currentIndex] : ""
|
||||
}
|
||||
|
||||
// Drop down indicator
|
||||
|
|
@ -110,9 +109,8 @@ ColumnLayout {
|
|||
highlighted: combo.highlightedIndex === index
|
||||
|
||||
contentItem: NText {
|
||||
text: {
|
||||
return root.optionsLabels[combo.model.indexOf(modelData)]
|
||||
}
|
||||
text: (combo.model.indexOf(modelData) >= 0 && combo.model.indexOf(
|
||||
modelData) < root.optionsLabels.length) ? root.optionsLabels[combo.model.indexOf(modelData)] : ""
|
||||
font.pointSize: Style.fontSizeMedium * scaling
|
||||
color: highlighted ? Colors.backgroundPrimary : Colors.textPrimary
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue