from __future__ import annotations import gi from gi.repository import GLib, Gtk, Pango, Adw class DownloadRow(Gtk.ListBoxRow): def __init__(self, name: str): super().__init__() self.set_selectable(False) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4) vbox.set_margin_start(12) vbox.set_margin_end(12) vbox.set_margin_top(8) vbox.set_margin_bottom(8) self.label = Gtk.Label(label=name, xalign=0.0) self.label.set_ellipsize(Pango.EllipsizeMode.END) self.label.add_css_class("heading") vbox.append(self.label) self.progress_bar = Gtk.ProgressBar() self.progress_bar.set_show_text(True) vbox.append(self.progress_bar) self.set_child(vbox) def update_progress(self, downloaded: int, total: int) -> None: if total > 0: fraction = downloaded / total self.progress_bar.set_fraction(fraction) self.progress_bar.set_text(f"{int(fraction * 100)}%") else: self.progress_bar.pulse() self.progress_bar.set_text("Downloading...") def set_status(self, status: str) -> None: self.progress_bar.set_text(status) class DownloadManager: def __init__(self): self.popover = Gtk.Popover() self.scrolled = Gtk.ScrolledWindow() self.scrolled.set_min_content_width(450) self.scrolled.set_min_content_height(250) self.scrolled.set_max_content_height(600) self.listbox = Gtk.ListBox() self.listbox.set_selection_mode(Gtk.SelectionMode.NONE) self.listbox.add_css_class("boxed-list") self.listbox.set_margin_start(12) self.listbox.set_margin_end(12) self.listbox.set_margin_top(12) self.listbox.set_margin_bottom(12) self.scrolled.set_child(self.listbox) self.popover.set_child(self.scrolled) self.active_downloads: dict[str, DownloadRow] = {} def add_download(self, download_id: str, name: str) -> DownloadRow: row = DownloadRow(name) self.active_downloads[download_id] = row self.listbox.append(row) return row def remove_download(self, download_id: str) -> None: if download_id in self.active_downloads: row = self.active_downloads.pop(download_id) self.listbox.remove(row)