Files
sims/bar/modules/bar.py
2025-09-30 20:52:03 +02:00

209 lines
7.2 KiB
Python

import psutil
from fabric.widgets.box import Box
from fabric.widgets.label import Label
from fabric.widgets.image import Image
from fabric.widgets.overlay import Overlay
from fabric.widgets.datetime import DateTime
from fabric.widgets.centerbox import CenterBox
from bar.modules.player import Player
from bar.modules.vinyl import VinylButton
from bar.modules.quick_menu import QuickMenuOpener
from bar.modules.battery import Battery
from bar.modules.calendar import CalendarService, CalendarPopup
from bar.modules.notmuch import NotmuchWidget
from fabric.widgets.wayland import WaylandWindow as Window
from fabric.system_tray.widgets import SystemTray
from fabric.river.widgets import (
RiverWorkspaces,
RiverWorkspaceButton,
RiverActiveWindow,
get_river_connection,
)
from fabric.widgets.circularprogressbar import CircularProgressBar
from bar.services.system_stats import SystemStatsService
from bar.config import VINYL, BATTERY, BAR_HEIGHT, WINDOW_TITLE, NOTMUCH
class StatusBar(Window):
def __init__(
self,
display: int,
tray: SystemTray | None = None,
monitor: int = 1,
river_service=None,
):
super().__init__(
name="bar",
layer="top",
anchor="left top right",
margin="0px 0px -2px 0px",
exclusivity="auto",
visible=False,
all_visible=False,
monitor=monitor,
)
if river_service:
self.river = river_service
else:
self.river = get_river_connection()
self.workspaces = RiverWorkspaces(
display,
name="workspaces",
spacing=4,
buttons_factory=lambda ws_id: RiverWorkspaceButton(id=ws_id, label=None),
river_service=self.river,
)
# Create calendar components (refresh every 2 minutes)
self.calendar_service = CalendarService(update_interval=120000)
self.calendar_popup = CalendarPopup()
self.calendar_popup_visible = False
# Create clickable datetime widget
from fabric.widgets.button import Button
datetime_widget = DateTime(name="date-time", formatters="%d %b - %H:%M")
self.date_time = Button(
name="date-time-button",
child=datetime_widget,
on_clicked=self.toggle_calendar,
style="background: transparent; border: none; padding: 0; margin: 0; box-shadow: none;"
)
# Connect calendar service to popup
self.calendar_service.connect("events-changed", self.update_calendar_display)
self.system_tray = tray
self.active_window = RiverActiveWindow(
name="active-window",
max_length=50,
style="color: #ffffff; font-size: 14px; font-weight: bold;",
)
self.ram_progress_bar = CircularProgressBar(
name="ram-progress-bar", pie=True, size=24
)
self.cpu_progress_bar = CircularProgressBar(
name="cpu-progress-bar", pie=True, size=24
)
self.progress_label = Label(
"", style="margin: 0px 6px 0px 0px; font-size: 12px"
)
self.progress_bars_overlay = Overlay(
child=self.ram_progress_bar,
overlays=[self.cpu_progress_bar, self.progress_label],
)
self.player = Player()
self.vinyl = None
if VINYL["enable"]:
self.vinyl = VinylButton()
# Create quick menu button
self.quick_menu = QuickMenuOpener(icon_name="open-menu-symbolic")
# Setup audio section with vinyl if enabled
if self.vinyl:
self.quick_menu.get_menu().setup_audio_section(vinyl_service=self.vinyl)
self.battery = None
if BATTERY["enable"]:
self.battery = Battery()
self.notmuch = None
if NOTMUCH["enable"]:
self.notmuch = NotmuchWidget()
self.status_container = Box(
name="widgets-container",
spacing=4,
orientation="h",
children=self.progress_bars_overlay,
)
end_container_children = []
end_container_children.append(self.status_container)
if self.system_tray:
end_container_children.append(self.system_tray)
if self.battery:
end_container_children.append(self.battery)
if self.notmuch:
end_container_children.append(self.notmuch)
# Add quick menu button next to time
end_container_children.append(self.quick_menu)
end_container_children.append(self.date_time)
center_children = []
if WINDOW_TITLE["enable"]:
center_children.append(self.active_window)
self.children = CenterBox(
name="bar-inner",
start_children=Box(
name="start-container",
spacing=6,
orientation="h",
children=[
Image(name="nixos-label", icon_name="nix-snowflake-white", icon_size=20),
self.workspaces,
],
),
center_children=Box(
name="center-container",
spacing=4,
orientation="h",
children=center_children,
),
end_children=Box(
name="end-container",
spacing=4,
orientation="h",
children=end_container_children,
),
)
# Create system stats service with signal-based updates
self.system_stats_service = SystemStatsService(update_interval=3000)
self.system_stats_service.connect("stats-changed", self.update_progress_bars)
# Set the bar height
self.set_size_request(-1, BAR_HEIGHT)
self.show_all()
def __del__(self):
"""Cleanup when bar is destroyed"""
if hasattr(self, 'calendar_service'):
self.calendar_service.stop_monitoring()
def update_progress_bars(self, service, cpu_percent, memory_percent):
"""Update progress bars when system stats change"""
self.cpu_progress_bar.value = cpu_percent
self.ram_progress_bar.value = memory_percent
def toggle_calendar(self, button=None):
"""Toggle the calendar popup when datetime is clicked"""
from loguru import logger
logger.info(f"[Calendar] DateTime clicked, popup_visible: {self.calendar_popup_visible}")
if self.calendar_popup_visible:
logger.info("[Calendar] Hiding calendar popup")
self.calendar_popup.set_visible(False)
self.calendar_popup_visible = False
else:
logger.info("[Calendar] Showing calendar popup")
# Use cached events - no need to refresh on click
cached_events = self.calendar_service.get_cached_events()
logger.info(f"[Calendar] Using {len(cached_events)} cached events")
self.calendar_popup.update_events_display(cached_events)
self.calendar_popup.set_visible(True)
self.calendar_popup.show_all()
self.calendar_popup_visible = True
def update_calendar_display(self, service, events):
"""Update the calendar popup with events"""
self.calendar_popup.update_events_display(events)