Added a dock widget that shows background processes.

This commit is contained in:
The Wobbler 2025-02-03 14:08:19 +01:00
parent 67c3b9e226
commit c55c1222f0
7 changed files with 135 additions and 7 deletions

View file

@ -17,7 +17,7 @@ class GUI:
self.settings = self.window.settings self.settings = self.window.settings
self.track_control = self.window.track_control self.track_control = self.window.track_control
self.window.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.app.library.main_library_dock) self.window.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.app.library.main_library_dock)
self.app.library.main_library_dock.setFeatures( self.app.library.main_library_dock.setFeatures(
QDockWidget.DockWidgetFeature.DockWidgetMovable | QDockWidget.DockWidgetFeature.DockWidgetMovable |
@ -54,3 +54,9 @@ class GUI:
self.track_control.on_track_change(previous_track, track) self.track_control.on_track_change(previous_track, track)
self.app.player.current_playlist.view.on_track_change(previous_track, track) self.app.player.current_playlist.view.on_track_change(previous_track, track)
def on_background_job_start(self, job: str):
self.window.process_dock.job_started_signal.emit(job)
def on_background_job_stop(self, job: str):
self.window.process_dock.on_background_job_stop(job)

View file

@ -160,8 +160,12 @@ class Player:
track = self.current_playlist.tracks[self.current_playlist.current_track_index + 1] track = self.current_playlist.tracks[self.current_playlist.current_track_index + 1]
if not track.cached: if not track.cached:
self.app.gui.on_background_job_start("track_caching")
track.cache() track.cache()
self.app.gui.on_background_job_stop("track_caching")
def cache_next_track(self): def cache_next_track(self):
# function that creates a thread which will cache the next track # function that creates a thread which will cache the next track
caching_thread = threading.Thread(target=self.caching_thread_function) caching_thread = threading.Thread(target=self.caching_thread_function)

View file

@ -11,12 +11,6 @@ class LibraryDock(QDockWidget):
self.library = library self.library = library
self.setAllowedAreas(
Qt.DockWidgetArea.LeftDockWidgetArea |
Qt.DockWidgetArea.RightDockWidgetArea |
Qt.DockWidgetArea.BottomDockWidgetArea
)
self.setAcceptDrops(True) self.setAcceptDrops(True)
self.library_widget = Library(library, self) self.library_widget = Library(library, self)

View file

@ -5,6 +5,7 @@ from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QMainWindow, QMenu from PyQt6.QtWidgets import QMainWindow, QMenu
from .track_control import TrackControl from .track_control import TrackControl
from .settings import Settings from .settings import Settings
from .process.process_dock import ProcessDock
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
@ -35,5 +36,9 @@ class MainWindow(QMainWindow):
self.settings.hide() self.settings.hide()
self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.settings) self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.settings)
self.process_dock = ProcessDock(app)
self.process_dock.hide()
self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.process_dock)
self.settings_action.triggered.connect(self.settings.show) self.settings_action.triggered.connect(self.settings.show)

View file

@ -0,0 +1 @@
#!/usr/bin/python3

View file

@ -0,0 +1,41 @@
#!/usr/bin/python3
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QFont
from PyQt6.QtWidgets import QSizePolicy, QGroupBox, QLabel, QProgressBar, QVBoxLayout
class BackgroundProcess(QGroupBox):
normal_font = QFont()
normal_font.setBold(False)
bold_font = QFont()
bold_font.setBold(True)
def __init__(self, title: str, parent=None, description: str="", steps: int=0):
super().__init__(title, parent)
self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
self.setAlignment(Qt.AlignmentFlag.AlignLeading | Qt.AlignmentFlag.AlignVCenter)
self.setFont(self.bold_font)
self.layout = QVBoxLayout(self)
self.description = QLabel(description, self)
self.description.setFont(self.normal_font)
self.layout.addWidget(self.description)
self.progress_bar = QProgressBar(self)
self.progress_bar.setMaximum(steps)
self.layout.addWidget(self.progress_bar)
self.setLayout(self.layout)
def get_progress(self):
return 0
def set_range(self, maximum: int, minimum: int=0):
self.progress_bar.setRange(minimum, maximum)
def update_progress(self):
self.progress_bar.setValue(self.get_progress())

View file

@ -0,0 +1,77 @@
#!/usr/bin/python3
from PyQt6.QtCore import QTimer, pyqtSignal
from PyQt6.QtWidgets import QWidget, QDockWidget, QScrollArea, QVBoxLayout
from .process import BackgroundProcess
PROGRESS_UPDATE_RATE = 60
PROGRESS_UPDATE_INTERVAL = 1000 // PROGRESS_UPDATE_RATE
class ProcessDock(QDockWidget):
# we need a signal for self.on_background_job_start() because PyQt6 doesn't allow some operations to be performed
# from a different thread
job_started_signal = pyqtSignal(str)
def __init__(self, app, parent=None):
super().__init__(parent)
self.app = app
self.processes = {}
self.setWindowTitle("Background Processes")
self.scroll_area = QScrollArea(self)
self.scroll_area.setWidgetResizable(True)
self.process_container = QWidget(self.scroll_area)
self.process_layout = QVBoxLayout(self.process_container)
# add expanding widget so the distance between processes will be equal
self.process_layout.addWidget(QWidget(self.process_container))
self.process_container.setLayout(self.process_layout)
self.scroll_area.setWidget(self.process_container)
self.setWidget(self.scroll_area)
self.progress_update_timer = QTimer()
self.progress_update_timer.timeout.connect(self.update_processes)
self.progress_update_timer.start(PROGRESS_UPDATE_INTERVAL)
self.job_started_signal.connect(self.on_background_job_start)
# for i in range(8):
# self.add_process(BackgroundProcess(f"Kurwa x{i}", self.process_container, "Boooooooober!!!"))
#
# self.add_process(BackgroundProcess("ja perdole!", self.process_container, "Boooooooober!!!"))
def add_process(self, name: str, process: BackgroundProcess):
if not name in self.processes:
self.processes[name] = process
self.process_layout.insertWidget(self.process_layout.count() - 1, process)
def update_processes(self):
for process in self.processes.values():
process.update_progress()
def on_background_job_start(self, job):
match job:
case "track_caching":
self.add_process(
job,
BackgroundProcess(
"Loading Track",
self.process_container,
"Loading next track in the background so it starts immediately."
)
)
def on_background_job_stop(self, job):
if job in self.processes:
self.processes.pop(job).deleteLater()