import time from fabric.widgets.wayland import WaylandWindow as Window from fabric.widgets.label import Label from fabric.widgets.box import Box from gi.repository import GLib, GObject from fabric.widgets.centerbox import CenterBox from services import brightness, audio from snippets import Animator, MaterialIcon def create_progress_bar(percentage, width=150): container = Box(orientation="h", name="progress-container") progress = Box( name="progress-fill", style=f"min-width: {percentage * width / 100}px;" ) background = Box(name="progress-background", style=f"min-width: {width}px;") background.children = [progress] container.children = [background] return container def update_progress_bar(progress_bar, percentage, width=150): progress_fill = progress_bar.children[0].children[0] progress_fill.set_style(f"min-width: {percentage * width / 100}px;") def create_labeled_progress(label_text, value_text, percentage): label = Label(name="osd-label", markup=label_text) value = Label(name="osd-value", markup=value_text) header = CenterBox(orientation="h", start_children=[label], end_children=[value]) progress = create_progress_bar(percentage) return Box( name="control-section", orientation="v", spacing=5, children=[header, progress] ) def get_brightness(): return ( round((brightness.screen_brightness / brightness.max_screen) * 100) if brightness.screen_brightness else 0 ) def get_volume(): return round(audio.speaker.volume) if audio.speaker else 0 class OSD(Window): def __init__(self): super().__init__( name="osd-menu", layer="overlay", anchor="bottom", margin="0 0 10px 0", keyboard_mode="on-demand", visible=False, style_classes="osd-panel", ) self.last_volume = get_volume() self.last_brightness = get_brightness() self.volume_container = create_labeled_progress( "Speaker", str(self.last_volume), self.last_volume ) self.brightness_container = create_labeled_progress( "Brightness", str(self.last_brightness), self.last_brightness ) self.children = Box( orientation="h", spacing=10, children=[self.brightness_container, self.volume_container], ) self.hide_timeout_id = None self._connect_signals() GLib.timeout_add(100, self._check_changes) def _connect_signals(self): audio.connect("notify::speaker", self._update_volume) brightness.connect("screen", self._update_brightness) def _update_volume(self, *_): volume = get_volume() self.volume_container.children[0].end_children[0].set_markup(str(volume)) update_progress_bar(self.volume_container.children[1], volume) self._reset_timeout() def _update_brightness(self, *_): brightness_level = get_brightness() self.brightness_container.children[0].end_children[0].set_markup( str(brightness_level) ) update_progress_bar(self.brightness_container.children[1], brightness_level) self._reset_timeout() def _reset_timeout(self): if self.hide_timeout_id: GLib.source_remove(self.hide_timeout_id) self.hide_timeout_id = GLib.timeout_add(1500, self._hide_osd) def _hide_osd(self): self.hide() self.hide_timeout_id = None return False def _check_changes(self): volume = get_volume() brightness_level = get_brightness() if volume != self.last_volume or brightness_level != self.last_brightness: self.last_volume, self.last_brightness = volume, brightness_level self.show_all() self._update_volume() self._update_brightness() return True