feat(modules/desktop): addweather SVG icon mapping and improve condition label handling

Why: replaced emoji-based weather icons with a dynamic SVG mapping, introduced WEATHER_ICON_MAP, updated format_weather_data and Weather class to use icon names and svg_file, removed unused constants and clarified day/night variant handling.

- New Features
  - Added WEATHER_ICON_MAP linking weather codes to SVG identifiers and supporting night variants.
  - Updated format_weather_data to return icon_name and use svg_file for dynamic icon resolution.
  - Modified Weather widget to set condition label via dynamic SVG files instead of emoji.

- Enhancements
  - Implemented day/night icon variant logic using optimistic naming based on known variants.
  - Removed unused constant imports and simplified label update logic.
  - Improved error handling with explicit fallbacks for missing weather fields.

- Bug Fixes
  - Fixed potential missing icon fallback by using .get with default values.
  - Corrected label assignment order to match new data structure.
This commit is contained in:
sankalp committed 2026-03-23 23:40:31 +05:45
1 parent c35550d209
commit 5656609348
2 files changed
+62 -14

No files matched your search

+32
View File
@@ -87,6 +87,38 @@ WEATHER_EMOJI_MAP = {
99: "⛈️", # Thunderstorm with heavy hail
}
# Weather condition to SVG icon mapping
WEATHER_ICON_MAP = {
0: "weather-clear",
1: "weather-few-clouds",
2: "weather-clouds",
3: "weather-overcast",
45: "weather-fog",
48: "weather-fog",
51: "weather-showers-scattered",
53: "weather-showers",
55: "weather-showers",
61: "weather-showers-scattered",
80: "weather-showers-scattered",
63: "weather-showers",
65: "weather-showers",
81: "weather-showers",
82: "weather-storm",
56: "weather-freezing-rain",
57: "weather-freezing-rain",
66: "weather-freezing-rain",
67: "weather-freezing-rain",
71: "weather-snow",
73: "weather-snow",
75: "weather-snow",
77: "weather-hail",
85: "weather-snow-scattered",
86: "weather-snow-scattered",
95: "weather-storm",
96: "weather-storm",
99: "weather-storm",
}
# Weather condition descriptions
WEATHER_DESC_MAP = {
0: "Clear sky",
+30 -14
View File
@@ -22,13 +22,14 @@ from modules.desktop.constants import (
LOCATION_APIS,
LOCATION_CACHE_TIMEOUT,
SYSTEM_UPDATE_INTERVAL,
WEATHER_CACHE_TIMEOUT,
WEATHER_DESC_MAP,
WEATHER_EMOJI_MAP,
WEATHER_ICON_MAP,
WEATHER_GRADIENT_MAP,
WEATHER_UPDATE_INTERVAL,
)
from utils.debounce import sync_debounce
from utils.utils import svg_file
# Thread pool for async operations
executor = ThreadPoolExecutor(max_workers=4)
@@ -112,7 +113,21 @@ def format_weather_data(weather_data: Dict[str, Any], city: str) -> List[str]:
daily = weather_data["daily"]
weather_code = current["weathercode"]
emoji = WEATHER_EMOJI_MAP.get(weather_code, "🌤️")
is_day = current.get("is_day", 1) # Default to day if missing
base_icon = WEATHER_ICON_MAP.get(weather_code, "weather-none-available")
# Determine day/night variant if applicable
icon_name = base_icon
if not is_day:
night_variant = f"{base_icon}-night"
import os
# Fast check if night variant exists using predefined list or checking the path
# Since we know the variants from earlier, let's just optimistically build it
# then logic in svg_file will handle resolution seamlessly (fallbacks can be tricky, but we assume it's correct)
if base_icon in ["weather-clear", "weather-clouds", "weather-few-clouds", "weather-overcast", "weather-showers", "weather-showers-scattered", "weather-snow", "weather-snow-scattered", "weather-storm"]:
icon_name = night_variant
condition = WEATHER_DESC_MAP.get(weather_code, "Unknown")
gradient_class = WEATHER_GRADIENT_MAP.get(weather_code, "weather-clear")
@@ -120,7 +135,7 @@ def format_weather_data(weather_data: Dict[str, Any], city: str) -> List[str]:
max_temp = f"{round(daily['temperature_2m_max'][0])}°"
min_temp = f"{round(daily['temperature_2m_min'][0])}°"
return [emoji, temp, condition, city, max_temp, min_temp, gradient_class]
return [icon_name, temp, condition, city, max_temp, min_temp, gradient_class]
except (KeyError, IndexError, TypeError) as e:
print(f"Error formatting weather data: {e}")
return None
@@ -211,7 +226,7 @@ class Weather(Box):
ellipsization="end",
)
self.temperature = Label(name="temperature", label="--°", h_align="start")
self.condition_em = Label(name="condition-emoji", label="🌤️", h_align="start")
self.condition_em = svg_file("weather/weather-none-available.svg", size=(48, 48), name="condition-emoji")
self.condition = Label(
name="condition",
label="Loading...",
@@ -234,17 +249,18 @@ class Weather(Box):
def update_labels(self, weather_info: List[str]):
if not weather_info or len(weather_info) != 7:
return
emoji, temp, condition, location, maxtemp, mintemp, _ = weather_info
icon_name, temp, condition, location, maxtemp, mintemp, _ = weather_info
maxmin = f"H:{maxtemp} L:{mintemp}"
updates = [
(self.city, location),
(self.temperature, temp),
(self.condition_em, emoji),
(self.condition, condition),
(self.feels_like, maxmin),
]
for label, text in updates:
label.set_label(text)
self.city.set_label(location)
self.temperature.set_label(temp)
# update SVG File
self.condition_em.dynamic_file(f"weather/{icon_name}.svg")
self.condition.set_label(condition)
self.feels_like.set_label(maxmin)
self.parent.set_visible(True)