from logging import getLogger from typing import Optional from PyQt5.QtCore import pyqtSignal, Qt, QThreadPool, pyqtSlot from PyQt5.QtWidgets import QWidget, QFrame from legendary.models.downloading import AnalysisResult from legendary.models.game import Game, InstalledGame from qtawesome import icon from rare.models.install import InstallQueueItemModel, InstallOptionsModel, InstallDownloadModel from rare.shared import RareCore, ImageManagerSingleton from rare.shared.workers.install_info import InstallInfoWorker from rare.ui.components.tabs.downloads.download_widget import Ui_DownloadWidget from rare.ui.components.tabs.downloads.info_widget import Ui_InfoWidget from rare.utils.misc import get_size, widget_object_name, elide_text from rare.widgets.image_widget import ImageWidget, ImageSize logger = getLogger("DownloadWidgets") class InfoWidget(QWidget): def __init__( self, game: Optional[Game], igame: Optional[InstalledGame], analysis: Optional[AnalysisResult] = None, old_igame: Optional[InstalledGame] = None, parent=None, ): super(InfoWidget, self).__init__(parent=parent) self.ui = Ui_InfoWidget() self.ui.setupUi(self) self.image_manager = ImageManagerSingleton() self.image = ImageWidget(self) self.image.setFixedSize(ImageSize.Icon) self.ui.image_layout.addWidget(self.image) self.ui.info_widget_layout.setAlignment(Qt.AlignTop) if game and igame: self.update_information(game, igame, analysis, old_igame) elif old_igame: self.ui.title.setText(old_igame.title) self.ui.remote_version.setText("...") self.ui.local_version.setText("...") self.ui.dl_size.setText("...") self.ui.install_size.setText("...") self.image.setPixmap(self.image_manager.get_pixmap(old_igame.app_name, color=True)) def update_information(self, game, igame, analysis, old_igame): self.ui.title.setText(game.app_title) self.ui.remote_version.setText( elide_text(self.ui.remote_version, old_igame.version if old_igame else game.app_version(igame.platform)) ) self.ui.local_version.setText(elide_text(self.ui.local_version, igame.version)) self.ui.dl_size.setText(get_size(analysis.dl_size) if analysis else "") self.ui.install_size.setText(get_size(analysis.install_size) if analysis else "") self.image.setPixmap(self.image_manager.get_pixmap(game.app_name, color=True)) class UpdateWidget(QFrame): enqueue = pyqtSignal(InstallOptionsModel) def __init__(self, game: Game, igame: InstalledGame, parent=None): super(UpdateWidget, self).__init__(parent=parent) self.ui = Ui_DownloadWidget() self.ui.setupUi(self) # lk: setObjectName has to be after `setupUi` because it is also set in that function self.setObjectName(widget_object_name(self, game.app_name)) self.game = game self.igame = igame self.ui.queue_buttons.setVisible(False) self.ui.move_buttons.setVisible(False) self.info_widget = InfoWidget(game, igame, parent=self) self.ui.info_layout.addWidget(self.info_widget) self.ui.update_button.clicked.connect(lambda: self.update_game(True)) self.ui.settings_button.clicked.connect(lambda: self.update_game(False)) def update_game(self, auto: bool): self.ui.update_button.setDisabled(True) self.ui.settings_button.setDisabled(True) self.enqueue.emit(InstallOptionsModel(app_name=self.game.app_name, update=True, silent=auto)) # True if settings def set_enabled(self, enabled: bool): self.ui.update_button.setEnabled(enabled) self.ui.settings_button.setEnabled(enabled) def version(self) -> str: return self.game.app_version(self.igame.platform) class QueueWidget(QFrame): # str: app_name move_up = pyqtSignal(str) # str: app_name move_down = pyqtSignal(str) # str: app_name remove = pyqtSignal(str) # InstallQueueItemModel force = pyqtSignal(InstallQueueItemModel) def __init__(self, item: InstallQueueItemModel, old_igame: InstalledGame, parent=None): super(QueueWidget, self).__init__(parent=parent) self.ui = Ui_DownloadWidget() self.ui.setupUi(self) # lk: setObjectName has to be after `setupUi` because it is also set in that function self.setObjectName(widget_object_name(self, item.options.app_name)) self.threadpool = QThreadPool.globalInstance() if not item: self.ui.queue_buttons.setEnabled(False) worker = InstallInfoWorker(RareCore.instance().core(), item.options) worker.signals.result.connect(self.add_info_widget) worker.signals.failed.connect(self.__on_info_worker_failed) worker.signals.finished.connect(self.__on_info_worker_finished) self.threadpool.start(worker) self.info_widget = InfoWidget(None, None, None, old_igame, parent=self) else: self.info_widget = InfoWidget( item.download.game, item.download.igame, item.download.analysis, old_igame, parent=self ) self.ui.info_layout.addWidget(self.info_widget) self.ui.update_buttons.setVisible(False) self.old_igame = old_igame self.item = item self.ui.move_up_button.setIcon(icon("fa.arrow-up")) self.ui.move_up_button.clicked.connect( lambda: self.move_up.emit(self.item.options.app_name) ) self.ui.move_down_button.setIcon(icon("fa.arrow-down")) self.ui.move_down_button.clicked.connect( lambda: self.move_down.emit(self.item.options.app_name) ) self.ui.remove_button.clicked.connect(lambda: self.remove.emit(self.item.options.app_name)) self.ui.force_button.clicked.connect(lambda: self.force.emit(self.item)) @pyqtSlot(str) def __on_info_worker_failed(self, message: str): logger.error(f"Failed to requeue download for {self.item.options.app_name} with error: {message}") self.remove.emit(self.item.options.app_name) @pyqtSlot() def __on_info_worker_finished(self): logger.info(f"Download requeue worker finished for {self.item.options.app_name}") @pyqtSlot(InstallDownloadModel) def add_info_widget(self, download: InstallDownloadModel): self.item.download = download if self.item: self.info_widget.update_information(download.game, download.igame, download.analysis, self.old_igame) self.ui.queue_buttons.setEnabled(bool(self.item)) def toggle_arrows(self, index: int, length: int): self.ui.move_up_button.setEnabled(bool(index)) self.ui.move_down_button.setEnabled(bool(length - (index + 1)))