From c22ea5dfdac2a9ccea5c2fa41a26a18eed8d1268 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Thu, 2 Apr 2026 23:12:43 +0545 Subject: [PATCH] refactor(modules): simplify SVG asset handling across modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhancements: - Add optimized night‑variant detection for weather icons using a predefined list - Replace `Svg` usage with direct `svg_file` calls throughout the todo widget, removing redundant relative‑path logic - Update dock and battery modules to load assets via direct paths, eliminating unnecessary `get_relative_path` calls- Introduce `WEATHER_CACHE_TIMEOUT` constant and tidy up unused imports (`WEATHER_EMOJI_MAP` removed) - Minor formatting and structural clean‑ups that improve code readability Bug Fixes: - Remove dead import of `WEATHER_EMOJI_MAP` and unused constant `WEATHER_EMOJI_MAP` - Correct syntax of `condition_em` initialization to avoid potential rendering issues New Features: - None. --- modules/controlcenter/battery.py | 2 +- modules/desktop/widget.py | 32 ++++++++++++++++------- modules/dock.py | 6 ++--- modules/launcher/plugins/wallpaper.py | 11 ++++---- modules/osd/components/audio.py | 13 +++------ modules/osd/components/brightness.py | 13 +++------ modules/osd/components/capslock.py | 11 +++----- modules/osd/components/keyboard_layout.py | 7 +++-- modules/osd/components/microphone.py | 13 +++------ modules/todo/todo_widget.py | 31 ++++++++-------------- 10 files changed, 60 insertions(+), 79 deletions(-) diff --git a/modules/controlcenter/battery.py b/modules/controlcenter/battery.py index bc49f74..e8c32ec 100644 --- a/modules/controlcenter/battery.py +++ b/modules/controlcenter/battery.py @@ -31,7 +31,7 @@ def get_battery_icon_file( clamped = max(0, min(100, percentage)) step = (clamped // 10) * 10 filename = f"battery-{step:03d}{'-charging' if is_charging else ''}.svg" - return svg_file(f"battery/{filename}") + return f"battery/{filename}" def set_bluetooth_enabled_with_fallback(client, enabled: bool): diff --git a/modules/desktop/widget.py b/modules/desktop/widget.py index 72472c1..abdc0a6 100644 --- a/modules/desktop/widget.py +++ b/modules/desktop/widget.py @@ -22,8 +22,8 @@ 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, @@ -114,18 +114,28 @@ def format_weather_data(weather_data: Dict[str, Any], city: str) -> List[str]: weather_code = current["weathercode"] 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"]: + 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") @@ -226,7 +236,9 @@ class Weather(Box): ellipsization="end", ) self.temperature = Label(name="temperature", label="--°", h_align="start") - self.condition_em = svg_file("weather/weather-none-available.svg", size=(48, 48), name="condition-emoji") + self.condition_em = svg_file( + "weather/weather-none-available.svg", size=(48, 48), name="condition-emoji" + ) self.condition = Label( name="condition", label="Loading...", @@ -251,16 +263,16 @@ class Weather(Box): return icon_name, temp, condition, location, maxtemp, mintemp, _ = weather_info maxmin = f"H:{maxtemp} L:{mintemp}" - + 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) diff --git a/modules/dock.py b/modules/dock.py index 9b5e801..70552f3 100644 --- a/modules/dock.py +++ b/modules/dock.py @@ -3,7 +3,7 @@ import os import re import subprocess -from fabric.utils.helpers import get_desktop_applications, get_relative_path +from fabric.utils import get_desktop_applications, get_relative_path, logger, GLib, Gtk from fabric.widgets.box import Box from fabric.widgets.button import Button from fabric.widgets.eventbox import EventBox @@ -11,15 +11,13 @@ from fabric.widgets.image import Image from fabric.widgets.label import Label from fabric.widgets.overlay import Overlay from fabric.widgets.revealer import Revealer -from gi.repository import GLib, Gtk -from loguru import logger import config.data as data from services.modus import modus_service from utils.functions import read_json_file, write_json_file, is_special_workspace_id from utils.icon_resolver import IconResolver from utils.occlusion import check_occlusion -from widgets.wayland import WaylandWindow as Window +from fabric.widgets.wayland import WaylandWindow as Window # Pinned apps file PINNED_APPS_FILE = get_relative_path("../config/assets/dock.json") diff --git a/modules/launcher/plugins/wallpaper.py b/modules/launcher/plugins/wallpaper.py index 681711e..0ca1ba4 100644 --- a/modules/launcher/plugins/wallpaper.py +++ b/modules/launcher/plugins/wallpaper.py @@ -10,7 +10,6 @@ from typing import Dict, List, Optional from loguru import logger from gi.repository import GdkPixbuf -from PIL import Image import config.data as data from fabric.utils.helpers import exec_shell_command_async @@ -179,10 +178,10 @@ class WallpaperPlugin(PluginBase): if not os.path.exists(cache_path): try: - with Image.open(full_path) as img: - # Use faster thumbnail creation with smaller size for better performance - img.thumbnail((32, 32), Image.Resampling.LANCZOS) - img.save(cache_path, "PNG", optimize=True) + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( + full_path, 32, 32, True + ) + pixbuf.savev(cache_path, "png", [], []) except Exception as e: logger.error(f"Error creating thumbnail for {filename}: {e}") return None @@ -289,7 +288,7 @@ class WallpaperPlugin(PluginBase): # Always set the wallpaper image exec_shell_command_async( - f'swww img "{ + f'awww img "{ full_path }" -t outer --transition-duration 1.5 --transition-step 255 --transition-fps 60 -f Nearest' ) diff --git a/modules/osd/components/audio.py b/modules/osd/components/audio.py index b5b2f29..c33d4c9 100644 --- a/modules/osd/components/audio.py +++ b/modules/osd/components/audio.py @@ -1,7 +1,6 @@ import math from fabric.audio import Audio -from fabric.utils import get_relative_path -from fabric.widgets.svg import Svg +from utils.utils import svg_file from fabric.widgets.scale import ScaleMark from .animated_scale import AnimatedScale from .base import BaseOSDContainer @@ -17,8 +16,8 @@ class AudioOSDContainer(BaseOSDContainer): self._connect_specific_signals() def _setup_specific_components(self): - self.osd_window_image = Svg( - get_relative_path("../../../config/assets/icons/volume/audio-volume.svg"), + self.osd_window_image = svg_file( + "volume/audio-volume.svg", size=(100, 100), name="osd-image", h_align="center", @@ -87,11 +86,7 @@ class AudioOSDContainer(BaseOSDContainer): 0 if display_volume == 0 else min(int(math.ceil(display_volume / 33)), 3) ) - self.osd_window_image.set_from_file( - get_relative_path( - f"../../../config/assets/icons/volume/audio-volume-{level}.svg" - ) - ) + self.osd_window_image.set_from_file(f"volume/audio-volume-{level}.svg") if muted or volume == 0: self.scale.add_style_class("muted") diff --git a/modules/osd/components/brightness.py b/modules/osd/components/brightness.py index 5d9ff56..fd54841 100644 --- a/modules/osd/components/brightness.py +++ b/modules/osd/components/brightness.py @@ -1,7 +1,6 @@ import math from services.brightness import Brightness -from fabric.utils import get_relative_path -from fabric.widgets.svg import Svg +from utils.utils import svg_file from fabric.widgets.scale import ScaleMark from .animated_scale import AnimatedScale from .base import BaseOSDContainer @@ -15,8 +14,8 @@ class BrightnessOSDContainer(BaseOSDContainer): self._connect_specific_signals() def _setup_specific_components(self): - self.osd_window_image = Svg( - get_relative_path("../../../config/assets/icons/brightness/brightness.svg"), + self.osd_window_image = svg_file( + "brightness/brightness.svg", size=(100, 100), name="osd-image", h_align="center", @@ -51,11 +50,7 @@ class BrightnessOSDContainer(BaseOSDContainer): normalized = self._get_normalized_brightness() level = 0 if normalized == 0 else min(int(math.ceil(normalized / 33)), 3) - self.osd_window_image.set_from_file( - get_relative_path( - f"../../../config/assets/icons/brightness/brightness-{level}.svg" - ) - ) + self.osd_window_image.set_from_file(f"brightness/brightness-{level}.svg") self.scale.animate_value(normalized) diff --git a/modules/osd/components/capslock.py b/modules/osd/components/capslock.py index 3edb32a..4ff7543 100644 --- a/modules/osd/components/capslock.py +++ b/modules/osd/components/capslock.py @@ -1,6 +1,5 @@ from fabric.widgets.label import Label -from fabric.widgets.svg import Svg -from fabric.utils import get_relative_path +from utils.utils import svg_file from .base import BaseOSDContainer from services.capslock import CapsLock @@ -13,8 +12,8 @@ class CapsLockOSDContainer(BaseOSDContainer): self._connect_specific_signals() def _setup_specific_components(self): - self.osd_image = Svg( - get_relative_path("../../../assets/icons/misc/caps-lock.svg"), + self.osd_image = svg_file( + "misc/caps-lock.svg", size=(100, 100), name="osd-image", h_align="center", @@ -35,9 +34,7 @@ class CapsLockOSDContainer(BaseOSDContainer): def _update_display(self, is_on: bool): icon_path = "caps-lock.svg" if is_on else "caps-lock-off.svg" - self.osd_image.set_from_file( - get_relative_path(f"../../../assets/icons/misc/{icon_path}") - ) + self.osd_image.set_from_file(f"misc/{icon_path}") if is_on: self.add_style_class("capslock-on") self.remove_style_class("capslock-off") diff --git a/modules/osd/components/keyboard_layout.py b/modules/osd/components/keyboard_layout.py index 5da0c8b..45de256 100644 --- a/modules/osd/components/keyboard_layout.py +++ b/modules/osd/components/keyboard_layout.py @@ -1,6 +1,5 @@ from fabric.widgets.label import Label -from fabric.widgets.svg import Svg -from fabric.utils import get_relative_path +from utils.utils import svg_file from .base import BaseOSDContainer from services.keyboard_layout import KeyboardLayout @@ -13,8 +12,8 @@ class KeyboardLayoutOSDContainer(BaseOSDContainer): self._connect_specific_signals() def _setup_specific_components(self): - self.osd_image = Svg( - get_relative_path("../../../assets/icons/misc/keyboard-layout.svg"), + self.osd_image = svg_file( + "misc/keyboard-layout.svg", size=(100, 100), name="osd-image", h_align="center", diff --git a/modules/osd/components/microphone.py b/modules/osd/components/microphone.py index 320681c..a7fd590 100644 --- a/modules/osd/components/microphone.py +++ b/modules/osd/components/microphone.py @@ -1,7 +1,6 @@ import math from fabric.audio import Audio -from fabric.utils import get_relative_path -from fabric.widgets.svg import Svg +from utils.utils import svg_file from fabric.widgets.scale import ScaleMark from .animated_scale import AnimatedScale from .base import BaseOSDContainer @@ -17,8 +16,8 @@ class MicrophoneOSDContainer(BaseOSDContainer): self._connect_specific_signals() def _setup_specific_components(self): - self.osd_window_image = Svg( - get_relative_path("../../../config/assets/icons/mic/microphone.svg"), + self.osd_window_image = svg_file( + "mic/microphone.svg", size=(100, 100), name="osd-image", h_align="center", @@ -87,11 +86,7 @@ class MicrophoneOSDContainer(BaseOSDContainer): 0 if display_volume == 0 else min(int(math.ceil(display_volume / 33)), 3) ) - self.osd_window_image.set_from_file( - get_relative_path( - f"../../../config/assets/icons/mic/microphone-{level}.svg" - ) - ) + self.osd_window_image.set_from_file(f"mic/microphone-{level}.svg") if muted or volume == 0: self.scale.add_style_class("muted") diff --git a/modules/todo/todo_widget.py b/modules/todo/todo_widget.py index 200afa7..db6200b 100644 --- a/modules/todo/todo_widget.py +++ b/modules/todo/todo_widget.py @@ -2,16 +2,15 @@ from datetime import datetime # Fabric imports -from fabric.utils import get_relative_path from fabric.widgets.box import Box from fabric.widgets.button import Button from fabric.widgets.entry import Entry from fabric.widgets.label import Label from fabric.widgets.scrolledwindow import ScrolledWindow -from fabric.widgets.svg import Svg from gi.repository import GLib # Local imports +from utils.utils import svg_file from services.todo import get_todo_service from widgets.mousecapture import MouseCapture from widgets.wayland import WaylandWindow as Window @@ -43,12 +42,10 @@ class TodoItem(Box): if self.todo_data["completed"] else "checkbox-uncheck.svg" ) - self.checkbox_icon = Svg( + self.checkbox_icon = svg_file( + "todo/" + checkbox_icon, name="todo-checkbox-icon", size=24, - svg_file=get_relative_path( - "../../config/assets/icons/todo/" + checkbox_icon - ), ) self.checkbox = Button( name="todo-checkbox", @@ -108,10 +105,10 @@ class TodoItem(Box): # ) # # Edit button - using SVG icon - self.edit_icon = Svg( + self.edit_icon = svg_file( + "todo/edit.svg", name="todo-edit-icon", size=12, - svg_file=get_relative_path("../../config/assets/icons/todo/edit.svg"), ) self.edit_button = Button( name="todo-edit", @@ -120,12 +117,10 @@ class TodoItem(Box): ) # Delete button - using SVG icon - self.delete_icon = Svg( + self.delete_icon = svg_file( + "todo/delete-symbolic.svg", name="todo-delete-icon", size=12, - svg_file=get_relative_path( - "../../config/assets/icons/todo/delete-symbolic.svg" - ), ) self.delete_button = Button( name="todo-delete", @@ -208,12 +203,10 @@ class TodoItem(Box): checkbox_icon = ( "checkbox-check.svg" if todo_data["completed"] else "checkbox-uncheck.svg" ) - new_checkbox_icon = Svg( + new_checkbox_icon = svg_file( + "todo/" + checkbox_icon, name="todo-checkbox-icon", size=20, - svg_file=get_relative_path( - "../../config/assets/icons/todo/" + checkbox_icon - ), ) self.checkbox.set_child(new_checkbox_icon) self.checkbox_icon = new_checkbox_icon @@ -293,12 +286,10 @@ class TodoListWidget(Window): self.new_todo_entry.connect("activate", self._add_todo) # Add button - using SVG icon - self.add_icon = Svg( + self.add_icon = svg_file( + "todo/plus-symbolic.svg", name="add-todo-icon", size=12, - svg_file=get_relative_path( - "../../config/assets/icons/todo/plus-symbolic.svg" - ), ) self.add_button = Button( name="add-todo-button",