Source code for upsies.uis.tui.jobwidgets.bdinfo

import functools

from prompt_toolkit.layout.containers import DynamicContainer, HSplit, VSplit

from .... import utils
from .. import widgets
from . import JobWidgetBase


[docs] class BdinfoJobWidget(JobWidgetBase): is_interactive = False
[docs] def setup(self): self._activity_indicator = widgets.ActivityIndicator( style='class:info', extend_width=False, ) self._bdinfo_progress_widgets = {} self.job.siblings['playlists'].signal.register('playlists_selected', self.handle_playlists_selected) self.job.signal.register('bdinfo_progress', self.handle_bdinfo_progress) self.job.signal.register('running', lambda _: self._activity_indicator.enable()) self.job.signal.register('finished', lambda _: self._activity_indicator.disable())
def handle_playlists_selected(self, discpath, playlists): # Add progress info widgets for each playlist. for playlist in playlists: label = playlist.label if label not in self._bdinfo_progress_widgets: self._bdinfo_progress_widgets[label] = BdinfoProgressWidget(label) def handle_bdinfo_progress(self, progress): self._bdinfo_progress_widgets[progress.playlist.label].update(progress) self.invalidate() @functools.cached_property def runtime_widget(self): return DynamicContainer(self.get_runtime_widgets) def get_runtime_widgets(self): if not self._bdinfo_progress_widgets: # Show activity indicator if no BDInfo report generation has started yet. self._activity_indicator.enable() return self._activity_indicator else: self._activity_indicator.disable() return HSplit(self._bdinfo_progress_widgets.values())
[docs] class BdinfoProgressWidget: _instances = [] def __new__(cls, *_args, **_kwargs): self = super().__new__(cls) cls._instances.append(self) return self def __init__(self, label): self._label = str(label) self._activity_indicator = widgets.ActivityIndicator() self._bar = widgets.ProgressBar(width=30) self._label_widget = widgets.TextField(text=lambda: self.label_padded, extend_width=False) self._time_elapsed = utils.types.Timestamp(0) self._time_elapsed_widget = widgets.TextField(lambda: str(self._time_elapsed), extend_width=False) self._time_remaining = utils.types.Timestamp(0) self._time_remaining_widget = widgets.TextField(lambda: str(self._time_remaining), extend_width=False) self._container = VSplit( children=[ self._label_widget, DynamicContainer(self._get_progress_widgets), ], style='class:info', width=lambda: self.label_width + len(' 0:00:10 0:01:30'), ) def _get_progress_widgets(self): if self.is_waiting_for_first_progress: # Show activity indicator if no bdinfo is currently generated and this instance is # next in line. return VSplit([ widgets.hspacer, self._activity_indicator, ]) elif 0 < self._bar.percent < 100: # Show progress if report is being generated. return VSplit([ widgets.hspacer, self._time_elapsed_widget, widgets.hspacer, self._bar, widgets.hspacer, self._time_remaining_widget, ]) elif self._bar.percent >= 100: # Report generation is done. return VSplit([ widgets.hspacer, widgets.TextField('✔', extend_width=False), ]) else: return widgets.hspacer @property def is_waiting_for_first_progress(self): prev_instance = None for instance in type(self)._instances: if ( instance is self # Report generation hasn't started/finished yet. and instance.percent <= 0 # Previous instance finished or this is the first instance. and ( prev_instance is None or prev_instance.percent >= 100 ) ): self._activity_indicator.enable() return True prev_instance = instance return False def update(self, progress): self.percent = progress.percent self.time_elapsed = progress.time_elapsed self.time_remaining = progress.time_remaining @property def label(self): return self._label @property def label_padded(self): return self.label.rjust(self.label_width) @property def label_width(self): return max( len(instance.label) for instance in type(self)._instances ) @property def percent(self): return self._bar.percent @percent.setter def percent(self, percent): self._bar.percent = percent self._activity_indicator.disable() @property def time_elapsed(self): return self._time_elapsed @time_elapsed.setter def time_elapsed(self, time_elapsed): self._time_elapsed = utils.types.Timestamp(time_elapsed) @property def time_remaining(self): return self._time_remaining @time_remaining.setter def time_remaining(self, time_remaining): self._time_remaining = utils.types.Timestamp(time_remaining) def __pt_container__(self): return self._container