diff --git a/modules/dashboard/Content.qml b/modules/dashboard/Content.qml index 0a1e23c2..0b49bd77 100644 --- a/modules/dashboard/Content.qml +++ b/modules/dashboard/Content.qml @@ -75,7 +75,7 @@ Item { anchors.bottom: parent.bottom anchors.margins: Tokens.padding.large - radius: Tokens.rounding.large + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) color: "transparent" Flickable { diff --git a/modules/dashboard/Dash.qml b/modules/dashboard/Dash.qml index 02e16231..736f4b09 100644 --- a/modules/dashboard/Dash.qml +++ b/modules/dashboard/Dash.qml @@ -21,7 +21,7 @@ GridLayout { Layout.preferredWidth: Tokens.sizes.dashboard.userWidth Layout.fillHeight: true - radius: Tokens.rounding.extraLarge + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) User { id: user @@ -37,7 +37,7 @@ GridLayout { Layout.preferredWidth: Tokens.sizes.dashboard.weatherWidth Layout.preferredHeight: weather.implicitHeight - radius: Tokens.rounding.extraLarge * 1.5 + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) SmallWeather { id: weather @@ -49,7 +49,7 @@ GridLayout { Layout.preferredWidth: dateTime.implicitWidth Layout.fillHeight: true - radius: Tokens.rounding.large + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) DateTime { id: dateTime @@ -63,7 +63,7 @@ GridLayout { Layout.fillWidth: true Layout.preferredHeight: calendar.implicitHeight - radius: Tokens.rounding.extraLarge + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) Calendar { id: calendar @@ -78,7 +78,7 @@ GridLayout { Layout.preferredWidth: resources.implicitWidth Layout.fillHeight: true - radius: Tokens.rounding.large + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) Resources { id: resources @@ -92,7 +92,7 @@ GridLayout { Layout.preferredWidth: media.implicitWidth Layout.fillHeight: true - radius: Tokens.rounding.extraLarge * 2 + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) Media { id: media diff --git a/modules/dashboard/Tabs.qml b/modules/dashboard/Tabs.qml index d95372b6..fa32d848 100644 --- a/modules/dashboard/Tabs.qml +++ b/modules/dashboard/Tabs.qml @@ -86,7 +86,7 @@ Item { implicitHeight: parent.implicitHeight * 2 color: Colours.palette.m3primary - radius: Tokens.rounding.full + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) } Behavior on x { @@ -148,7 +148,7 @@ Item { anchors.verticalCenter: parent.verticalCenter implicitHeight: parent.height + Tokens.sizes.dashboard.tabIndicatorSpacing * 2 - radius: Tokens.rounding.medium + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) color: tab.current ? Colours.palette.m3primary : Colours.palette.m3onSurface onClicked: root.dashState.currentTab = tab.TabBar.index } diff --git a/modules/dashboard/WeatherTab.qml b/modules/dashboard/WeatherTab.qml index 34a715bc..b0da9cd5 100644 --- a/modules/dashboard/WeatherTab.qml +++ b/modules/dashboard/WeatherTab.qml @@ -67,7 +67,7 @@ Item { Layout.fillWidth: true implicitHeight: bigInfoRow.implicitHeight + Tokens.padding.small - radius: Tokens.rounding.extraLarge * 2 + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) color: Colours.tPalette.m3surfaceContainer RowLayout { @@ -155,7 +155,7 @@ Item { Layout.fillWidth: true implicitHeight: forecastItemColumn.implicitHeight + Tokens.padding.medium * 2 - radius: Tokens.rounding.large + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) color: Colours.tPalette.m3surfaceContainer ColumnLayout { @@ -209,7 +209,7 @@ Item { Layout.fillWidth: true Layout.preferredHeight: 60 - radius: Tokens.rounding.medium + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) color: Colours.tPalette.m3surfaceContainer Row { diff --git a/modules/dashboard/dash/Calendar.qml b/modules/dashboard/dash/Calendar.qml index 9061f2ee..8b5b170b 100644 --- a/modules/dashboard/dash/Calendar.qml +++ b/modules/dashboard/dash/Calendar.qml @@ -62,7 +62,7 @@ CustomMouseArea { StateLayer { color: Colours.palette.m3primary - radius: pressed ? Tokens.rounding.small : Tokens.rounding.large + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) disabled: { const now = new Date(); return root.currMonth === now.getMonth() && root.currYear === now.getFullYear(); diff --git a/modules/dashboard/dash/User.qml b/modules/dashboard/dash/User.qml index 04cfabb1..0378142e 100644 --- a/modules/dashboard/dash/User.qml +++ b/modules/dashboard/dash/User.qml @@ -216,7 +216,7 @@ Item { implicitWidth: 10 implicitHeight: 10 - radius: Tokens.rounding.full + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) color: Colours.palette.m3secondaryContainer } @@ -229,7 +229,7 @@ Item { implicitWidth: 15 implicitHeight: 15 - radius: Tokens.rounding.full + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) color: Colours.palette.m3secondaryContainer } @@ -240,7 +240,7 @@ Item { anchors.leftMargin: -Tokens.padding.medium y: Tokens.padding.extraSmall - radius: Tokens.rounding.largeIncreased + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) color: Colours.palette.m3secondaryContainer implicitWidth: wmLabel.implicitWidth + Tokens.padding.medium * 2 implicitHeight: wmLabel.implicitHeight + Tokens.padding.small * 2 diff --git a/modules/dashboard/media/LyricList.qml b/modules/dashboard/media/LyricList.qml index c5b4e45b..20547c98 100644 --- a/modules/dashboard/media/LyricList.qml +++ b/modules/dashboard/media/LyricList.qml @@ -176,7 +176,7 @@ Item { implicitWidth: shape.implicitSize + Tokens.padding.medium * 2 implicitHeight: shape.implicitSize + Tokens.padding.medium * 2 color: Colours.palette.m3primaryContainer - radius: Tokens.rounding.full + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) LoadingIndicator { id: shape diff --git a/modules/dashboard/media/LyricsInfo.qml b/modules/dashboard/media/LyricsInfo.qml index 1962309d..2b98724b 100644 --- a/modules/dashboard/media/LyricsInfo.qml +++ b/modules/dashboard/media/LyricsInfo.qml @@ -33,7 +33,7 @@ Item { anchors.fill: parent anchors.margins: !btn.pressed && btn.containsMouse ? -Tokens.padding.extraSmall : 0 group: blobGroup - radius: Tokens.rounding.medium + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) Behavior on anchors.margins { Anim {} @@ -50,7 +50,7 @@ Item { implicitHeight: parent.height group: blobGroup - radius: Tokens.rounding.medium + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) deformScale: 0.00001 states: State { diff --git a/modules/dashboard/performance/BatteryTank.qml b/modules/dashboard/performance/BatteryTank.qml index 5b38ff57..9a7aec80 100644 --- a/modules/dashboard/performance/BatteryTank.qml +++ b/modules/dashboard/performance/BatteryTank.qml @@ -12,7 +12,7 @@ StyledClippingRect { property real animPerc: UPower.displayDevice.percentage color: Colours.palette.m3secondaryContainer - radius: Tokens.rounding.large + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) implicitWidth: Config.dashboard.performance.showCpu || (Config.dashboard.performance.showGpu && Gpu.type !== Gpu.None) || Config.dashboard.performance.showStorage || Config.dashboard.performance.showMemory ? Tokens.sizes.dashboard.perfBattWidth : Tokens.sizes.dashboard.perfBattWidthSingle implicitHeight: Tokens.sizes.dashboard.perfBattHeight @@ -39,7 +39,7 @@ StyledClippingRect { implicitHeight: parent.height * root.animPerc color: Colours.palette.m3secondary - radius: Tokens.rounding.extraSmall + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) clip: true Contents { diff --git a/modules/dashboard/performance/HeroCard.qml b/modules/dashboard/performance/HeroCard.qml index 8cc4fce3..41cf4a7e 100644 --- a/modules/dashboard/performance/HeroCard.qml +++ b/modules/dashboard/performance/HeroCard.qml @@ -17,7 +17,7 @@ StyledRect { required property real temperature color: Colours.tPalette.m3surfaceContainer - radius: Tokens.rounding.extraLarge + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) implicitWidth: Tokens.sizes.dashboard.perfHeroCardWidth implicitHeight: Math.max(tempProg.implicitHeight + detailsRow.implicitHeight + Tokens.spacing.large, usageShape.implicitHeight + usageLabel.implicitHeight) + Tokens.padding.large * 2 diff --git a/modules/dashboard/performance/MemoryCard.qml b/modules/dashboard/performance/MemoryCard.qml index 31266387..bff14185 100644 --- a/modules/dashboard/performance/MemoryCard.qml +++ b/modules/dashboard/performance/MemoryCard.qml @@ -12,7 +12,7 @@ StyledRect { readonly property color accent: Colours.palette.m3tertiary color: Colours.tPalette.m3surfaceContainer - radius: Tokens.rounding.medium + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) implicitWidth: layout.implicitWidth + Tokens.padding.extraLargeIncreased * 2 implicitHeight: layout.implicitHeight + Tokens.padding.large * 2 diff --git a/modules/dashboard/performance/NetworkCard.qml b/modules/dashboard/performance/NetworkCard.qml index 68ed3080..cb91e6b7 100644 --- a/modules/dashboard/performance/NetworkCard.qml +++ b/modules/dashboard/performance/NetworkCard.qml @@ -10,7 +10,7 @@ StyledRect { id: root color: Colours.tPalette.m3surfaceContainer - radius: Tokens.rounding.extraLarge + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) implicitWidth: Tokens.sizes.dashboard.perfNetworkCardWidth implicitHeight: Tokens.sizes.dashboard.perfNetworkCardHeight diff --git a/modules/dashboard/performance/StorageCard.qml b/modules/dashboard/performance/StorageCard.qml index 9e1f8693..120b20a0 100644 --- a/modules/dashboard/performance/StorageCard.qml +++ b/modules/dashboard/performance/StorageCard.qml @@ -14,7 +14,7 @@ StyledRect { readonly property real percentage: Storage.primaryDisk?.perc ?? 0 color: Colours.tPalette.m3surfaceContainer - radius: Tokens.rounding.extraExtraLarge + radius: 0 // nosignal: square dashboard cards to match the redesign (F-D1) implicitWidth: layout.implicitWidth + layout.anchors.margins * 2 implicitHeight: layout.implicitHeight + Tokens.padding.large * 2 diff --git a/modules/nsbar/NsBar.qml b/modules/nsbar/NsBar.qml index 92c13c47..760ecd1a 100644 --- a/modules/nsbar/NsBar.qml +++ b/modules/nsbar/NsBar.qml @@ -16,6 +16,7 @@ import Quickshell import Quickshell.Wayland import Quickshell.Bluetooth import Quickshell.Services.UPower +import Quickshell.Services.SystemTray import qs.services import qs.utils import qs.components @@ -139,10 +140,12 @@ Variants { } } - // System tray + // System tray — only shown when an app actually registers a tray + // icon, otherwise the pill just opened an empty panel (F-T1). IconPill { icon: "widgets" panel: "tray" + visible: SystemTray.items.values.length > 0 } // Notifications bell (with unread dot overlaid on the icon) diff --git a/services/Glyphs.qml b/services/Glyphs.qml index fcc31002..26169e2a 100644 --- a/services/Glyphs.qml +++ b/services/Glyphs.qml @@ -145,16 +145,21 @@ Singleton { "warning": root.cp(0xf071), "web_asset_off": root.cp(0xf2d0), "wifi_find": root.cp(0xf1eb), - // weather (Icons.getWeatherIcon) - "clear_day": root.cp(0xf185), - "clear_night": root.cp(0xf186), - "partly_cloudy_day": root.cp(0xf6c4), - "cloudy": root.cp(0xf0c2), - "cloud": root.cp(0xf0c2), - "rainy": root.cp(0xf73d), - "cloudy_snowing": root.cp(0xf2dc), - "foggy": root.cp(0xf75f), - "air": root.cp(0xf72e), + // weather (Icons.getWeatherIcon) — Material-weather family, every + // codepoint verified present in JetBrainsMono Nerd Font Mono. The old + // Font-Awesome mapping had several glyphs absent from the font (rendered + // as "?" boxes) and was missing thunderstorm/snowing_heavy (F-D1). + "clear_day": root.cp(0xf0599), + "clear_night": root.cp(0xf0594), + "partly_cloudy_day": root.cp(0xf0595), + "cloudy": root.cp(0xf0590), + "cloud": root.cp(0xf0590), + "rainy": root.cp(0xf0597), + "cloudy_snowing": root.cp(0xf0598), + "snowing_heavy": root.cp(0xf0f37), + "thunderstorm": root.cp(0xf0593), + "foggy": root.cp(0xf0591), + "air": root.cp(0xf059d), // apps / devices (Icons.get*) "code": root.cp(0xf121), "forum": root.cp(0xf086), diff --git a/services/Weather.qml b/services/Weather.qml index f2b36eec..caf3dc95 100644 --- a/services/Weather.qml +++ b/services/Weather.qml @@ -41,15 +41,43 @@ Singleton { fetchCoordsFromCity(configLocation); } } else if (!loc || timer.elapsed() > 900) { - Requests.get("https://ipinfo.io/json", text => { + fetchLocationFromIp(); + } + } + + // Auto-detect location from the public IP (used when weatherLocation is + // empty). Stock caelestia only queried ipinfo.io with no error handling; + // on the 2026-06-15 hardware test that call never populated `loc` (the + // city path works via the same Requests.get, so it is provider-specific — + // finding F-W2). Repair: wrap parsing defensively and fall back to a second + // provider (geojs.io, which returns separate latitude/longitude fields) on + // any error or empty response. + function fetchLocationFromIp(): void { + const useGeoJs = () => { + Requests.get("https://get.geojs.io/v1/ip/geo.json", text => { + try { + const g = JSON.parse(text); + if (g.latitude && g.longitude) { + loc = g.latitude + "," + g.longitude; + city = g.city ?? ""; + timer.restart(); + } + } catch (e) {} + }); + }; + + Requests.get("https://ipinfo.io/json", text => { + try { const response = JSON.parse(text); if (response.loc) { loc = response.loc; city = response.city ?? ""; timer.restart(); + return; } - }); - } + } catch (e) {} + useGeoJs(); + }, useGeoJs); } function fetchCityFromCoords(coords: string): void { @@ -131,8 +159,10 @@ Singleton { for (let i = 0; i < json.daily.time.length; i++) forecastList.push({ date: json.daily.time[i].replace(/-/g, "/"), - maxTempC: json.daily.temperature_2m_max[i], - minTempC: json.daily.temperature_2m_min[i], + maxTempC: Math.round(json.daily.temperature_2m_max[i]), + minTempC: Math.round(json.daily.temperature_2m_min[i]), + maxTempF: Math.round(toFahrenheit(json.daily.temperature_2m_max[i])), + minTempF: Math.round(toFahrenheit(json.daily.temperature_2m_min[i])), weatherCode: json.daily.weather_code[i], icon: Icons.getWeatherIcon(json.daily.weather_code[i]) }); @@ -210,6 +240,11 @@ Singleton { onLocChanged: fetchWeatherData() + // Stock caelestia only called reload() on a config CHANGE, never at startup, + // so a saved location blanked after a reboot and an empty (auto/IP) location + // never populated on a fresh boot (finding F-W1). Fetch once on load. + Component.onCompleted: reload() + Connections { function onWeatherLocationChanged(): void { root.reload(); @@ -222,7 +257,7 @@ Singleton { interval: 3600000 // 1 hour running: true repeat: true - onTriggered: fetchWeatherData() + onTriggered: reload() // re-detect an auto/IP location too, not just refetch a known one } ElapsedTimer {