From 6ecbdda121673e26d4ea76438355294114f705a6 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Sun, 31 Aug 2025 10:24:01 -0400 Subject: [PATCH 1/4] Location: should fix edge case of location data being not ready on time --- Commons/Settings.qml | 2 +- Modules/SettingsPanel/Tabs/DisplayTab.qml | 2 +- Modules/SettingsPanel/Tabs/TimeWeatherTab.qml | 4 +- Services/GitHubService.qml | 2 +- Services/LocationService.qml | 78 ++++++++++--------- Services/NightLightService.qml | 8 +- 6 files changed, 51 insertions(+), 45 deletions(-) diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 7a71239..72652d0 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -26,7 +26,7 @@ Singleton { property string defaultAvatar: Quickshell.env("HOME") + "/.face" // Used to access via Settings.data.xxx.yyy - property alias data: adapter + readonly property alias data: adapter property bool isLoaded: false diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml index b2bda25..f00fec4 100644 --- a/Modules/SettingsPanel/Tabs/DisplayTab.qml +++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml @@ -329,7 +329,7 @@ ColumnLayout { NToggle { label: "Automatic Scheduling" - description: `Based on the sunset and sunrise time in ${LocationService.data.stableName} - recommended.` + description: `Based on the sunset and sunrise time in ${LocationService.stableName} - recommended.` checked: Settings.data.nightLight.autoSchedule onToggled: checked => Settings.data.nightLight.autoSchedule = checked visible: Settings.data.nightLight.enabled diff --git a/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml b/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml index 50ea298..6e63738 100644 --- a/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml +++ b/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml @@ -30,8 +30,8 @@ ColumnLayout { } NText { - visible: LocationService.data.coordinatesReady - text: `${LocationService.data.stableName} (${LocationService.displayCoordinates})` + visible: LocationService.coordinatesReady + text: `${LocationService.stableName} (${LocationService.displayCoordinates})` font.pointSize: Style.fontSizeS * scaling color: Color.mOnSurfaceVariant verticalAlignment: Text.AlignVCenter diff --git a/Services/GitHubService.qml b/Services/GitHubService.qml index cb75563..2523a50 100644 --- a/Services/GitHubService.qml +++ b/Services/GitHubService.qml @@ -13,7 +13,7 @@ Singleton { property string githubDataFile: Quickshell.env("NOCTALIA_GITHUB_FILE") || (Settings.cacheDir + "github.json") property int githubUpdateFrequency: 60 * 60 // 1 hour expressed in seconds property bool isFetchingData: false - property alias data: adapter // Used to access via GitHubService.data.xxx.yyy + readonly property alias data: adapter // Used to access via GitHubService.data.xxx.yyy // Public properties for easy access property string latestVersion: "Unknown" diff --git a/Services/LocationService.qml b/Services/LocationService.qml index 5db601e..a8f71b6 100644 --- a/Services/LocationService.qml +++ b/Services/LocationService.qml @@ -13,18 +13,27 @@ Singleton { property string locationFile: Quickshell.env("NOCTALIA_WEATHER_FILE") || (Settings.cacheDir + "location.json") property int weatherUpdateFrequency: 30 * 60 // 30 minutes expressed in seconds property bool isFetchingWeather: false - property alias data: adapter // Used to access via LocationService.data.xxx + + readonly property alias data: adapter // Used to access via LocationService.data.xxx from outside, best to use "adapter" inside the service. + + // Stable UI properties - only updated when location is fully resolved + property bool coordinatesReady: false + property string stableLatitude: "" + property string stableLongitude: "" + property string stableName: "" FileView { id: locationFileView path: locationFile onAdapterUpdated: saveTimer.start() onLoaded: { + Logger.log("Location", "Loaded cached data") // Initialize stable properties on load if (adapter.latitude !== "" && adapter.longitude !== "" && adapter.weatherLastFetch > 0) { - adapter.stableLatitude = adapter.latitude - adapter.stableLongitude = adapter.longitude - adapter.coordinatesReady = true + root.stableLatitude = adapter.latitude + root.stableLongitude = adapter.longitude + root.coordinatesReady = true + Logger.log("Location", "Coordinates ready") } updateWeather() } @@ -42,21 +51,17 @@ Singleton { property int weatherLastFetch: 0 property var weather: null - // Stable UI properties - only updated when location is fully resolved - property bool coordinatesReady: false - property string stableLatitude: "" - property string stableLongitude: "" - property string stableName: "" + } } // Helper property for UI components (outside JsonAdapter to avoid binding loops) readonly property string displayCoordinates: { - if (!data.coordinatesReady || data.stableLatitude === "" || data.stableLongitude === "") { + if (!root.coordinatesReady || root.stableLatitude === "" || root.stableLongitude === "") { return "" } - const lat = parseFloat(data.stableLatitude).toFixed(4) - const lon = parseFloat(data.stableLongitude).toFixed(4) + const lat = parseFloat(root.stableLatitude).toFixed(4) + const lon = parseFloat(root.stableLongitude).toFixed(4) return `${lat}, ${lon}` } @@ -90,19 +95,18 @@ Singleton { Logger.log("Location", "Resetting weather data") // Mark as changing to prevent UI updates - data.coordinatesReady = false + root.coordinatesReady = false + // Reset stable properties + root.stableLatitude = "" + root.stableLongitude = "" + root.stableName = "" // Reset core data - data.latitude = "" - data.longitude = "" - data.name = "" - data.weatherLastFetch = 0 - data.weather = null - - // Reset stable properties - data.stableLatitude = "" - data.stableLongitude = "" - data.stableName = "" + adapter.latitude = "" + adapter.longitude = "" + adapter.name = "" + adapter.weatherLastFetch = 0 + adapter.weather = null // Try to fetch immediately updateWeather() @@ -115,9 +119,9 @@ Singleton { return } - if ((data.weatherLastFetch === "") || (data.weather === null) || (data.latitude === "") || (data.longitude === "") - || (data.name !== Settings.data.location.name) - || (Time.timestamp >= data.weatherLastFetch + weatherUpdateFrequency)) { + if ((adapter.weatherLastFetch === "") || (adapter.weather === null) || (adapter.latitude === "") || (adapter.longitude === "") + || (adapter.name !== Settings.data.location.name) + || (Time.timestamp >= adapter.weatherLastFetch + weatherUpdateFrequency)) { getFreshWeather() } } @@ -129,28 +133,28 @@ Singleton { // Check if location name has changed const locationChanged = data.name !== Settings.data.location.name if (locationChanged) { - data.coordinatesReady = false - Logger.log("Location", "Location changed from", data.name, "to", Settings.data.location.name) + root.coordinatesReady = false + Logger.log("Location", "Location changed from", adapter.name, "to", Settings.data.location.name) } - if ((data.latitude === "") || (data.longitude === "") || locationChanged) { + if ((adapter.latitude === "") || (adapter.longitude === "") || locationChanged) { _geocodeLocation(Settings.data.location.name, function (latitude, longitude, name, country) { Logger.log("Location", "Geocoded", Settings.data.location.name, "to:", latitude, "/", longitude) // Save location name - data.name = Settings.data.location.name + adapter.name = Settings.data.location.name // Save GPS coordinates - data.latitude = latitude.toString() - data.longitude = longitude.toString() + adapter.latitude = latitude.toString() + adapter.longitude = longitude.toString() - data.stableName = `${name}, ${country}` + root.stableName = `${name}, ${country}` _fetchWeather(latitude, longitude, errorCallback) }, errorCallback) } else { - _fetchWeather(data.latitude, data.longitude, errorCallback) + _fetchWeather(adapter.latitude, adapter.longitude, errorCallback) } } @@ -200,9 +204,9 @@ Singleton { data.weatherLastFetch = Time.timestamp // Update stable display values only when complete and successful - data.stableLatitude = data.latitude = weatherData.latitude.toString() - data.stableLongitude = data.longitude = weatherData.longitude.toString() - data.coordinatesReady = true + root.stableLatitude = data.latitude = weatherData.latitude.toString() + root.stableLongitude = data.longitude = weatherData.longitude.toString() + root.coordinatesReady = true isFetchingWeather = false Logger.log("Location", "Cached weather to disk - stable coordinates updated") diff --git a/Services/NightLightService.qml b/Services/NightLightService.qml index 9e940a4..36932d8 100644 --- a/Services/NightLightService.qml +++ b/Services/NightLightService.qml @@ -31,7 +31,7 @@ Singleton { var cmd = ["wlsunset"] cmd.push("-t", `${params.nightTemp}`, "-T", `${params.dayTemp}`) if (params.autoSchedule) { - cmd.push("-l", `${LocationService.data.stableLatitude}`, "-L", `${LocationService.data.stableLongitude}`) + cmd.push("-l", `${LocationService.stableLatitude}`, "-L", `${LocationService.stableLongitude}`) } else { cmd.push("-S", params.manualSunrise) cmd.push("-s", params.manualSunset) @@ -55,9 +55,11 @@ Singleton { } Connections { - target: LocationService.data + target: LocationService function onCoordinatesReadyChanged() { - apply() + if (LocationService.coordinatesReady) { + apply() + } } } From b1daf2e8bc53b658d3b4c72445882ab761e772da Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Sun, 31 Aug 2025 10:29:25 -0400 Subject: [PATCH 2/4] Location: Set stable name on load to the user specified name. Until we get a proper weather update --- Services/LocationService.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/Services/LocationService.qml b/Services/LocationService.qml index a8f71b6..6483428 100644 --- a/Services/LocationService.qml +++ b/Services/LocationService.qml @@ -32,6 +32,7 @@ Singleton { if (adapter.latitude !== "" && adapter.longitude !== "" && adapter.weatherLastFetch > 0) { root.stableLatitude = adapter.latitude root.stableLongitude = adapter.longitude + root.stableName = adapter.name root.coordinatesReady = true Logger.log("Location", "Coordinates ready") } From fdf67ab5121f2fbade8c693ae6ab7b4951bf6ce3 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Sun, 31 Aug 2025 10:34:13 -0400 Subject: [PATCH 3/4] ScreenCorners: use the same Math.round() for bar height so corners dont overlap semitransp bar --- Modules/Background/ScreenCorners.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Background/ScreenCorners.qml b/Modules/Background/ScreenCorners.qml index a2c8913..ce3222d 100644 --- a/Modules/Background/ScreenCorners.qml +++ b/Modules/Background/ScreenCorners.qml @@ -45,10 +45,10 @@ Loader { margins { top: ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "top" - && Settings.data.bar.backgroundOpacity > 0 ? Math.floor(Style.barHeight * scaling) : 0 + && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0 bottom: ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "bottom" - && Settings.data.bar.backgroundOpacity > 0 ? Math.floor(Style.barHeight * scaling) : 0 + && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0 } // Source we want to show only as a ring From fcf627c30b814783d6ac7ffd55db8eca9595cd88 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Sun, 31 Aug 2025 10:36:40 -0400 Subject: [PATCH 4/4] BarHeight: more rounding uniformization --- Modules/Bar/Widgets/Tray.qml | 2 +- Modules/Launcher/Launcher.qml | 2 +- Modules/SettingsPanel/Tabs/AboutTab.qml | 2 +- Modules/WiFiPanel/WiFiPanel.qml | 4 ++-- Widgets/NPanel.qml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/Bar/Widgets/Tray.qml b/Modules/Bar/Widgets/Tray.qml index 4160d98..d960f45 100644 --- a/Modules/Bar/Widgets/Tray.qml +++ b/Modules/Bar/Widgets/Tray.qml @@ -104,7 +104,7 @@ Rectangle { // Anchor the menu to the tray icon item (parent) and position it below the icon const menuX = (width / 2) - (trayMenu.item.width / 2) - const menuY = (Style.barHeight * scaling) + const menuY = Math.round(Style.barHeight * scaling) trayMenu.item.menu = modelData.menu trayMenu.item.showAt(parent, menuX, menuY) } else { diff --git a/Modules/Launcher/Launcher.qml b/Modules/Launcher/Launcher.qml index 2ac193a..d2c5553 100644 --- a/Modules/Launcher/Launcher.qml +++ b/Modules/Launcher/Launcher.qml @@ -244,7 +244,7 @@ NPanel { // Search bar Rectangle { Layout.fillWidth: true - Layout.preferredHeight: Style.barHeight * scaling + Layout.preferredHeight: Math.round(Style.barHeight * scaling) Layout.bottomMargin: Style.marginM * scaling radius: Style.radiusM * scaling color: Color.mSurface diff --git a/Modules/SettingsPanel/Tabs/AboutTab.qml b/Modules/SettingsPanel/Tabs/AboutTab.qml index 21c55b2..52ed90c 100644 --- a/Modules/SettingsPanel/Tabs/AboutTab.qml +++ b/Modules/SettingsPanel/Tabs/AboutTab.qml @@ -81,7 +81,7 @@ ColumnLayout { Layout.alignment: Qt.AlignCenter Layout.topMargin: Style.marginS * scaling Layout.preferredWidth: updateText.implicitWidth + 46 * scaling - Layout.preferredHeight: Style.barHeight * scaling + Layout.preferredHeight: Math.round(Style.barHeight * scaling) radius: Style.radiusL * scaling color: updateArea.containsMouse ? Color.mPrimary : Color.transparent border.color: Color.mPrimary diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml index 4349cc4..80323de 100644 --- a/Modules/WiFiPanel/WiFiPanel.qml +++ b/Modules/WiFiPanel/WiFiPanel.qml @@ -271,7 +271,7 @@ NPanel { Item { Layout.fillWidth: true - Layout.preferredHeight: Style.barHeight * scaling + Layout.preferredHeight: Math.round(Style.barHeight * scaling) Rectangle { anchors.fill: parent @@ -313,7 +313,7 @@ NPanel { Rectangle { Layout.preferredWidth: Style.baseWidgetSize * 2.5 * scaling - Layout.preferredHeight: Style.barHeight * scaling + Layout.preferredHeight: Math.round(Style.barHeight * scaling) radius: Style.radiusM * scaling color: Color.mPrimary diff --git a/Widgets/NPanel.qml b/Widgets/NPanel.qml index 2bfc771..e65a1b0 100644 --- a/Widgets/NPanel.qml +++ b/Widgets/NPanel.qml @@ -38,7 +38,7 @@ Loader { property real opacityValue: originalOpacity property alias isClosing: hideTimer.running - readonly property real barHeight: Style.barHeight * scaling + readonly property real barHeight: Math.round(Style.barHeight * scaling) readonly property bool barAtBottom: Settings.data.bar.position === "bottom" signal opened