materialicon

This commit is contained in:
sankalp committed 2024-11-02 11:12:18 +05:45
1 parent cf3801814c
commit 9bc0630a1a
29 files changed
+324 -536

No files matched your search

+18
View File
@@ -0,0 +1,18 @@
# material_icon.py
from fabric.widgets.label import Label
def MaterialIcon(icon_name: str, size: str = "24px", props: dict = None):
label_props = {
"label": icon_name, # Directly use the provided icon name
"name": "material_icon",
"style": f"font-size: {size}; ", # 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)
+25 -18
View File
@@ -1,21 +1,23 @@
from fabric.hyprland.widgets import Language, WorkspaceButton, Workspaces
from fabric.hyprland.widgets import Language
from fabric.system_tray.widgets import SystemTray
from fabric.utils import FormattedString, bulk_replace
from fabric.utils import FormattedString, bulk_replace, exec_shell_command
from fabric.widgets.box import Box
from fabric.widgets.button import Button
from fabric.widgets.centerbox import CenterBox
from fabric.widgets.datetime import DateTime
from fabric.widgets.wayland import WaylandWindow as Window
from modules.bar.widgets import (
BatteryLabel,
Bluetooth,
HardwareUsage,
MicrophoneIndicator,
Network,
PowerProfile,
TaskBar,
VolumeIndicator,
Wifi,
workspace,
)
from .glance import OpenAppsBar
from icon import MaterialIcon
class Bar(Window):
@@ -29,11 +31,6 @@ class Bar(Window):
visible=False,
all_visible=False,
)
self.workspaces = Workspaces(
name="workspaces",
spacing=4,
buttons=[WorkspaceButton(id=i, label=str(i)) for i in range(1, 11)],
)
self.language = Language(
formatter=FormattedString(
"{replace_lang(language)}",
@@ -46,17 +43,28 @@ class Bar(Window):
),
)
self.date_time = DateTime(formatters=["%-I:%M 󰧞 %a %d %b"], name="datetime")
self.system_tray = SystemTray(spacing=4, icon_size=18)
self.system_tray = SystemTray(name="tray", spacing=4, icon_size=18)
self.TaskBar = TaskBar(icon_size=18)
self.volume = VolumeIndicator()
self.wifi = Wifi()
self.network = Network()
self.bluetooth = Bluetooth()
self.battery = BatteryLabel(name="battery")
self.microphone = MicrophoneIndicator()
self.power = PowerProfile()
self.open_apps_bar = OpenAppsBar()
self.workspaces = Button(
child=workspace,
name="workspaces",
on_clicked=lambda _: exec_shell_command("wofi --show drun --fork"),
)
self.logo = Button(
child=MaterialIcon("search", size="16px"),
name="logo",
on_clicked=lambda _: exec_shell_command(
"/home/sankalp/fabric/fabric_send 'launcher.toggle()'"
),
)
self.info = HardwareUsage()
self.applets = Box(
name="applets",
spacing=4,
@@ -64,10 +72,9 @@ class Bar(Window):
self.language,
self.power,
self.bluetooth,
self.wifi,
self.network,
self.volume,
self.microphone,
# self.battery,
],
)
self.children = CenterBox(
@@ -76,14 +83,14 @@ class Bar(Window):
name="start-container",
spacing=8,
orientation="h",
children=self.TaskBar,
children=[self.logo, self.workspaces, self.info],
),
center_children=Box(
name="center-container",
spacing=8,
orientation="h",
children=[
self.workspaces,
self.TaskBar,
],
),
end_children=Box(
-54
View File
@@ -1,54 +0,0 @@
import gi
from fabric.widgets.box import Box
from fabric.widgets.button import Button
from fabric.widgets.image import Image
from .icon_resolver import IconResolver
gi.require_version("Glace", "0.1")
from gi.repository import Glace
class OpenAppsBar(Box):
def __init__(self):
self.client_buttons = {}
super().__init__(spacing=10)
self.icon_resolver = IconResolver()
self._manager = Glace.Manager()
self._manager.connect("client-added", self.on_client_added)
def on_active_window(self, _, event):
print(event.data)
print(self.client_buttons)
# client_buttons[]
def on_client_added(self, _, client: Glace.Client):
client_image = Image()
client_button = Button(
name="panel-button",
image=client_image,
on_button_press_event=lambda *_: client.activate(),
)
self.client_buttons[client.get_id()] = client_button
client.connect(
"notify::app-id",
lambda *_: [
client_image.set_from_pixbuf(
self.icon_resolver.get_icon_pixbuf(client.get_app_id(), 24)
),
print(client.get_id()),
],
)
client.connect(
"notify::activated",
lambda *_: (
client_button.add_style_class("activated")
if client.get_activated()
else client_button.remove_style_class("activated")
),
)
client.bind_property("title", client_button, "tooltip-text", 0)
client.connect("close", lambda *_: self.remove(client_button))
self.add(client_button)
-100
View File
@@ -1,100 +0,0 @@
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()) + "/fabric"
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-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
)
@@ -1,7 +1,9 @@
from .battery import *
from .bluetooth import *
from .info import *
from .microphone import *
from .network import *
from .powerprofile import *
from .taskbar import *
from .volume import *
from .wifi import *
from .workspace import *
+19 -25
View File
@@ -2,25 +2,24 @@ import psutil
from fabric.utils import invoke_repeater
from fabric.widgets.box import Box
from fabric.widgets.label import Label
from icon import MaterialIcon
class BatteryLabel(Box):
ICONS_CHARGING = [
"battery_charging_20", "battery_charging_20", "battery_charging_20", "battery_charging_30", "battery_charging_30",
"battery_charging_50", "battery_charging_60", "battery_charging_80", "battery_charging_80",
"battery_charging_90", "battery_charging_full"
]
ICONS_NOT_CHARGING = [
"battery_alret", "battery_1_bar", "battery_1_bar", "battery_2_bar", "battery_2_bar",
"battery_3_bar", "battery_4_bar", "battery_4_bar", "battery_5_bar",
"battery_6_bar", "battery_full"
]
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.battery_icon = Label(
label="󰁹",
name="symbol",
# style="font-size: 16px; margin-right: 4px;",
)
self.battery_label = Label(
label="N/A",
style="font-size: 16px; margin-left: 4px;",
)
invoke_repeater(1000, self.update_battery_status, initial_call=True)
self.children = self.battery_icon, self.battery_label
def update_battery_status(self):
battery = psutil.sensors_battery()
if battery is None:
@@ -28,22 +27,17 @@ class BatteryLabel(Box):
return
battery_percent = round(battery.percent) if battery else 0.0
self.battery_label.set_label(f"{(battery_percent or 'N/A')}%")
battery_label = Label(label=f"{battery_percent}%")
is_charging = battery.power_plugged if battery else False
icons = self.ICONS_CHARGING if is_charging else self.ICONS_NOT_CHARGING
icons = (
["󰢟", "󰂆", "󰂇", "󰂈", "󰢝", "󰂉", "󰢞", "󰂊", "󰂋", "󰂅"]
if is_charging
else ["󱃍", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"]
)
index = min(max(battery_percent // 10, 0), 9)
index = min(max(battery_percent // 10, 0), 10)
battery_icon = MaterialIcon(icons[index], size="16px")
self.battery_icon.set_label(icons[index])
self.children = (battery_icon, battery_label)
if battery_percent == 100:
self.hide()
else:
self.show()
self.show() if battery_percent < 100 else self.hide()
return True
+20 -13
View File
@@ -1,28 +1,35 @@
from fabric.bluetooth import BluetoothClient
from fabric.widgets.box import Box
from fabric.widgets.label import Label
from icon import MaterialIcon # Import your MaterialIcon function
class Bluetooth(Box):
ICON_ENABLED = "bluetooth" # Use the appropriate Material icon name
ICON_DISABLED = "bluetooth_disabled" # Use the appropriate Material icon name
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.bluetooth_client = BluetoothClient()
self.bluetooth_icon = Label(
label="󰂲",
# name="symbol",
style="font-size: 18px;",
)
self.bluetooth_icon = None
self.bluetooth_client.connect("changed", self.update_bluetooth_status)
self.update_bluetooth_status()
self.add(self.bluetooth_icon)
def update_bluetooth_status(self, *args):
if self.bluetooth_client.enabled:
self.bluetooth_icon.set_label("󰂯")
else:
self.bluetooth_icon.set_label("󰂲")
icon_label = (
self.ICON_ENABLED if self.bluetooth_client.enabled else self.ICON_DISABLED
)
new_icon = MaterialIcon(icon_label, size="16px")
if self.bluetooth_icon:
self.remove(self.bluetooth_icon)
self.bluetooth_icon = new_icon
self.add(self.bluetooth_icon)
def on_destroy(self):
"""Disconnect the Bluetooth client when the widget is destroyed."""
self.bluetooth_client.disconnect("changed", self.update_bluetooth_status)
-35
View File
@@ -1,35 +0,0 @@
from fabric.widgets.box import Box
from fabric.widgets.label import Label
from services.inhibit import Inhibit # Importing Inhibit from the services module
class IdleIndicator(Box):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.inhibit_service = Inhibit() # Use the imported Inhibit service
self.idle_icon = Label(
label="󰅐", # Icon symbol for idle/inhibit indication
name="symbol",
)
# Add the idle icon as a child widget
self.children = (self.idle_icon,)
# Check the initial inhibition state and update the icon visibility
self.update_idle_status()
def update_idle_status(self):
"""Update the idle status based on inhibition state."""
print(
f"Inhibition state: {self.inhibit_service.is_inhibit}"
) # Debugging output
if self.inhibit_service.is_inhibit:
self.idle_icon.set_visible(True) # Show the idle icon when inhibited
else:
self.idle_icon.set_visible(False) # Hide the idle icon when not inhibited
def toggle_idle(self):
"""Toggle the idle state by interacting with the inhibit service."""
self.inhibit_service.toggle() # Toggle the inhibition state
self.update_idle_status() # Refresh the icon visibility
+59
View File
@@ -0,0 +1,59 @@
import psutil
from fabric.utils import invoke_repeater
from fabric.widgets.box import Box
from fabric.widgets.button import Button
from fabric.widgets.label import Label
from fabric.widgets.overlay import Overlay
from fabric.widgets.circularprogressbar import CircularProgressBar
from icon import MaterialIcon # Import your updated MaterialIcon function
class HardwareUsage(Button):
HARDWARE_ITEMS = [
("CPU", "settings_motion_mode"), # Pass the Material icon name directly
("Swap", "swap_horiz"),
("RAM", "memory"),
]
def __init__(self):
super().__init__(child=self._create_content())
invoke_repeater(1000, self._update_labels)
def _create_content(self):
self.box = Box(orientation="h", name="tray")
self.progress_bars = {}
self.labels = {}
self.icons = {}
for hardware, icon_name in self.HARDWARE_ITEMS:
self.progress_bars[hardware] = self._create_progress_bar()
self.labels[hardware] = Label(style="font-size:14px; margin: 4px;")
self.icons[hardware] = MaterialIcon(icon_name, size="16px")
self._pack_items(hardware)
return self.box
def _create_progress_bar(self):
return CircularProgressBar(name="progress", pie=True, size=30)
def _pack_items(self, hardware):
overlay = Overlay(child=self.progress_bars[hardware], overlays=self.icons[hardware])
self.box.pack_start(overlay, False, False, 0)
self.box.pack_start(self.labels[hardware], False, False, 0)
def _update_labels(self):
usages = self._get_hardware_usages()
self._update_progress_bars(usages)
def _get_hardware_usages(self):
return {
"CPU": round(psutil.cpu_percent()),
"RAM": round(psutil.virtual_memory().percent),
"Swap": round(psutil.swap_memory().percent),
}
def _update_progress_bars(self, usages):
for hardware, usage in usages.items():
self.progress_bars[hardware].value = usage / 100
self.labels[hardware].set_label(f"{usage}%")
self.progress_bars[hardware].set_tooltip_text(f"{hardware} Usage: {usage}%")
+17 -15
View File
@@ -1,33 +1,35 @@
from fabric.audio.service import Audio
from fabric.widgets.box import Box
from fabric.widgets.label import Label
from icon import MaterialIcon # Import your MaterialIcon function
class MicrophoneIndicator(Box):
def __init__(self, **kwargs):
ICON_MUTED = "mic_off"
ICON_UNMUTED = "mic"
def __init__(self, **kwargs):
super().__init__(**kwargs)
audio_service = Audio()
self.audio_service = audio_service
self.microphone_icon = Label(
label="󰍭",
name="symbol",
# style="font-size: 16px; margin-left:4px;",
)
self.audio_service = Audio()
self.microphone_icon = self.create_microphone_icon()
self.audio_service.connect("microphone_changed", self.update_microphone_status)
self.update_microphone_status()
self.children = (self.microphone_icon,)
def create_microphone_icon(self):
return MaterialIcon(self.ICON_MUTED, size="16px")
def update_microphone_status(self, *args):
current_microphone = self.audio_service.microphone
if current_microphone:
is_muted = current_microphone.muted
icon_name = self.ICON_MUTED if is_muted else self.ICON_UNMUTED
if is_muted:
self.microphone_icon.set_visible(True)
else:
self.microphone_icon.set_visible(False)
self.microphone_icon.set_label(icon_name)
self.microphone_icon.set_visible(is_muted)
else:
self.microphone_icon.set_visible(False)
return True
@@ -0,0 +1,69 @@
import psutil
from fabric.utils import invoke_repeater
from fabric.widgets.box import Box
from icon import MaterialIcon
import subprocess
class Network(Box):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.update_interval = 5000
self.last_status = None
invoke_repeater(self.update_interval, self.update_network_status, initial_call=True)
def update_network_status(self):
current_status = self.get_network_status()
if current_status != self.last_status:
self.update_icon(current_status)
self.last_status = current_status
return True
def update_icon(self, current_status):
self.icon_label = MaterialIcon(current_status, size="16px")
self.children = (self.icon_label,)
def get_network_status(self):
if self.is_ethernet_connected():
return "network_ethernet"
if self.is_wifi_connected():
return self.get_wifi_strength_icon()
return "signal_wifi_off"
def get_wifi_strength_icon(self):
wifi_strength = self.check_wifi_strength()
return self.wifi_signal_icon(wifi_strength)
def wifi_signal_icon(self, strength):
if strength is None or strength <= -100:
return "signal_wifi_0_bar"
if strength > -50:
return "signal_wifi_4_bar"
if strength > -60:
return "network_wifi_3_bar"
if strength > -70:
return "network_wifi_2_bar"
return "network_wifi_1_bar"
def check_wifi_strength(self):
try:
result = subprocess.run(['iwconfig'], capture_output=True, text=True)
for line in result.stdout.splitlines():
if 'Signal level' in line:
signal_level = line.split('Signal level=')[1].split(' ')[0]
return int(signal_level.strip().replace('dBm', ''))
return None
except Exception:
return None
def is_wifi_connected(self):
return any(self._is_interface_up(interface, ["wlan", "wifi"]) for interface in psutil.net_if_addrs())
def is_ethernet_connected(self):
return any(self._is_interface_up(interface, ["eth"]) for interface in psutil.net_if_addrs())
def _is_interface_up(self, interface, keywords):
if any(substring in interface.lower() for substring in keywords):
return psutil.net_if_stats().get(interface, {}).isup
return False
@@ -1,27 +1,21 @@
from fabric.utils import exec_shell_command, invoke_repeater
from fabric.widgets.box import Box
from fabric.widgets.label import Label
from icon import MaterialIcon
PROFILE_ICONS = {
"power-saver": "󰡳",
"power-saver": "data_saver_on",
"balanced": None,
"performance": "󰡴",
"performance": "mode_heat",
}
class PowerProfile(Box):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.profile_icon = Label(
label="󰡳",
name="symbol",
# style="font-size: 16px; margin-right: 4px;",
)
self.profile_icon = None
invoke_repeater(1000, self.update_power_profile, initial_call=True)
self.children = (self.profile_icon,)
def update_power_profile(self):
profile = self.get_power_profile()
self.update_icon(profile)
@@ -29,12 +23,22 @@ class PowerProfile(Box):
def get_power_profile(self):
result = exec_shell_command("powerprofilesctl get")
return result.strip() if result else "power-saver"
return result.strip() or "power-saver"
def update_icon(self, profile):
if profile in ["power-saver", "performance"]:
icon = PROFILE_ICONS[profile]
self.profile_icon.set_label(icon)
self.profile_icon.show()
icon_name = PROFILE_ICONS.get(profile)
new_icon = MaterialIcon(icon_name, size="16px") if icon_name else None
if self.profile_icon:
self.remove(self.profile_icon)
if new_icon:
self.profile_icon = new_icon
self.add(self.profile_icon)
else:
self.profile_icon.hide()
if self.profile_icon:
self.profile_icon.hide()
self.profile_icon = None
@@ -1,180 +0,0 @@
import glob
import json
import subprocess
from typing import TypedDict
from fabric.hyprland.widgets import get_hyprland_connection
from fabric.widgets.box import Box
from fabric.widgets.button import Button
from fabric.widgets.image import Image
from fabric.widgets.label import Label
from gi.repository import GdkPixbuf, GLib, Gtk
class PagerClient(TypedDict):
title: str
initialClass: str
mapped: bool
hidden: bool
address: str
class TaskBar(Box):
def __init__(self, icon_size: int = 24, **kwargs):
super().__init__(orientation="h", spacing=6, name="taskbar", **kwargs)
self.connection = get_hyprland_connection()
self.icon_size = icon_size
self.icon_theme = Gtk.IconTheme.get_default()
self.set_visible(False)
if self.connection.ready:
self.render_with_delay()
else:
self.connection.connect("event::ready", lambda *_: self.render_with_delay())
for event in (
"activewindow",
"openwindow",
"closewindow",
"changefloatingmode",
):
self.connection.connect("event::" + event, lambda *_: self.render(None))
def render_with_delay(self, *_):
GLib.timeout_add(100, self.render)
def render(self, *_):
self.children = []
clients = self.fetch_clients()
active_window_address = self.get_active_window_address()
# Group clients by initialClass
grouped_clients = {}
for client in clients:
if client["mapped"] and not client["hidden"]:
window_class = client["initialClass"].lower()
if window_class not in grouped_clients:
grouped_clients[window_class] = []
grouped_clients[window_class].append(client)
if grouped_clients:
for window_class, client_group in grouped_clients.items():
# Fetch the icon for the application (one icon per group)
icon = self.bake_window_icon(window_class)
# Create a vertical box inside the button for the icon and the dots
icon_box = Box(orientation="v", spacing=0)
icon_box.set_halign(Gtk.Align.CENTER)
# Add the icon at the top
icon_box.add(icon)
# Add dot(s) directly below the icon to indicate the number of open instances
if len(client_group) > 1:
dots_box = Box(orientation="h", spacing=2) # Box to hold the dots
dots_box.set_halign(Gtk.Align.CENTER)
for _ in range(len(client_group)):
dot = Label(
label="•"
) # Each dot represents one window instance
dot.set_style(
"font-size: 7px; color: rgba(255, 255, 255, 0.6);"
) # Lighter dot color
dots_box.add(dot)
icon_box.add(dots_box)
# Create a button and add the icon_box (icon + dots) inside the button
button = Button(child=icon_box, tooltip_text=client_group[0]["title"])
# Highlight the active window
if any(
client["address"] == active_window_address
for client in client_group
):
button.set_style(
"background-color: @surfaceVariant; transition-duration: 0.3s; border-radius:100px;"
)
# Connect click event to focus the application window
button.connect(
"button-press-event", self.on_icon_click, client_group[0]["address"]
)
# Add the button to the taskbar
self.add(button)
self.set_visible(True)
self.show_all()
else:
self.set_visible(False)
def get_active_window_address(self) -> str:
# Fetch the address of the currently active window
active_window_info = json.loads(
self.connection.send_command("j/activewindow").reply.decode()
)
print(f"Active window address: {active_window_info.get('address', '')}")
return active_window_info.get("address", "")
def on_icon_click(self, widget, event, address):
command = ["hyprctl", "dispatch", "focuswindow", f"address:{address}"]
subprocess.run(command, check=True)
def fetch_clients(self) -> list[PagerClient]:
return json.loads(self.connection.send_command("j/clients").reply.decode())
def bake_window_icon(
self, window_class: str, fallback_icon: str = "image-missing"
) -> Image:
icon_name = self.get_icon_from_desktop_entry(window_class)
if icon_name:
pixbuf = self.load_icon(icon_name)
else:
pixbuf = self.load_icon(window_class, fallback_icon)
return Image(pixbuf=pixbuf, size=self.icon_size)
def get_icon_from_desktop_entry(self, window_class: str) -> str:
desktop_files = glob.glob("/usr/share/applications/*.desktop")
for desktop_file in desktop_files:
with open(desktop_file, "r") as f:
for line in f:
if line.startswith("Name="):
app_name = line.split("=", 1)[1].strip().lower()
if window_class in app_name:
for line in f:
if line.startswith("Icon="):
return line.split("=", 1)[1].strip()
return None
def load_icon(
self, icon_name: str, fallback_icon: str = "image-missing"
) -> GdkPixbuf.Pixbuf:
try:
pixbuf = self.icon_theme.load_icon(
icon_name,ecode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Active window address: 0x60d8e93ecf50
Active window address: 0x60d8e93ecf50
Active window address: 0x60d8e93ecf50
^C2024-10-22 13:47:53.414 | INFO | fabric.core.application:on_exit:316 - [Fabric] exiting...
sankalp on 53ur!tyD3m0n fabric/rework/bar via 🐍 v3.12.7 [⏱ 1m4s]✔
╰─λ
self.icon_size,
Gtk.IconLookupFlags.FORCE_SIZE,
)
except Exception:
pixbuf = self.icon_theme.load_icon(
fallback_icon,
self.icon_size,
Gtk.IconLookupFlags.FORCE_SIZE,
)
return pixbuf
+54 -36
View File
@@ -2,64 +2,82 @@ from fabric.audio.service import Audio
from fabric.utils import exec_shell_command, invoke_repeater
from fabric.widgets.box import Box
from fabric.widgets.button import Button
from icon import MaterialIcon
VOLUME_ICONS = {
"muted": "volume_off",
"low": "volume_mute",
"medium-low": "volume_down",
"medium-high": "volume_up",
"high": "volume_up",
}
class VolumeIndicator(Box):
def __init__(self, **kwargs):
super().__init__(**kwargs)
audio_service = Audio()
self.audio_service = audio_service
self.volume_icon = Button(
label="󰖁",
style="margin-left:6px; font-size:18px;",
# name="symbol",
)
# Connect mouse button events to handle clicks
self.volume_icon.connect("button-press-event", self.on_button_press)
self.audio_service = Audio()
self.volume_icon_button = self.create_volume_icon()
self.volume_icon_button.connect("button-press-event", self.on_button_press)
self.audio_service.connect("changed", self.update_volume_status)
invoke_repeater(1000, self.update_volume_status, initial_call=True)
self.children = (self.volume_icon,)
self.children = (self.volume_icon_button,)
def create_volume_icon(self):
"""Create a button with a Material icon for volume."""
icon = MaterialIcon(VOLUME_ICONS["muted"], size="16px")
button = Button(child=icon)
button.icon_widget = icon
return button
def on_button_press(self, widget, event):
if event.button == 1:
self.on_clicked()
self.toggle_mute()
elif event.button == 3:
self.on_right_clicked()
elif event.button == 2:
self.on_middle_clicked()
self.open_audio_settings()
def on_right_clicked(self):
exec_shell_command("pavucontrol")
def on_clicked(self):
def toggle_mute(self):
current_stream = self.audio_service.speaker
if current_stream:
current_stream.muted = not current_stream.muted
self.update_volume_status()
# def on_middle_clicked(self):
# exec_shell_command("pavucontrol")
def open_audio_settings(self):
exec_shell_command("pavucontrol")
def update_volume_status(self, *args):
current_stream = self.audio_service.speaker
if current_stream:
volume_level = current_stream.volume
is_muted = current_stream.muted
if is_muted:
self.volume_icon.set_label("󰖁")
else:
if volume_level == 0:
self.volume_icon.set_label("󰝟")
elif volume_level <= 33:
self.volume_icon.set_label("󰕿")
elif volume_level <= 66:
self.volume_icon.set_label("󰖀")
else:
self.volume_icon.set_label("󰕾")
self.update_icon(current_stream)
return True
def update_icon(self, stream):
"""Update the icon based on the current stream status."""
if stream.muted:
icon_name = VOLUME_ICONS["muted"]
volume_percentage = 0
tooltip_text = "Volume Muted"
else:
volume_level = stream.volume
icon_name = self.get_volume_icon(volume_level)
volume_percentage = int(volume_level)
tooltip_text = f"Volume: {volume_percentage}%"
self.volume_icon_button.icon_widget.set_label(icon_name)
self.volume_icon_button.set_tooltip_text(tooltip_text)
def get_volume_icon(self, volume_level):
"""Determine the appropriate icon based on the volume level."""
if volume_level == 0:
return VOLUME_ICONS["low"]
elif volume_level <= 33:
return VOLUME_ICONS["medium-low"]
elif volume_level <= 66:
return VOLUME_ICONS["medium-high"]
else:
return VOLUME_ICONS["high"]
-42
View File
@@ -1,42 +0,0 @@
import socket
import psutil
from fabric.utils import invoke_repeater
from fabric.widgets.box import Box
from fabric.widgets.label import Label
class Wifi(Box):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.wifi_icon = Label(
label="󰤭",
name="symbol",
# style="font-size: 16px; margin-right: 6px;",
)
invoke_repeater(1000, self.update_wifi_status, initial_call=True)
self.children = (self.wifi_icon,)
def update_wifi_status(self):
wifi_on = self.check_wifi_status()
if wifi_on:
self.wifi_icon.set_label("󰤥")
else:
self.wifi_icon.set_label("󰤭")
return True
def check_wifi_status(self):
for interface, addrs in psutil.net_if_addrs().items():
if "wlan" in interface or "wifi" in interface:
if (
interface in psutil.net_if_stats()
and psutil.net_if_stats()[interface].isup
):
for addr in addrs:
if addr.family in (socket.AF_INET, socket.AF_INET6):
return True
return False
@@ -0,0 +1,19 @@
import json
from fabric.hyprland.service import Hyprland
from fabric.widgets.label import Label
connection = Hyprland()
workspaceData = connection.send_command("j/activeworkspace").reply
activeWorkspace = json.loads(workspaceData.decode("utf-8"))["name"]
workspace = Label(label=f"Workspace {activeWorkspace}")
def on_workspace(obj, signal):
global activeWorkspace
activeWorkspace = json.loads(signal.data[0])
workspace.set_label(f"Workspace {activeWorkspace}")
connection.connect("event::workspace", on_workspace)