From ba6c7358500abb3de72b58cd6b0edec476405952 Mon Sep 17 00:00:00 2001 From: Uyanide Date: Mon, 13 Oct 2025 21:35:34 +0200 Subject: [PATCH] quickshell: CacheServise --- niri/config.kdl | 4 +- niri/config.kdl.template | 4 +- quickshell/Assets/Config/.gitignore | 5 +- quickshell/Assets/Config/Settings.json | 3 +- .../Modules/Bar/Components/FocusedWindow.qml | 15 +++-- quickshell/Services/CacheService.qml | 31 ++++++++++ quickshell/Services/IpService.qml | 3 +- quickshell/Services/LocationService.qml | 4 +- quickshell/Services/LyricsService.qml | 13 ++--- quickshell/Services/Niri.qml | 19 ++++--- quickshell/Services/NotificationService.qml | 2 +- quickshell/Services/SettingsService.qml | 2 + quickshell/shell.qml | 56 +++++++++++-------- 13 files changed, 102 insertions(+), 59 deletions(-) create mode 100644 quickshell/Services/CacheService.qml diff --git a/niri/config.kdl b/niri/config.kdl index e746b19..a6b9175 100644 --- a/niri/config.kdl +++ b/niri/config.kdl @@ -303,8 +303,8 @@ binds { Mod+L { spawn-sh "loginctl lock-session"; } // Media - XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ && wp-vol"; } - XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%- && wp-vol"; } + XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"; } + XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%-"; } XF86AudioMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; } XF86AudioMicMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; } XF86AudioPlay allow-when-locked=true { spawn-sh "playerctl play-pause"; } diff --git a/niri/config.kdl.template b/niri/config.kdl.template index 6ec1f52..55bf5cc 100644 --- a/niri/config.kdl.template +++ b/niri/config.kdl.template @@ -303,8 +303,8 @@ binds { Mod+L { spawn-sh "loginctl lock-session"; } // Media - XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ && wp-vol"; } - XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%- && wp-vol"; } + XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"; } + XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%-"; } XF86AudioMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; } XF86AudioMicMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; } XF86AudioPlay allow-when-locked=true { spawn-sh "playerctl play-pause"; } diff --git a/quickshell/Assets/Config/.gitignore b/quickshell/Assets/Config/.gitignore index 57f40e3..5f1b178 100644 --- a/quickshell/Assets/Config/.gitignore +++ b/quickshell/Assets/Config/.gitignore @@ -1,5 +1,2 @@ # some sensitive files -Location.json -GeoInfoToken.txt -IpCache.json -Notifications.json \ No newline at end of file +GeoInfoToken.txt \ No newline at end of file diff --git a/quickshell/Assets/Config/Settings.json b/quickshell/Assets/Config/Settings.json index 429d32c..adcdd39 100644 --- a/quickshell/Assets/Config/Settings.json +++ b/quickshell/Assets/Config/Settings.json @@ -1,7 +1,8 @@ { + "location": "Munich", "notifications": { "doNotDisturb": false, - "lastSeenTs": 1760375164000 + "lastSeenTs": 1760383655000 }, "primaryColor": "#89b4fa", "showLyricsBar": false diff --git a/quickshell/Modules/Bar/Components/FocusedWindow.qml b/quickshell/Modules/Bar/Components/FocusedWindow.qml index c19bcab..d91bde1 100644 --- a/quickshell/Modules/Bar/Components/FocusedWindow.qml +++ b/quickshell/Modules/Bar/Components/FocusedWindow.qml @@ -5,6 +5,7 @@ import Quickshell import Quickshell.Widgets import qs.Constants import qs.Services +import qs.Utils Item { id: root @@ -12,24 +13,22 @@ Item { property real maxWidth: 250 property string fallbackIcon: "application-x-executable" - function getAppIcon() { + function getAppIcon(appId) { try { - const focusedWindow = Niri.getFocusedWindow(); - if (focusedWindow && focusedWindow.appId) { + if (appId) { try { - const idValue = focusedWindow.appId; - const normalizedId = (typeof idValue === 'string') ? idValue : String(idValue); + const normalizedId = (typeof appId === 'string') ? appId : String(appId); const iconResult = ThemeIcons.iconForAppId(normalizedId.toLowerCase()); if (iconResult && iconResult !== "") return iconResult; } catch (iconError) { - console.warn("Error getting icon from CompositorService:", iconError); + Logger.warn("FocusedWindow", "Error getting icon from CompositorService: " + iconError); } } return ThemeIcons.iconFromName(root.fallbackIcon); } catch (e) { - console.warn("Error in getAppIcon:", e); + Logger.warn("FocusedWindow", "Error in getAppIcon:", e); return ThemeIcons.iconFromName(root.fallbackIcon); } } @@ -55,7 +54,7 @@ Item { id: windowIcon anchors.fill: parent - source: getAppIcon() + source: getAppIcon(Niri.focusedWindowAppId) asynchronous: true smooth: true visible: source !== "" diff --git a/quickshell/Services/CacheService.qml b/quickshell/Services/CacheService.qml new file mode 100644 index 0000000..8b983d7 --- /dev/null +++ b/quickshell/Services/CacheService.qml @@ -0,0 +1,31 @@ +import QtQuick +import Quickshell +import Quickshell.Io +import qs.Utils +pragma Singleton + +Singleton { + id: root + + property string cacheDir: Quickshell.env("HOME") + "/.cache/quickshell/" + property var cacheFiles: ["Location.json", "Ip.json", "Notifications.json", "LyricsOffset.txt"] + property bool loaded: false + property string locationCacheFile: cacheDir + "Location.json" + property string ipCacheFile: cacheDir + "Ip.json" + property string notificationsCacheFile: cacheDir + "Notifications.json" + property string lyricsOffsetCacheFile: cacheDir + "LyricsOffset.txt" + + Process { + id: process + + running: true + command: ["sh", "-c", `mkdir -p ${cacheDir} && touch ${cacheDir + cacheFiles.join(` && touch ${cacheDir}`)}`] + onExited: (code, status) => { + if (code === 0) + root.loaded = true; + else + Logger.error("CacheService", `Failed to create cache files: ${command.join(" ")}`); + } + } + +} diff --git a/quickshell/Services/IpService.qml b/quickshell/Services/IpService.qml index 8c19a02..9bd0ff1 100644 --- a/quickshell/Services/IpService.qml +++ b/quickshell/Services/IpService.qml @@ -7,6 +7,7 @@ pragma Singleton Singleton { property alias ip: cacheFileAdapter.ip + property string cacheFilePath: CacheService.ipCacheFile property string countryCode: "N/A" property real fetchInterval: 120 // in s property real fetchTimeout: 10 // in s @@ -150,7 +151,7 @@ Singleton { FileView { id: cacheFile - path: Qt.resolvedUrl("../Assets/Config/IpCache.json") + path: cacheFilePath watchChanges: false onLoaded: { Logger.log("IpService", "Loaded IP from cache file: " + cacheFileAdapter.ip); diff --git a/quickshell/Services/LocationService.qml b/quickshell/Services/LocationService.qml index 3e4ff1a..a3a2c45 100644 --- a/quickshell/Services/LocationService.qml +++ b/quickshell/Services/LocationService.qml @@ -12,8 +12,8 @@ Singleton { id: root - property string locationName: "Munich" - property string locationFile: Qt.resolvedUrl("../Assets/Config/Location.json") + property string locationName: SettingsService.location + property string locationFile: CacheService.locationCacheFile property int weatherUpdateFrequency: 30 * 60 // 30 minutes expressed in seconds property bool isFetchingWeather: false readonly property alias data: adapter // Used to access via LocationService.data.xxx from outside, best to use "adapter" inside the service. diff --git a/quickshell/Services/LyricsService.qml b/quickshell/Services/LyricsService.qml index e8d19ed..5545f14 100644 --- a/quickshell/Services/LyricsService.qml +++ b/quickshell/Services/LyricsService.qml @@ -9,7 +9,7 @@ Singleton { property int linesCount: 3 property int linesAhead: linesCount / 2 property int currentIndex: linesCount - linesAhead - 1 - property string offsetFile: Qt.resolvedUrl("../Assets/Config/LyricsOffset.txt") + property string offsetFile: CacheService.lyricsOffsetCacheFile property int offset: 0 // in ms property int offsetStep: 500 // in ms property int referenceCount: 0 @@ -26,7 +26,7 @@ Singleton { Logger.log("LyricsService", "Starting lyrics syncing"); // fill lyrics with empty lines lyrics = Array(linesCount).fill(" "); - listenProcess.exec(["sh", "-c", `sl-wrap listen -l ${linesCount} -a ${linesAhead} -f ${offsetFile.slice(7)}`]); + listenProcess.exec(["sh", "-c", `sl-wrap listen -l ${linesCount} -a ${linesAhead} -f ${offsetFile}`]); } } @@ -127,17 +127,14 @@ Singleton { writeOffset(); } } catch (e) { - Logger.log("LyricsService", "Error reading offset file:", e); + Logger.error("LyricsService", "Error reading offset file:", e); } } onLoadFailed: { - Logger.log("LyricsService", "Error loading offset file:", errorString); + Logger.error("LyricsService", "Error loading offset file:", errorString); } onSaveFailed: { - Logger.log("LyricsService", "Error saving offset file:", errorString); - } - onSaved: { - Logger.log("LyricsService", "Offset file saved."); + Logger.error("LyricsService", "Error saving offset file:", errorString); } } diff --git a/quickshell/Services/Niri.qml b/quickshell/Services/Niri.qml index 9a12197..93e47bf 100644 --- a/quickshell/Services/Niri.qml +++ b/quickshell/Services/Niri.qml @@ -14,15 +14,15 @@ Singleton { property bool noFocus: focusedWindowId === -1 property bool inOverview: false property string focusedWindowTitle: "" - // property string focusedWindowAppId: "" + property string focusedWindowAppId: "" function updateFocusedWindowTitle() { if (windows && windows[focusedWindowId]) { focusedWindowTitle = windows[focusedWindowId].title || ""; - // focusedWindowAppId = windows[focusedWindowId].appId || ""; + focusedWindowAppId = windows[focusedWindowId].appId || ""; } else { focusedWindowTitle = ""; - // focusedWindowAppId = ""; + focusedWindowAppId = ""; } } @@ -30,8 +30,6 @@ Singleton { return (windows && windows[focusedWindowId]) || null; } - onWindowsChanged: updateFocusedWindowTitle() - onFocusedWindowIdChanged: updateFocusedWindowTitle() Component.onCompleted: { eventStream.running = true; } @@ -102,6 +100,7 @@ Singleton { }; } root.windows = windowsMap; + root.updateFocusedWindowTitle(); } catch (e) { Logger.error("Niri", "Error parsing windows event:", e); } @@ -120,6 +119,7 @@ Singleton { } else { root.focusedWindowId = -1; } + root.updateFocusedWindowTitle(); } catch (e) { Logger.error("Niri", "Error parsing window focus event:", e); } @@ -155,9 +155,10 @@ Singleton { root.windows[id] = targetWin; } if (isFocused) { - root.focusedWindowId = id; - if (needUpdateTitle) + if (root.focusedWindowId !== id || needUpdateTitle){ + root.focusedWindowId = id; root.updateFocusedWindowTitle(); + } } } @@ -169,6 +170,10 @@ Singleton { const closedId = event.windowClosed.id; if (closedId && (root.windows && root.windows[closedId])) { delete root.windows[closedId]; + if (root.focusedWindowId === closedId) { + root.focusedWindowId = -1; + root.updateFocusedWindowTitle(); + } } } catch (e) { Logger.error("Niri", "Error parsing window closed event:", e); diff --git a/quickshell/Services/NotificationService.qml b/quickshell/Services/NotificationService.qml index 1d272cb..dc4e67e 100644 --- a/quickshell/Services/NotificationService.qml +++ b/quickshell/Services/NotificationService.qml @@ -16,7 +16,7 @@ Singleton { // Configuration property int maxVisible: 5 property int maxHistory: 100 - property string historyFile: Qt.resolvedUrl("../Assets/Config/Notifications.json") + property string historyFile: CacheService.notificationsCacheFile property string cacheDirImagesNotifications: Quickshell.env("HOME") + "/.cache/quickshell/notifications/" property real lowUrgencyDuration: 3 property real normalUrgencyDuration: 8 diff --git a/quickshell/Services/SettingsService.qml b/quickshell/Services/SettingsService.qml index e817a7b..0081692 100644 --- a/quickshell/Services/SettingsService.qml +++ b/quickshell/Services/SettingsService.qml @@ -9,6 +9,7 @@ Singleton { property alias primaryColor: adapter.primaryColor property alias showLyricsBar: adapter.showLyricsBar property alias notifications: adapter.notifications + property alias location: adapter.location property string settingsFilePath: Qt.resolvedUrl("../Assets/Config/Settings.json") FileView { @@ -25,6 +26,7 @@ Singleton { property string primaryColor: "#89b4fa" property bool showLyricsBar: false property JsonObject notifications + property string location: "New York" notifications: JsonObject { property bool doNotDisturb: false diff --git a/quickshell/shell.qml b/quickshell/shell.qml index 97dcd1e..a889994 100644 --- a/quickshell/shell.qml +++ b/quickshell/shell.qml @@ -10,38 +10,48 @@ import qs.Services ShellRoot { id: root - Notification { - id: notification - } + Loader { + id: loader - IPCService { - id: ipcService - } + active: CacheService.loaded - Bar { - id: bar - } + sourceComponent: Item { + Notification { + id: notification + } - Corners { - id: corners - } + IPCService { + id: ipcService + } - CalendarPanel { - id: calendarPanel + Bar { + id: bar + } - objectName: "calendarPanel" - } + Corners { + id: corners + } - ControlCenterPanel { - id: controlCenterPanel + CalendarPanel { + id: calendarPanel - objectName: "controlCenterPanel" - } + objectName: "calendarPanel" + } - NotificationHistoryPanel { - id: notificationHistoryPanel + ControlCenterPanel { + id: controlCenterPanel + + objectName: "controlCenterPanel" + } + + NotificationHistoryPanel { + id: notificationHistoryPanel + + objectName: "notificationHistoryPanel" + } + + } - objectName: "notificationHistoryPanel" } }