Files
Modus/modules/bar/components/updates.py
T
2025-04-25 06:33:51 +05:45

116 lines
3.7 KiB
Python

import json
from fabric.utils import exec_shell_command_async, get_relative_path, invoke_repeater
from fabric.widgets.box import Box
from fabric.widgets.centerbox import CenterBox
from fabric.widgets.label import Label
from fabric.widgets.button import Button
from fabric.widgets.stack import Stack
from gi.repository import Gtk
import utils.icons as icons
import config.data as data
class UpdatesWidget(Button):
"""A widget to display the number of available updates."""
def __init__(
self,
**kwargs,
):
# Determine if we should use vertical layout for components
is_vertical_layout = data.VERTICAL
# Initialize the button with specific name and style
super().__init__(
name="update",
orientation="h" if not is_vertical_layout else "v",
**kwargs,
)
self.script_file = get_relative_path("../../../config/scripts/systemupdates.sh")
self.update_level_label = Label(
name="update-label",
label="0",
visible=False, # Initially hidden
)
self.update_icon = Label(name="update-icon", markup=icons.update)
self.updated_icon = Label(name="updated-icon", markup=icons.updated)
# Create boxes with proper orientation
self.update_box = CenterBox(
orientation="v" if is_vertical_layout else "h",
center_children=[self.update_icon, self.update_level_label],
)
self.updated_box = CenterBox(
orientation="v" if is_vertical_layout else "h",
center_children=[self.updated_icon],
)
# Stack to switch between states
self.stack = Stack()
self.stack.add_named(self.update_box, "update_box")
self.stack.add_named(self.updated_box, "updated_box")
self.stack.set_visible_child_name("update_box")
self.children = Box(
orientation="v" if is_vertical_layout else "h",
children=self.stack,
)
# Configure stack transitions
self.stack.set_homogeneous(False)
self.stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
# Connect click handler
self.connect("button-press-event", self.on_button_press)
# Check for updates every minute
invoke_repeater(60000, self.update, initial_call=True)
def update_values(self, value: str) -> bool:
"""Update the widget state based on update check results"""
try:
value = json.loads(value)
except json.JSONDecodeError:
return False
update_count = str(value["total"])
self.update_level_label.set_label(update_count)
# Show appropriate state based on update count
if update_count == "0":
self.stack.set_visible_child_name("updated_box")
self.update_level_label.set_visible(False)
else:
self.stack.set_visible_child_name("update_box")
self.update_level_label.set_visible(True)
self.set_tooltip_text(value.get("tooltip", ""))
return True
def on_button_press(self, _, event) -> bool:
"""Handle button press events"""
if event.button == 1: # Left click
# Run update command
exec_shell_command_async(
f"{self.script_file} -arch -up",
lambda _: None,
)
self.update()
return True
else:
# Other clicks just refresh
self.update()
def update(self) -> bool:
"""Check for system updates"""
exec_shell_command_async(
f"{self.script_file} -arch",
lambda output: self.update_values(output),
)
return True