From 9bc0630a1a2b838b6eefbec3bea89e331bb0f438 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Sat, 2 Nov 2024 11:12:18 +0545 Subject: [PATCH] materialicon --- config/fabric/icon.py | 18 ++ config/fabric/modules/bar/bar.py | 43 +++-- config/fabric/modules/bar/glance.py | 54 ------ config/fabric/modules/bar/icon_resolver.py | 100 ---------- config/fabric/modules/bar/widgets/__init__.py | 4 +- .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 362 bytes .../__pycache__/battery.cpython-312.pyc | Bin 0 -> 2245 bytes .../__pycache__/bluetooth.cpython-312.pyc | Bin 0 -> 1977 bytes .../widgets/__pycache__/idle.cpython-312.pyc | Bin 0 -> 1866 bytes .../widgets/__pycache__/info.cpython-312.pyc | Bin 0 -> 4028 bytes .../__pycache__/material_icon.cpython-312.pyc | Bin 0 -> 664 bytes .../__pycache__/microphone.cpython-312.pyc | Bin 0 -> 2085 bytes .../__pycache__/network.cpython-312.pyc | Bin 0 -> 4900 bytes .../__pycache__/powerprofile.cpython-312.pyc | Bin 0 -> 2170 bytes .../__pycache__/taskbar.cpython-312.pyc | Bin 0 -> 7993 bytes .../__pycache__/volume.cpython-312.pyc | Bin 0 -> 4273 bytes .../widgets/__pycache__/wifi.cpython-312.pyc | Bin 0 -> 3697 bytes .../__pycache__/workspace.cpython-312.pyc | Bin 0 -> 1083 bytes config/fabric/modules/bar/widgets/battery.py | 44 ++--- .../fabric/modules/bar/widgets/bluetooth.py | 33 ++-- config/fabric/modules/bar/widgets/idle.py | 35 ---- config/fabric/modules/bar/widgets/info.py | 59 ++++++ .../fabric/modules/bar/widgets/microphone.py | 32 ++-- config/fabric/modules/bar/widgets/network.py | 69 +++++++ .../modules/bar/widgets/powerprofile.py | 38 ++-- .../fabric/modules/bar/widgets/taskbar11.py | 180 ------------------ config/fabric/modules/bar/widgets/volume.py | 90 +++++---- config/fabric/modules/bar/widgets/wifi.py | 42 ---- .../fabric/modules/bar/widgets/workspace.py | 19 ++ 29 files changed, 324 insertions(+), 536 deletions(-) create mode 100644 config/fabric/icon.py delete mode 100644 config/fabric/modules/bar/glance.py delete mode 100644 config/fabric/modules/bar/icon_resolver.py create mode 100644 config/fabric/modules/bar/widgets/__pycache__/__init__.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/battery.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/bluetooth.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/idle.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/info.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/material_icon.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/microphone.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/network.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/powerprofile.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/taskbar.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/volume.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/wifi.cpython-312.pyc create mode 100644 config/fabric/modules/bar/widgets/__pycache__/workspace.cpython-312.pyc delete mode 100644 config/fabric/modules/bar/widgets/idle.py create mode 100644 config/fabric/modules/bar/widgets/info.py create mode 100644 config/fabric/modules/bar/widgets/network.py delete mode 100644 config/fabric/modules/bar/widgets/taskbar11.py delete mode 100644 config/fabric/modules/bar/widgets/wifi.py create mode 100644 config/fabric/modules/bar/widgets/workspace.py diff --git a/config/fabric/icon.py b/config/fabric/icon.py new file mode 100644 index 00000000..881cf7a1 --- /dev/null +++ b/config/fabric/icon.py @@ -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) + diff --git a/config/fabric/modules/bar/bar.py b/config/fabric/modules/bar/bar.py index 34b27e43..80401209 100644 --- a/config/fabric/modules/bar/bar.py +++ b/config/fabric/modules/bar/bar.py @@ -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( diff --git a/config/fabric/modules/bar/glance.py b/config/fabric/modules/bar/glance.py deleted file mode 100644 index be006b70..00000000 --- a/config/fabric/modules/bar/glance.py +++ /dev/null @@ -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) diff --git a/config/fabric/modules/bar/icon_resolver.py b/config/fabric/modules/bar/icon_resolver.py deleted file mode 100644 index 883ed1a1..00000000 --- a/config/fabric/modules/bar/icon_resolver.py +++ /dev/null @@ -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 - ) diff --git a/config/fabric/modules/bar/widgets/__init__.py b/config/fabric/modules/bar/widgets/__init__.py index b5bc916d..61b7a0e2 100644 --- a/config/fabric/modules/bar/widgets/__init__.py +++ b/config/fabric/modules/bar/widgets/__init__.py @@ -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 * diff --git a/config/fabric/modules/bar/widgets/__pycache__/__init__.cpython-312.pyc b/config/fabric/modules/bar/widgets/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b265d066645e8fdefbee8ab62d0081cb3bed74c0 GIT binary patch literal 362 zcmX}nJx;?g6bEoSDNR#RgoHpvEQl=(cws~wfr**ONu0)tlV{luQ7^z1I0FMG;Q&Zh zn3&j*x-sFj;5R(~Z2kT9wph%OtEc;m)w>%%$H{*Mf7m=YJfi{?SfJMc?}WVquh47a zwdXbUio9l{)7fK6rNe{+MC$M!OkDF&@>^G1sXdEgwR&B4WcwEI1=RK%WC7@IGe23W_C?} zWUDzusw2_Dp%szZN};OSRN+9SO662>?YHwTE&;gjT4hzS;HKghuK}JMVYi zynXMR_j5R0k6;~r71E%qqsX)5w?y2^ARMfp%hk8ipxO4U*VJwCvP*Od%QF%*Z_nQU~#!Z3lC2g0MpF zU^$-HLD{#HvOht>JI6SgpiTeDXtZD$Qjmr{gJKZPu8H09h(gG27O?8lbiGVh zb2;X?G;VV_zTKtI5kua+ERQsX1Kwh|3BtEE4BKb;IlM=%#K1EabFe7~dg@r-D_;YlMoj%uKRO z80KhGA+G|0Aa$qFvSllF!IFHGw=`pv`X?r#(H5Tvm%) ziaDVe`S_?ZLiBVzn^OyhX2qd+@kw3HXg1@W*j@Q)@-iHrX&QJARb5^_F)&%3usxea z8)A4quqw8$itP)1YhwF`*s{PcsO$UtSNHedv40WIZGj`&R$f*hmfO}hP}b**JMO&% zcBHbFE3|}*cy>3Gw_0q^10m0cm9~gUlO6DEMLaHge2p$w+G%1HmpGfX+F3>Jb9iZA zvSw90N=kP>E(jHecQ=RM25! zTR==zo1)dR;b&+f4hmhqL3$WgWGCf(;%~v~@jtXf=B1ZuD?Da6cF= zzkNT{aCLBg@X81GL(zxF-u$9-G4O5VM&#b!#GP0l@|p z!+77d%zE>YwdNzY&y<6|zSeV%UvKDGYv{PmulEnF_79bXKN@16o?eJ7^{lqOzI5qs zWB09|yA6G1VWXvE@yt@^jdQmy-)lKl4n5e@xma3hJznOogdemVT#Bu=94+%#>*njO z1Rq3Vj|J3w;z#Lw>4zgAk#_h6No3Q?RI-{Z(|TEUXAAHlS-wOPx8PdL8WKbw3~&+qlG@Xb#{oNylh zEyjdKCm+XOswaoRn}*zh*TrCHxwAA{QB~$%*GO)Pz)(lD@dbl}1{ah(>$ih0Cpy^+ z{_bV0?Nofr{pnNW42Ud$s|~itK8*2iD7=XdZKC!~bZ`^xd&+m<#%sNQAs|kKe*wB4 BJv#sZ literal 0 HcmV?d00001 diff --git a/config/fabric/modules/bar/widgets/__pycache__/bluetooth.cpython-312.pyc b/config/fabric/modules/bar/widgets/__pycache__/bluetooth.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3415dd725fb23268ce2095f066c8ac166a5d581a GIT binary patch literal 1977 zcmah}%}*Ow5PxrXZ9m)VK)_9CQ@aZSnpILPsucCmqLw(SP=ZSnDFAAre~e1M@XJg`zSxP+2f=Su}*Qw1wudA#Rd#j0Z2rjTq3x7Fxk&atEn#KiP@u zCoAm-_Mp?n&cQJFud8EQ<6{%v$PgECl zd!8CUAvNL0oW>GmKG8JOHeF3){F#1lHy_oYIR3e=#)PVXle%rws_S2DEE!NPt$Xgc zy4!G6(U%-*&H3?r%Q~BP{G_H;E!}Z6&EYW=W#gX@3JdibEjYS;Pq&r|b9#lD)k3Xq zG%V^ADmp7Ho5nnKfp3>;Y-yF9gX?R3Qyo?N?Mcu(B_J<0&@+kyP>z-Hra_Rqkgz%EaCzf~@OOCllRl>LM(NY3TQ`b+CXkBLcLI^|_^g-P#~H2FzoNdV8-^;eey)=O7^OJ;G)u2g%O^Hn z*0}8OoGP%`1@58`$l72RAg_Ta_v)BHHqi0lNON$)8=PnkPVNs*ZWWtyZePy*T5J~Y zdd0iXMU?D6AtKqw9H)Dl>HK~=e<=4pxVe4vk<=Wx;tgCmkgp!+M+1Nz z68QnyCJ(dC^TXbGfYJ!N2+{rnCEgCLSs<^4QfGF6QM7_-a0Zmx0D*27RB`R&qUl7f zs<;bO=_Ex78(UdkpmuN)wwhu(ia{Nh)mN!8#`qX2sbW~f6wJoRSCC>A2ZeDsh{DYK zDX2|!eJ$IGHP+QCVC&?8K+e1UciAJCe|&SV*t|CDU7LMMz6cVfCiz^l^%~VQKc#8m zU;tj$v@aXF6`ruS!5hnQ!Usd}GByI7pNS?;m0Fgj!E4_DZSdMpLY(j(W}I-~Io!pI zO?23w-?(*{y}U7VB9Yj;e`eFM(ZAmkVz+VdsKCAile0G*S7Vj-912HgU!;yE*I1># z!g!f{i32r+co3IQ^3Ws4tWQ1)e{Yh#2O>|Y!+-3#h%r7wSC7!p5z3uNIeZ&G6#qhe H4{rYpL?5&( literal 0 HcmV?d00001 diff --git a/config/fabric/modules/bar/widgets/__pycache__/idle.cpython-312.pyc b/config/fabric/modules/bar/widgets/__pycache__/idle.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a1a4dec2e528bab4ade603ee09372206d813d1c5 GIT binary patch literal 1866 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 A6#xJL literal 0 HcmV?d00001 diff --git a/config/fabric/modules/bar/widgets/__pycache__/material_icon.cpython-312.pyc b/config/fabric/modules/bar/widgets/__pycache__/material_icon.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a80706c08a08f5ddd0378f8ea0d31b38b0d4925 GIT binary patch literal 664 zcmZ8eL5tHs6rRaU(rCBXZug)SY(;U&!3GvR=!%Eci@5e8c-TuxGt+L?Bn>lJwI#wH zJd3w2sIUhw;veuo2(k-;Wln-#yltsoJozS#g1%(F_g*sdz3)ptR4OMC#OB8fgVP2= zUv={*N<}fh1jRmLh~W@Lcnf31N{n!WQCKD?eT!Mo%q==H9Q(UI=Wbj;cgn%0=LXU9D+c?hoVivetCHH8$2;%JO*(8yr)a zp%$-bF58spDCDZN-Sxs?5UbLoMe!CnhO%}Ordjn+hYAWwm>RSvRnB?3xnrr{wIF_7 zbGL^Pccm9U^uomLdp!~OZZu@OA(w8?6Yk@H4R|Wue+0Laky^S}ShxcYL>(CQFu4J+ zhrZMr(`s{CKQ~Dy{ez9e+Um4^7VcTus#|+^XH{fZrgr_a-8ixvldGTX^WVzVqjK}b zI=~@q&VfaHqH9-@Cmr|}oPwibMZ+?HvTrQx+!SY^ k)&E9b1UM!b$beFUI2JwTe6aWAK literal 0 HcmV?d00001 diff --git a/config/fabric/modules/bar/widgets/__pycache__/microphone.cpython-312.pyc b/config/fabric/modules/bar/widgets/__pycache__/microphone.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35203a9fabb6d4f4c9e347e882381e87089374e9 GIT binary patch literal 2085 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 literal 0 HcmV?d00001 diff --git a/config/fabric/modules/bar/widgets/__pycache__/powerprofile.cpython-312.pyc b/config/fabric/modules/bar/widgets/__pycache__/powerprofile.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..20218d07d431ef4557ee70f02c588a9b2c584de0 GIT binary patch literal 2170 zcmah~&2JM&6rb5$+w0iIj^mUdl3*tx&7xxWLxQTH3bmAipavCAzKk}WNwTp1=&VCN zWU8o&R7X_{hgRg!1BXgg6%PFqdaTq74xzS2MFq8o_C^V<5U0M`UFWNoI+EYa+c*36 z{eJJmKgD7_2-fJKvFUF$gnpAsX9fJjW*!c=5k(Z+sDul+q!bh^b;VXoT0wKqsvRf= z3qd$*G(dwi^tDGf^<_lEOj}bue+7LZVD$Vc6+;n8HqVO0nPIj~ij`8yEK?D; z%GWE`7~!nS%o^hc7V0~ddDx;KNZm5+bHz$o#Hd*_iDO=8oK(tr5iV6IBQx-hp}vSz zD|3t=b*)05G;On7WK=||j89cKe5c5YUO=8yd}Z@hID86t87g3k3Q7Y_VTzaaf=ZQT zRM4mjGC(zu!3LVgh0tYW1Vr?b{N5#AnX+tF#5-I|9wYGEoCNU|zKv>I))l3WJ_p{Z zW}!O%27iGimvuxs(V$wWkr`iisZ{GTQ#7I6iwUy zPKFt9W`O~r6CzE7h-lRdnOHz6hggtE%~pX~MqCDoZ#Pt-In16C!E19SpLRr;kfLom z4k3=rY&yO4;?3MlrNnZMS-xi4)!dXh$*p1zvNCHkCpT&G+?++HSH<%K zhsFM#6lOaSM#1D91@U|d{i4TKLQQ?3sgJB4Th~V(4W=8~hJN68egCSqN?XIno5RO{ zpg-&9H{k`eD-AM8`P)1L;x>?cbt?_qg2v774CkSst9s<*mf+)n8YrLOQ;tuyyfU7`4{vgUg( z!!)>|LRkbm-nMss5S~i{_N?x=w@aw5^3gi@BwM8hZ^&7(XZ@d_1zFDB;u`7x{Az5^ z2SDxQ+MhsM5iQ7>qUMG6+Oevf!J1<&G9x5nmp;6B=G=w%$hmhf<}V9X)_@Fw%UTtX z^HSwH6RJt6&}J;k49#r=J|xXy*%+j3mYC4XY|b4%j!at`me(1Bpe+vUs*oK`C9TdU zAfPrGj;gR^!-$}5q^B)^p_{^guf3y=sW)7SVMmliMJwy>yg2BG;#C%%K25T zHDELcjE(4#$C18vdZKZ9BRV9FXIIYNy3*<&Z}yKrh`#(N-q(t!*W>ASBGpP{nu$y+ zG2Tp!ZzLw#V-vTu2Z_v+07_)s`ZIJnQzamnsXc^vLr>0ELOz-`ZO`J)Ik)GzYyd7% zh?qY}i}F8^7?|&u*yNZw02sYQ-zjVgu A(*OVf literal 0 HcmV?d00001 diff --git a/config/fabric/modules/bar/widgets/__pycache__/taskbar.cpython-312.pyc b/config/fabric/modules/bar/widgets/__pycache__/taskbar.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9dfe4c69e74a4aa68d4daad96f1a4bc9150c7d56 GIT binary patch literal 7993 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 literal 0 HcmV?d00001 diff --git a/config/fabric/modules/bar/widgets/__pycache__/wifi.cpython-312.pyc b/config/fabric/modules/bar/widgets/__pycache__/wifi.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..96135b1c40f1e4a19c0a6bf27bd395afcee559d0 GIT binary patch literal 3697 zcmds4-ESLJ7Qc5s9Dj_Hv`!#SV`37L)}?Vm*s=nm5;aw!VwF^)s=C&$W+$FWI?cp3 zckHH)f>enJ9K`2CNqM3VMItIledJF7Ee{=H$!2IJ&~~NWx2mQqx=(w~eAr2AKBRqP zB%gcd+>bf;_dDm@p0>8%BATH5OQf!WHaBJipfe^Jr zCu{U7eV0;F^brDNRPHnWnrG%3k-am+d;#8Io%^T+-kPh5QD47C&ISE`s|9Um>&@?} z;%5OLQwsZ?3-}|gc7eionmd-^z_a(zh{pA+pW9N-J-V!C^SKmfiw5Ft3pr(3(#=w}x~CQ$wxYw;=m@-iAB#VX1xBcY#YyO3+HB=BKXDeDXK&|7J_^T(-}9Xa zk|;O33wXrmY4|m!L0qCQ6Y9YK*Iq(iqZ?d1FK_wehjbGX>f4VBq)a~NSLhbSJEB+i zF?3SOf|AwbQelg?x%7k`YU*56@gR^M9QU(BQ;S+oyHH?9RuB2;`g=7gN>3SiNN?tm zbaVC-u!;FNh@bw2Y2gmxV&QLR&Ro|k$7<53C5>Jw*QBScnKSnrc;46dJx0MCUdfg1 zK*1~(b;C)ovc4cIs>)0@gc~B^e{{3q=TP6Tayldo0z=Mo`i|)5Q+!MOoFnN9o9bn{iJf9c=6xo$G`6kqLE*L+K^|6BV0kH zd9%p$+#+)*`~_ENn>pG9{5b4uCPBEaaHI32^}^isRHc0R#K&_V&20~iRlCMOb>DR2 zeP9qSOIuhmlpILN?#ELi8-wL64Wb$QSk{;}5Bb~{bf}xQ+#A!i8re;H=>S8$Q7$B(NzEyGo2n zP^>=g$NtY|4ZM@gXF%W;+Wr2C&AAWewtMg*{q69jB3Sogfh@~*SeD&l6Z(=YzgkiZ zcf_ePoyv#dz0NS#vm^?nnW4RQ)T?K+nqkOtin2b?Iv2#WdqH67#!z7S?q-g4@*@`# zpS=5sDE8d#42b=AyLmBuH!OgVc(M0CVGs_@&camCb4Ir^PUEfQmEU_kl~*9A=kpgB z`nBEjz<^WdITgOMCBy$A?iaASvx8GE0!P?!c*X0@On|tY literal 0 HcmV?d00001 diff --git a/config/fabric/modules/bar/widgets/__pycache__/workspace.cpython-312.pyc b/config/fabric/modules/bar/widgets/__pycache__/workspace.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff2a1286b10b50d209f9ca94257e52be56a1b929 GIT binary patch literal 1083 zcmZ8g&1(}u6rcS_nyp^!im8imiYOBiQ3D(dsoB61fzm)}H0l#xKuC&18H zjTsTq(==x>MT_qSi~o>N8)^pC)qs74A40&P}x%0Io)fEJS6%? z0j*%))4QO#QiUd5XQ_KY_D7P9sbI!x0Tre@=4@6G~ zw?T=yHc`UggT_qPaWI<$)~$qx9kgV+#UdLN8X~x4SE$zg)@{~A!hbp%M%Z)_CJE*c zPN>a{_61n40U6|n13Wge&}q_5!Y7u`h*xIYks?XbXAu7du6zZTzH38IjcV*$a-@}< zXe1}X0DlfD}lo;ss h>O*3t8vPSiq}ihckm4o1P!`#S&t literal 0 HcmV?d00001 diff --git a/config/fabric/modules/bar/widgets/battery.py b/config/fabric/modules/bar/widgets/battery.py index 1bc0d2ce..6c9d116c 100644 --- a/config/fabric/modules/bar/widgets/battery.py +++ b/config/fabric/modules/bar/widgets/battery.py @@ -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 + diff --git a/config/fabric/modules/bar/widgets/bluetooth.py b/config/fabric/modules/bar/widgets/bluetooth.py index ba8c2566..dba05448 100644 --- a/config/fabric/modules/bar/widgets/bluetooth.py +++ b/config/fabric/modules/bar/widgets/bluetooth.py @@ -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) + diff --git a/config/fabric/modules/bar/widgets/idle.py b/config/fabric/modules/bar/widgets/idle.py deleted file mode 100644 index f55f0065..00000000 --- a/config/fabric/modules/bar/widgets/idle.py +++ /dev/null @@ -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 diff --git a/config/fabric/modules/bar/widgets/info.py b/config/fabric/modules/bar/widgets/info.py new file mode 100644 index 00000000..398e9493 --- /dev/null +++ b/config/fabric/modules/bar/widgets/info.py @@ -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}%") + diff --git a/config/fabric/modules/bar/widgets/microphone.py b/config/fabric/modules/bar/widgets/microphone.py index 97835264..186e36d4 100644 --- a/config/fabric/modules/bar/widgets/microphone.py +++ b/config/fabric/modules/bar/widgets/microphone.py @@ -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 + diff --git a/config/fabric/modules/bar/widgets/network.py b/config/fabric/modules/bar/widgets/network.py new file mode 100644 index 00000000..b4e64c47 --- /dev/null +++ b/config/fabric/modules/bar/widgets/network.py @@ -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 + diff --git a/config/fabric/modules/bar/widgets/powerprofile.py b/config/fabric/modules/bar/widgets/powerprofile.py index 30dfe4fa..53da53ac 100644 --- a/config/fabric/modules/bar/widgets/powerprofile.py +++ b/config/fabric/modules/bar/widgets/powerprofile.py @@ -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 + + diff --git a/config/fabric/modules/bar/widgets/taskbar11.py b/config/fabric/modules/bar/widgets/taskbar11.py deleted file mode 100644 index 3e176ee7..00000000 --- a/config/fabric/modules/bar/widgets/taskbar11.py +++ /dev/null @@ -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 - diff --git a/config/fabric/modules/bar/widgets/volume.py b/config/fabric/modules/bar/widgets/volume.py index 8bf5d568..76d9dd57 100644 --- a/config/fabric/modules/bar/widgets/volume.py +++ b/config/fabric/modules/bar/widgets/volume.py @@ -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"] + diff --git a/config/fabric/modules/bar/widgets/wifi.py b/config/fabric/modules/bar/widgets/wifi.py deleted file mode 100644 index 5b782f6b..00000000 --- a/config/fabric/modules/bar/widgets/wifi.py +++ /dev/null @@ -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 diff --git a/config/fabric/modules/bar/widgets/workspace.py b/config/fabric/modules/bar/widgets/workspace.py new file mode 100644 index 00000000..f13372d6 --- /dev/null +++ b/config/fabric/modules/bar/widgets/workspace.py @@ -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)