From 9501d244d658f9747a8822d19d9d2c7e8bb9f1d8 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Fri, 28 Feb 2025 16:28:06 +0545 Subject: [PATCH] rename snippets to utils --- snippets/animator.py | 179 --------------------------- snippets/icon.py | 16 --- {snippets => utils}/__init__.py | 5 +- {snippets => utils}/custom_image.py | 0 utils/icon_resolver.py | 103 +++++++++++++++ snippets/iconss.py => utils/icons.py | 6 +- 6 files changed, 109 insertions(+), 200 deletions(-) delete mode 100644 snippets/animator.py delete mode 100644 snippets/icon.py rename {snippets => utils}/__init__.py (84%) rename {snippets => utils}/custom_image.py (100%) create mode 100644 utils/icon_resolver.py rename snippets/iconss.py => utils/icons.py (96%) diff --git a/snippets/animator.py b/snippets/animator.py deleted file mode 100644 index 1799ae6..0000000 --- a/snippets/animator.py +++ /dev/null @@ -1,179 +0,0 @@ -from typing import cast - -from fabric import Property, Service, Signal -from gi.repository import GLib, Gtk - - -class Animator(Service): - @Signal - def finished(self) -> None: ... - - @Property(tuple[float, float, float, float], "read-write") - def bezier_curve(self) -> tuple[float, float, float, float]: - return self._bezier_curve - - @bezier_curve.setter - def bezier_curve(self, value: tuple[float, float, float, float]): - self._bezier_curve = value - return - - @Property(float, "read-write") - def value(self): - return self._value - - @value.setter - def value(self, value: float): - self._value = value - return - - @Property(float, "read-write") - def max_value(self): - return self._max_value - - @max_value.setter - def max_value(self, value: float): - self._max_value = value - return - - @Property(float, "read-write") - def min_value(self): - return self._min_value - - @min_value.setter - def min_value(self, value: float): - self._min_value = value - return - - @Property(bool, "read-write", default_value=False) - def playing(self): - return self._playing - - @playing.setter - def playing(self, value: bool): - self._playing = value - return - - @Property(bool, "read-write", default_value=False) - def repeat(self): - return self._repeat - - @repeat.setter - def repeat(self, value: bool): - self._repeat = value - return - - def __init__( - self, - bezier_curve: tuple[float, float, float, float], - duration: float, - min_value: float = 0.0, - max_value: float = 1.0, - repeat: bool = False, - tick_widget: Gtk.Widget | None = None, - **kwargs, - ): - super().__init__(**kwargs) - self._bezier_curve = (1, 0, 1, 1) - self._duration = 5 - self._value = 0.0 - self._min_value = 0.0 - self._max_value = 1.0 - self._repeat = False - - self.bezier_curve = bezier_curve - self.duration = duration - self.value = min_value - self.min_value = min_value - self.max_value = max_value - self.repeat = repeat - - self.playing = False - self._start_time = None - self._tick_handler = None - self._timeline_pos = 0 - self._tick_widget = tick_widget - - def do_get_time_now(self): - return GLib.get_monotonic_time() / 1_000_000 - - def do_lerp(self, start: float, end: float, time: float) -> float: - return start + (end - start) * time - - def do_interpolate_cubic_bezier(self, time: float) -> float: - y_points = (0, self.bezier_curve[1], self.bezier_curve[3], 1) - return ( - (1 - time) ** 3 * y_points[0] - + 3 * (1 - time) ** 2 * time * y_points[1] - + 3 * (1 - time) * time**2 * y_points[2] - + time**3 * y_points[3] - ) - - def do_ease(self, time: float) -> float: - return self.do_lerp( - self.min_value, self.max_value, self.do_interpolate_cubic_bezier(time) - ) - - def do_update_value(self, delta_time: float): - if not self.playing: - return - - elapsed_time = delta_time - cast(float, self._start_time) - - self._timeline_pos = min(1, elapsed_time / self.duration) - - self.value = self.do_ease(self._timeline_pos) - - if not self._timeline_pos >= 1: - return - - if not self.repeat: - self.value = self.max_value - self.finished() - self.pause() - return - - self._start_time = delta_time - self._timeline_pos = 0 - return - - def do_handle_tick(self, *_): - current_time = self.do_get_time_now() - self.do_update_value(current_time) - return True - - def do_remove_tick_handlers(self): - if self._tick_handler: - if self._tick_widget: - self._tick_widget.remove_tick_callback(self._tick_handler) - else: - GLib.source_remove(self._tick_handler) - self._tick_handler = None - return - - def play(self): - if self.playing: - return - - self._start_time = self.do_get_time_now() - - if not self._tick_handler: - if self._tick_widget: - self._tick_handler = self._tick_widget.add_tick_callback( - self.do_handle_tick - ) - else: - self._tick_handler = GLib.timeout_add(16, self.do_handle_tick) - - self.playing = True - return - - def pause(self): - self.playing = False - return self.do_remove_tick_handlers() - - def stop(self): - if not self._tick_handler: - self._timeline_pos = 0 - self.playing = False - return - return self.do_remove_tick_handlers() diff --git a/snippets/icon.py b/snippets/icon.py deleted file mode 100644 index 86e77c0..0000000 --- a/snippets/icon.py +++ /dev/null @@ -1,16 +0,0 @@ -from fabric.widgets.label import Label - - -def MaterialIcon(icon_name: str, size: int = 24, props=None): - label_props = { - "label": str(icon_name), # Directly use the provided icon name - "name": "material_icon", - "style": f"font-size: {size}px;", # Set font family for Material Icons - "h_align": "center", # Align horizontally - "v_align": "center", # Align vertically - } - - if props: - label_props.update(props) - - return Label(**label_props) diff --git a/snippets/__init__.py b/utils/__init__.py similarity index 84% rename from snippets/__init__.py rename to utils/__init__.py index d4d3f96..587fe40 100644 --- a/snippets/__init__.py +++ b/utils/__init__.py @@ -1,13 +1,12 @@ -from .animator import * from .custom_image import * -from .icon import * +from .icon_resolver import * import json import os from fabric.utils import get_relative_path def read_config(): - config_path = get_relative_path("../config/assets/launcher.json") + config_path = get_relative_path("../config/assets/modus.json") with open(config_path, "r") as file: # Load JSON data into a Python dictionary diff --git a/snippets/custom_image.py b/utils/custom_image.py similarity index 100% rename from snippets/custom_image.py rename to utils/custom_image.py diff --git a/utils/icon_resolver.py b/utils/icon_resolver.py new file mode 100644 index 0000000..cd814c7 --- /dev/null +++ b/utils/icon_resolver.py @@ -0,0 +1,103 @@ +import json +import os +import re + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import GLib, Gtk +from loguru import logger + + +# TODO WIP +# Idea: nearest string matching algorithm +# if already exists: retrieve from json +# if found: stor in json: app_id -> icon_name +# if not found: store in json -> misisng-icon + + +CACHE_DIR = str(GLib.get_user_cache_dir()) + "/modus" +ICON_CACHE_FILE = CACHE_DIR + "/icons.json" +if not os.path.exists(CACHE_DIR): + os.makedirs(CACHE_DIR) + + +class IconResolver: + def __init__( + self, default_applicaiton_icon: str = "application-x-executable-symbolic" + ): + if os.path.exists(ICON_CACHE_FILE): + f = open(ICON_CACHE_FILE) + try: + self._icon_dict = json.load(f) + except json.JSONDecodeError: + logger.info("[ICONS] Cache file does not exist or is corrupted") + f.close() + else: + self._icon_dict = {} + + self.default_applicaiton_icon = default_applicaiton_icon + + def get_icon_name(self, app_id: str): + if app_id in self._icon_dict: + return self._icon_dict[app_id] + new_icon = self._compositor_find_icon(app_id) + logger.info( + f"[ICONS] found new icon: '{new_icon}' for app id: '{app_id}', storing..." + ) + self._store_new_icon(app_id, new_icon) + return new_icon + + def get_icon_pixbuf(self, app_id: str, size: int = 16): + return Gtk.IconTheme.get_default().load_icon( + self.get_icon_name(app_id), + size, + Gtk.IconLookupFlags.FORCE_SIZE, + ) + + def _store_new_icon(self, app_id: str, icon: str): + self._icon_dict[app_id] = icon + with open(ICON_CACHE_FILE, "w") as f: + json.dump(self._icon_dict, f) + f.close() + + def _get_icon_from_desktop_file(self, desktop_file_path: str): + # TODO: get icon in the [Desktop Entry] section only + with open(desktop_file_path) as f: + for line in f.readlines(): + if "Icon=" in line: + return "".join(line[5:].split()) + return self.default_applicaiton_icon + + def _get_desktop_file(self, app_id: str) -> str | None: + data_dirs = GLib.get_system_data_dirs() + for data_dir in data_dirs: + data_dir = data_dir + "/applications/" + if os.path.exists(data_dir): + # Do name resolving here + + files = os.listdir(data_dir) + matching = [ + s for s in files if "".join(app_id.lower().split()) in s.lower() + ] + if matching: + return data_dir + matching[0] + + for word in list(filter(None, re.split(r"-|\.|_|\s", app_id))): + matching = [s for s in files if word.lower() in s.lower()] + if matching: + return data_dir + matching[0] + + return None + + def _compositor_find_icon(self, app_id: str): + if Gtk.IconTheme.get_default().has_icon(app_id): + return app_id + if Gtk.IconTheme.get_default().has_icon(app_id + "-desktop"): + return app_id + "-desktop" + desktop_file = self._get_desktop_file(app_id) + return ( + self._get_icon_from_desktop_file(desktop_file) + if desktop_file + else self.default_applicaiton_icon + ) diff --git a/snippets/iconss.py b/utils/icons.py similarity index 96% rename from snippets/iconss.py rename to utils/icons.py index 78eb34d..79c2407 100644 --- a/snippets/iconss.py +++ b/utils/icons.py @@ -53,8 +53,8 @@ shutdown: str = "" power_saving: str = "" power_balanced: str = "勺" power_performance: str = "" -charging: str = "𐁣" -discharging: str = "𐁪" +charging: str = "" +discharging: str = "" alert: str = "" # Applets @@ -64,6 +64,7 @@ night: str = "" coffee: str = "" dnd: str = "" darkmode: str = "﹖" +world: str = "" wifi_off: str = "" bluetooth_off: str = "" @@ -128,6 +129,7 @@ disc_off: str = "" # Misc dot: str = "" +palette: str = "" exceptions: list[str] = ["font_family", "font_weight", "span"]