diff --git a/config/fabric/modules/launcher/app.py b/config/fabric/modules/launcher/app.py index 02c110b9..aafeda84 100644 --- a/config/fabric/modules/launcher/app.py +++ b/config/fabric/modules/launcher/app.py @@ -34,7 +34,7 @@ def handle_application_search(launcher, query: str): def bake_favorite_slot(launcher, app, **kwargs) -> Button: return Button( child=Image(pixbuf=app.get_icon_pixbuf(), size=40), - style="background-color: transparent; border-radius: 10px; padding: 10px;", + name="fav-item", tooltip_text=app.description, on_clicked=lambda *_: (app.launch(), launcher.set_visible(False)), **kwargs, diff --git a/config/fabric/modules/launcher/control.py b/config/fabric/modules/launcher/control.py deleted file mode 100644 index aca2134d..00000000 --- a/config/fabric/modules/launcher/control.py +++ /dev/null @@ -1,138 +0,0 @@ -# desktop_buttons.py - -import subprocess -from fabric.widgets.button import Button -from fabric.widgets.box import Box -from fabric.widgets.label import Label -from fabric.utils import exec_shell_command -from loguru import logger - - -class DesktopButtonManager: - def __init__(self, emoji_viewport): - self.emoji_viewport = emoji_viewport - - def show_desktop_buttons(self): - """Display buttons for desktop controls like Wi-Fi, Bluetooth, Dark Mode, etc.""" - self.emoji_viewport.children = [] - row = Box(orientation="h", spacing=10) - desktop_controls = [ - { - "name": "Wi-Fi", - "icon": ("󰤨", "󰤭"), - "toggle": self.toggle_wifi, - "state": self.check_wifi_state, - }, - { - "name": "Bluetooth", - "icon": ("󰂯", "󰂲"), - "toggle": self.toggle_bluetooth, - "state": self.check_bluetooth_state, - }, - { - "name": "Dark Mode", - "icon": ("󱎖", "󱎖"), - "toggle": self.toggle_dark_mode, - "state": self.check_dark_mode_state, - }, - { - "name": "Idle", - "icon": ("󱑁", "󱑁"), - "toggle": self.toggle_idle_mode, - "state": lambda: False, # Modify as needed - }, - { - "name": "Do Not Disturb", - "icon": ("󰂚", "󰂛"), - "toggle": self.toggle_dnd, - "state": None, - }, - ] - - for i, control in enumerate(desktop_controls): - if control["state"] and callable(control["state"]): - current_state = control["state"]() - else: - current_state = False - - icon = control["icon"][0] if current_state else control["icon"][1] - button = Button( - child=Box( - orientation="h", - spacing=20, - children=[ - Label( - label=icon, - name="icon-label", - style="font-size:32px; margin:0 12px 0 0; padding:12px;", - ), - ], - ), - on_clicked=control["toggle"], - name="db-item", - tooltip_text=f"{control['name']} is {'on' if current_state else 'off'}", - ) - row.add(button) - if (i + 1) % 8 == 0: - self.emoji_viewport.add(row) - row = Box( - orientation="h", spacing=10 - ) # New row for next set of buttons - - # Add remaining buttons in last row - if len(desktop_controls) % 8 != 0: - self.emoji_viewport.add(row) - - def toggle_wifi(self, *_): - state = self.check_wifi_state() - command = "nmcli radio wifi on" if not state else "nmcli radio wifi off" - exec_shell_command(command) - logger.info("Toggled Wi-Fi.") - - def check_wifi_state(self): - result = subprocess.run( - "nmcli radio wifi", shell=True, capture_output=True, text=True - ) - return "enabled" in result.stdout - - def toggle_bluetooth(self, *_): - state = self.check_bluetooth_state() - command = "bluetoothctl power on" if not state else "bluetoothctl power off" - exec_shell_command(command) - logger.info("Toggled Bluetooth.") - - def check_bluetooth_state(self): - result = exec_shell_command("bluetoothctl show") - return "Powered: yes" in result - - def toggle_dark_mode(self, *_): - command = os.path.expanduser("~/fabric/assets/scripts/dark-theme.sh --toggle") - exec_shell_command(command) - logger.info("Toggled Dark Mode.") - - def check_dark_mode_state(self): - result = exec_shell_command( - "gsettings get org.gnome.desktop.interface color-scheme" - ) - current_mode = result.strip().replace("'", "") - return current_mode == "prefer-dark" - - def toggle_idle_mode(self, *_): - # Add logic for idle mode toggle if needed - logger.info("Toggled Idle Mode.") - - def toggle_dnd(self, *_): - current_state = self.check_dnd_state() - command = ( - "gsettings set org.gnome.desktop.notifications show-banners true" - if current_state - else "gsettings set org.gnome.desktop.notifications show-banners false" - ) - exec_shell_command(command) - logger.info("Toggled Do Not Disturb.") - - def check_dnd_state(self): - result = exec_shell_command( - "gsettings get org.gnome.desktop.notifications show-banners" - ) - return result.strip() == "false" diff --git a/config/fabric/modules/launcher/emoji_service.py b/config/fabric/modules/launcher/emoji_service.py deleted file mode 100644 index 3b5f19b0..00000000 --- a/config/fabric/modules/launcher/emoji_service.py +++ /dev/null @@ -1,55 +0,0 @@ -import json -import os -from loguru import logger -from fabric.utils import exec_shell_command_async -import subprocess - - -class EmojiItem: - def __init__(self, str: str, name: str, slug: str, group: str): - self.str = str - self.name = name - self.slug = slug - self.group = group - - -class EmojiService: - def __init__(self): - self.emoji = None - self.load_emojis() - - def load_emojis(self): - try: - # Construct the path using os.path.expanduser to handle the '~' correctly - emoji_path = os.path.expanduser("~/fabric/assets/emoji.json") - with open(emoji_path, "r") as f: - data = json.load(f) - self.emoji = [ - EmojiItem(str, item["name"], item["slug"], item["group"]) - for str, item in data.items() - ] - except Exception as e: - logger.error(f"Failed to load emoji data: {e}") - self.emoji = [] - - def get_emojis(self): - return self.emoji - - def query(self, filter: str): - if self.emoji is None: - return [] - return [ - e - for e in self.emoji - if filter in e.name or filter in e.slug or filter in e.group - ][:44] - - def copy(self, emoji_item: EmojiItem): - try: - # Use subprocess to run the wl-copy command to copy emoji - subprocess.run(["wl-copy"], input=emoji_item.str.encode(), check=True) - except Exception as e: - logger.error(f"Failed to copy emoji: {e}") - - -emoji_service = EmojiService() diff --git a/config/fabric/modules/launcher/inhibit.py b/config/fabric/modules/launcher/inhibit.py deleted file mode 100644 index d999a41a..00000000 --- a/config/fabric/modules/launcher/inhibit.py +++ /dev/null @@ -1,43 +0,0 @@ -import subprocess -import re - - -class Inhibit: - def __init__(self): - self._id = None - - @property - def is_inhibit(self): - """Check if inhibition is active.""" - return self._id is not None - - def _inhibit(self, command, data): - """Send a command to the DBus service to inhibit or un-inhibit.""" - dbus_command = ( - f"dbus-send --print-reply --dest=org.freedesktop.ScreenSaver " - f"/org/freedesktop/ScreenSaver org.freedesktop.ScreenSaver.{command} {data}" - ) - output = subprocess.run( - dbus_command, shell=True, capture_output=True, text=True - ) - - if command == "Inhibit": - match = re.search(r"uint32\s+(\d+)", output.stdout) - return int(match.group(1)) if match else None - return None - - def toggle(self): - """Toggle the inhibition state.""" - if self._id is None: - self._id = self._inhibit("Inhibit", "string:'ags' string:'Manual pause'") - else: - self._id = self._inhibit("UnInhibit", f"uint32:{self._id}") - - # Notify that the state has changed - self.changed("is-inhibit") - - def changed(self, property_name): - """Notify listeners that a property has changed.""" - print( - f"Property '{property_name}' changed. Inhibition is now {'active' if self.is_inhibit else 'inactive'}." - ) diff --git a/config/fabric/modules/launcher/main.css b/config/fabric/modules/launcher/main.css deleted file mode 100644 index 6d5b11c3..00000000 --- a/config/fabric/modules/launcher/main.css +++ /dev/null @@ -1,450 +0,0 @@ - -* { - all: unset; - color: @foreground; - font-size: 16px; - font-family: "Product Sans", Roboto, "Font Awesome 6 Free", Helvetica, Arial, - sans-serif; -} - -#bar { - background-color: @surface; - padding: 3px; -} -#bar label { - font-weight: bold; -} - -#modules_left, -#modules_center, -#modules_right { - padding-top: 6px; - padding-bottom: 6px; - margin-left: 12px; - margin-right: 12px; -} - -#workspaces { - border-radius: 16px; - font-weight: bold; - font-style: normal; - color: @onSurface; - background: @surfaceContainer; - padding-left: 4px; - padding-right: 4px; -} - -#workspaces > button { - padding: 0px 5px; - margin: 4px 0px; - margin-right: 3px; - border-radius: 100px; - min-width: 20px; - border: 0px; -} - - -#workspaces > button:last-child { - margin-right: 0px; -} - -#workspaces > button label { - color: @onSurface; - font-weight: bold; -} - -#workspaces > button:hover { - color: @onSurface; - background-color: mix(@onSurface, @surface, 0.85); -} - -#workspaces > button.active { - background: @secondaryContainer; -} - -#workspaces > button.active label { - color: @onSecondaryContainer; -} - -#workspaces > button.empty { - color: @onSurfaceVariant; - opacity: 0.6; -} - -#datetime { - background-color: @surfaceContainer; - border-radius: 16px; - padding: 2px 10px 0px 10px; -} - -#kb_layout { - font-size: 12px; -} - -/* system tray */ -#tray { - background-color: @surfaceContainer; - border-radius: 100px; - padding: 2px 10px 0px 10px; -} - -#tray > button { - margin: 0px; - padding: 0px; -} - -#tray image { - color: @onSurface; -} - -/* menu and menu items (written for the system tray) */ -menu { - border-radius: 10px; - background-color: @surfaceContainer; -} - -menu > menuitem { - border-radius: 0px; - padding: 6px; - margin-left: 2px; - margin-right: 2px; - color: @onSurface; -} - -menu > menuitem:first-child { - margin-top: 1px; - border-radius: 8px 8px 0px 0px; -} - -menu > menuitem:last-child { - margin-bottom: 1px; - border-radius: 0px 0px 8px 8px; -} - -menu > menuitem:hover { - background-color: mix(@onSurface, @surface, 0.85); -} - -tooltip { - background-color: @surfaceContainer; - border-radius: 11px; - outline: none; - border: none; - box-shadow: none; -} - -tooltip label { - color: @onSurface; - outline: none; - border: none; - box-shadow: none; - font-weight: normal; -} - -#logo { - background-color: @secondaryContainer; - color: @onSecondaryContainer; - border-radius: 100px; - min-width: 38px; - padding: 0px; -} -#logo label, -#logo .icon, -#logo image { - color: @onSecondaryContainer; - font-weight: 400; - margin: 0px 3px 0px 0px; -} - -#logo:hover { - background-color: mix(@secondaryContainer, @onSecondaryContainer, 0.05); - box-shadow: 00px 3px 3px -2px rgba(0, 0, 0, 0.2); -} - -#applets { - background-color: @surfaceContainer; - border-radius: 100px; - padding: 2px 10px 2px 10px; - margin: 0px; -} - -#applets .icon { - color: @onSurface; - font-weight: 600; -} - -#applets > button { - color: @onSurface; - margin: 0px; - padding: 0px; -} - -#battery { - background-color: @surfaceContainer; - border-radius: 100px; - padding: 2px 10px 2px 10px; -} - -#battery label { - color: @onSurface; - font-size: 16px; - font-weight: 300; -} - -#battery .icon { - color: @onSurface; -} - -#battery.critical { - background-color: @error; -} - -#battery.critical label, -#battery.critical .icon { - color: @onError; -} - -#power-event { - transition: all 0.1s ease; - background-color: @surfaceContainer; - border-radius: 999px; - padding: 7px; -} - - -#power-shutdown > *, -#power-reboot > *, -#power-logout > *, -#power-suspend > *, -#power-lock > *{ - color: @foreground; - padding:4px; - margin: 4px; - border-radius: 999px; -} - -#power-shutdown:hover > *, #power-shutdown:focus > *, -#power-reboot:hover > *, #power-reboot:focus > *, -#power-logout:hover > *, #power-logout:focus > *, -#power-suspend:hover > *, #power-suspend:focus > *, -#power-lock:hover > *, #power-lock:focus > *{ - color: @onSurface; - background-color: mix(@onSurface, @surface, 0.85); -} - -#shutdown-confirm > *, #reboot-confirm > *, #logout-confirm > *, #suspend-confirm > * { - color: @background; - font-size: 20px; - font-weight: normal; - padding: 4px; - margin: 4px; - border-radius: 999px; - border-radius: 999px; -} - -#shutdown-confirm:hover > *, #reboot-confirm:hover > *, #logout-confirm:hover > *, #suspend-confirm:hover > * { - color: @onSurface; - background-color: mix(@onSurface, @surface, 0.85); -} - -#confirm-box { - background-color: @surfaceContainer; - margin: 3px; - border-radius: 999px; -} - -#accept, #cancel { - color: @foreground; - padding: 2px; - margin: 4px; - border-radius: 999px; -} - -#accept:hover, #cancel:hover { - color: @onSurface; - background-color: mix(@onSurface, @surface, 0.85); -} - - -#launcher { - margin: 18px; - border: 1px solid @outlineVariant; - background-color: @surface; - border-radius: 24px; - padding: 18px; -} - -#launcher button { - border-radius: 11px; - background-color: transparent; - background-image: none; - box-shadow: none; - padding: 7px; -} - - -#launcher button:focus { - box-shadow: inset 0 0 0 1px @primary; - background-color: @background; - color: @foreground; -} - -#launcher button:hover { - box-shadow: inset 0 0 0 1px @background; - background-color: @background; -} - -#launcher entry { - transition: all 0.1s ease; - border-radius: 11px; - color: @foreground; - background-color:@surfaceContainer; - box-shadow: inset 0 0 0 @background; - padding: 10px; - margin: 12px; -} - -#launcher entry:focus { - box-shadow: inset 0 0 0 1px @primary; - background-color: @background; -} - -#launcher entry:hover { - box-shadow: inset 0 0 0 1px @background; - background-color: @background; -} - -#launcher entry selection { - color: @outline; - background-color: transparent; -} - -#launcher button#app-item { - border-radius: 11px; - color: @foreground; - background-color: transparent; - background-image: none; - box-shadow: none; - transition: 200ms; - padding: 7pt; -} - -#launcher button#app-item:hover #title, -#launcher button#app-item:focus #title { - color: @primary; -} - -#launcher button#app-item:hover #description, -#launcher button#app-item:focus #description { - color: @inversePrimary; -} - -#launcher button#app-item:hover image, -#launcher button#app-item:focus image { - -gtk-icon-shadow: 2px 2px @primary; -} - -#launcher button#app-item:active { - background-color: @primaryContainer; - border-radius: 11px; - box-shadow: inset 0 0 0 1px rgba(158, 142, 130, 0.04); -} - -#launcher button#app-item:active #title { - color: @foreground; -} - -#launcher button#emoji-item { - border-radius: 11px; - background-color: transparent; - background-image: none; - box-shadow: none; - padding: 0px; -} - -#launcher button#emoji-item:disabled { - color: mix(@onSurface, transparent, 0.38); -} - -#launcher button#emoji-item label { - font-size: 27px; -} - -#launcher button#emoji-item:hover, -#launcher button#emoji-item:focus { - text-shadow: 2px 2px 2px @primary; -} - -#launcher button#cliphist-item { - border-radius: 11px; - background-color: transparent; - background-image: none; - box-shadow: none; -} - -window#launcher button#cliphist-item:disabled { - color: mix(@onSurface, transparent, 0.38); -} - -#launcher button#cliphist-item:hover, -#launcher button#cliphist-item:focus { - text-shadow: 2px 2px 2px @primary; -} - -#launcher button#sh-item { - border-radius: 11px; - background-color: transparent; - background-image: none; - box-shadow: none; -} - -#launcher button#sh-item:disabled { - color: mix(@onSurface, transparent, 0.38); -} - -#launcher button#sh-item:hover, -#launcher button#sh-item:focus { - text-shadow: 2pt 2pt 2pt @primary; -} - -#launcher button#help-item { - border-radius: 11px; - background-color: transparent; - background-image: none; - box-shadow: none; -} - -#launcher button#help-item:hover label, -#launcher button#help-item:focus label{ - text-shadow: 2px 2px 2px @primary; -} - -#launcher button#wall-item { - border-radius: 11px; - background-color: transparent; - background-image: none; - box-shadow: none; -} - -#launcher button#wall-item:disabled { - color: mix(@onSurface, transparent, 0.38); -} - -#launcher button#wall-item:hover, -#launcher button#wall-item:focus { - text-shadow: 10pt 10pt 10pt @primary; - background-color: mix(@onSurface, @surface, 0.92); -} - -#launcher button#db-item { - border-radius: 11px; - background-color: transparent; - background-image: none; - box-shadow: none; -} - -#launcher button#db-item:hover label, -#launcher button#db-item:focus label{ - text-shadow: 4px 4px 4px @primary; -/* margin: 12px;*/ -} \ No newline at end of file diff --git a/config/fabric/modules/launcher/sh.py b/config/fabric/modules/launcher/sh.py deleted file mode 100644 index 369c9044..00000000 --- a/config/fabric/modules/launcher/sh.py +++ /dev/null @@ -1,56 +0,0 @@ -import os -import subprocess - -CACHE_DIR = os.getenv("XDG_CACHE_HOME", os.path.join(os.path.expanduser("~"), ".cache")) -BINS = os.path.join(CACHE_DIR, "binaries") - - -class Sh: - def __init__(self): - self.reload() # Load binaries on initialization - - def ls(self, path): - if not os.path.exists(path): - return [] - try: - return ( - subprocess.check_output(f"ls {path}", shell=True, text=True) - .strip() - .splitlines() - ) - except subprocess.CalledProcessError: - return [] - - def reload(self): - """Reload the binaries from the PATH environment variable.""" - paths = os.getenv("PATH", "").split(":") - bins = [] - - for path in paths: - bins.extend(self.ls(path)) - - # Remove duplicates and save to file - unique_bins = set(bins) - with open(BINS, "w") as f: - f.write("\n".join(unique_bins)) - - @staticmethod - def query(filter_str): - """Filter binaries using fzf and return the results.""" - try: - result = subprocess.check_output( - f"cat {BINS} | fzf -f {filter_str} | head -n 16", shell=True, text=True - ) - return list(dict.fromkeys(result.splitlines())) # Deduplicate results - except subprocess.CalledProcessError: - return [] - - @staticmethod - def run(args: str): - """Execute a command and print its output.""" - try: - output = subprocess.check_output(args, shell=True, text=True) - print(f":sh {args.strip()}:") - print(output) - except subprocess.CalledProcessError as err: - print(f"Error running command: {err}") diff --git a/config/fabric/modules/launcher/shell.py b/config/fabric/modules/launcher/shell.py index 19a59941..0d8afc89 100644 --- a/config/fabric/modules/launcher/shell.py +++ b/config/fabric/modules/launcher/shell.py @@ -39,4 +39,4 @@ class ShellCommandManager: Sh.run(cmd) # Run the shell command self.launcher.set_visible(False) # Close the launcher after execution except Exception as e: - print(f"Error executing command: {e}") + logger.error(f"Error executing command: {e}") diff --git a/config/fabric/modules/launcher/wallpaper.py b/config/fabric/modules/launcher/wallpaper.py index 55277845..bb96e7b2 100644 --- a/config/fabric/modules/launcher/wallpaper.py +++ b/config/fabric/modules/launcher/wallpaper.py @@ -88,7 +88,7 @@ class WallpaperManager: ) logger.info(f"Wallpaper applied: {wallpaper_path}") except Exception as e: - logger.info(f"Error applying wallpaper: {e}") + logger.error(f"Error applying wallpaper: {e}") def apply_wallpaper_random(self): script_path = os.path.expanduser("~/dotfiles/hypr/scripts/wallpaper.py") @@ -99,4 +99,4 @@ class WallpaperManager: ) logger.info("Random wallpaper applied.") except Exception as e: - logger.info(f"Error applying random wallpaper: {e}") + logger.error(f"Error applying random wallpaper: {e}") diff --git a/config/fabric/style/main.css b/config/fabric/style/main.css index 2394d07c..90f8b76d 100644 --- a/config/fabric/style/main.css +++ b/config/fabric/style/main.css @@ -354,6 +354,22 @@ tooltip label { color: @foreground; } +#launcher button#fav-item{ + border-radius: 10px; + padding: 10px; +} + +#launcher button#fav-item:hover image, +#launcher button#fav-item:focus image { + -gtk-icon-shadow: 2px 2px @primary; +} + +#launcher button#fav-item:active { + background-color: transparent; + border-radius: 11px; + box-shadow: inset 0 0 0 1px rgba(158, 142, 130, 0.04); +} + #launcher button#emoji-item { border-radius: 11px; background-color: transparent;