diff --git a/rare/components/main_window.py b/rare/components/main_window.py index e11a6165..5d45c64d 100644 --- a/rare/components/main_window.py +++ b/rare/components/main_window.py @@ -6,7 +6,7 @@ from PyQt5.QtGui import QCloseEvent from PyQt5.QtWidgets import QMainWindow, QMessageBox, QApplication from rare import data_dir, shared -from rare.components.tabs.tab_widget import TabWidget +from rare.components.tabs import TabWidget from rare.utils.rpc import DiscordRPC logger = getLogger("Window") diff --git a/rare/components/tabs/__init__.py b/rare/components/tabs/__init__.py index e69de29b..cc3d16e7 100644 --- a/rare/components/tabs/__init__.py +++ b/rare/components/tabs/__init__.py @@ -0,0 +1,110 @@ +from PyQt5.QtCore import QSize, pyqtSignal +from PyQt5.QtWidgets import QMenu, QTabWidget, QWidget, QWidgetAction, QShortcut +from qtawesome import icon + +from rare import shared +from rare.components.tabs.account import MiniWidget +from rare.components.tabs.downloads import DownloadTab +from rare.components.tabs.games import GamesTab +from rare.components.tabs.settings import SettingsTab +from rare.components.tabs.settings.debug import DebugSettings +from rare.components.tabs.shop import Shop +from rare.components.tabs.tab_utils import TabBar, TabButtonWidget + + +class TabWidget(QTabWidget): + delete_presence = pyqtSignal() + + def __init__(self, parent): + super(TabWidget, self).__init__(parent=parent) + disabled_tab = 3 if not shared.args.offline else 1 + self.core = shared.core + self.signals = shared.signals + self.setTabBar(TabBar(disabled_tab)) + # Generate Tabs + self.games_tab = GamesTab() + self.addTab(self.games_tab, self.tr("Games")) + + if not shared.args.offline: + # updates = self.games_tab.default_widget.game_list.updates + self.downloadTab = DownloadTab(self.games_tab.updates) + self.addTab(self.downloadTab, "Downloads" + ( + " (" + str(len(self.games_tab.updates)) + ")" if len(self.games_tab.updates) != 0 else "")) + self.store = Shop(self.core) + self.addTab(self.store, self.tr("Store (Beta)")) + self.settings = SettingsTab(self) + + if shared.args.debug: + self.settings.addTab(DebugSettings(), "Debug") + + # Space Tab + self.addTab(QWidget(), "") + self.setTabEnabled(disabled_tab, False) + # Button + self.account = QWidget() + self.addTab(self.account, "") + self.setTabEnabled(disabled_tab + 1, False) + + self.mini_widget = MiniWidget() + account_action = QWidgetAction(self) + account_action.setDefaultWidget(self.mini_widget) + account_button = TabButtonWidget('mdi.account-circle', 'Account') + account_button.setMenu(QMenu()) + account_button.menu().addAction(account_action) + self.tabBar().setTabButton(disabled_tab + 1, self.tabBar().RightSide, account_button) + + self.addTab(self.settings, icon("fa.gear"), + "(!)" if self.settings.about.update_available else "") + + # Signals + # set current index + self.signals.set_main_tab_index.connect(self.setCurrentIndex) + + # update dl tab text + self.signals.update_download_tab_text.connect(self.update_dl_tab_text) + + # Open game list on click on Games tab button + self.tabBarClicked.connect(self.mouse_clicked) + self.setIconSize(QSize(25, 25)) + + # shortcuts + QShortcut("Alt+1", self).activated.connect(lambda: self.setCurrentIndex(0)) + QShortcut("Alt+2", self).activated.connect(lambda: self.setCurrentIndex(1)) + QShortcut("Alt+3", self).activated.connect(lambda: self.setCurrentIndex(2)) + QShortcut("Alt+4", self).activated.connect(lambda: self.setCurrentIndex(5)) + + def update_dl_tab_text(self): + num_downloads = len(set([i.options.app_name for i in self.downloadTab.dl_queue] + [i for i in + self.downloadTab.update_widgets.keys()])) + + if num_downloads != 0: + self.setTabText(1, f"Downloads ({num_downloads})") + else: + self.setTabText(1, "Downloads") + + def mouse_clicked(self, tab_num): + if tab_num == 0: + self.games_tab.layout().setCurrentIndex(0) + + if not shared.args.offline and tab_num == 3: + self.store.load() + + def game_imported(self, app_name: str): + igame = self.core.get_installed_game(app_name) + if self.core.get_asset(app_name, False).build_version != igame.version: + self.downloadTab.add_update(igame) + downloads = len(self.downloadTab.dl_queue) + len(self.downloadTab.update_widgets.keys()) + self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else "")) + self.games_tab.update_list(app_name) + self.games_tab.setCurrentIndex(0) + + def resizeEvent(self, event): + self.tabBar().setMinimumWidth(self.width()) + super(TabWidget, self).resizeEvent(event) + + # Remove text "sync game" + def finished_sync(self, app_name): + if self.core.is_installed(app_name): + self.games_tab.widgets[app_name][0].info_text = "" + self.games_tab.widgets[app_name][0].info_label.setText("") + self.games_tab.widgets[app_name][1].info_label.setText("") diff --git a/rare/components/tabs/cloud_saves/__init__.py b/rare/components/tabs/cloud_saves/__init__.py index 2ad64723..e69de29b 100644 --- a/rare/components/tabs/cloud_saves/__init__.py +++ b/rare/components/tabs/cloud_saves/__init__.py @@ -1,156 +0,0 @@ -from logging import getLogger - -from PyQt5.QtCore import QThread, pyqtSignal, Qt -from PyQt5.QtWidgets import QScrollArea, QWidget, QVBoxLayout, QLabel, QPushButton, QMessageBox - -from legendary.core import LegendaryCore -from legendary.models.game import SaveGameStatus -from rare import shared -from rare.components.dialogs.path_input_dialog import PathInputDialog -from rare.components.tabs.cloud_saves.sync_widget import SyncWidget -from rare.utils.extra_widgets import WaitingSpinner - -logger = getLogger("Sync Saves") - - -class LoadThread(QThread): - signal = pyqtSignal(list) - - def __init__(self, core: LegendaryCore): - super(LoadThread, self).__init__() - self.core = core - - def run(self) -> None: - saves = self.core.get_save_games() - self.signal.emit(saves) - - -class SyncSaves(QScrollArea): - finished = pyqtSignal(str) - - def __init__(self): - super(SyncSaves, self).__init__() - self.core = shared.core - self.signals = shared.signals - self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) - self.load_saves() - - def load_saves(self, app_name=None, auto=False): - self.widget = QWidget() - layout = QVBoxLayout() - layout.addWidget(WaitingSpinner()) - layout.addWidget(QLabel("

Loading Cloud Saves

")) - layout.addStretch() - self.widget.setLayout(layout) - self.setWidget(self.widget) - - self.start_thread = LoadThread(self.core) - self.start_thread.signal.connect(lambda x: self.setup_ui(x, app_name, auto)) - self.start_thread.start() - self.igames = self.core.get_installed_list() - - def setup_ui(self, saves: list, app_name, auto=False): - self.start_thread.disconnect() - self.main_layout = QVBoxLayout() - self.title = QLabel( - f"

" + self.tr("Cloud Saves") + "

\n" + self.tr("Found Saves for folowing Games")) - self.main_layout.addWidget(self.title) - - saves_games = [] - for i in saves: - if not i.app_name in saves_games and self.core.is_installed(i.app_name): - saves_games.append(i.app_name) - if len(saves_games) == 0: - # QMessageBox.information(self.tr("No Games Found"), self.tr("Your games don't support cloud save")) - self.title.setText( - f"

" + self.tr("Cloud Saves") + "

\n" + self.tr("Your games does not support Cloud Saves")) - self.setWidget(self.title) - return - - self.sync_all_button = QPushButton(self.tr("Sync all games")) - self.sync_all_button.clicked.connect(self.sync_all) - self.main_layout.addWidget(self.sync_all_button) - - latest_save = {} - for i in sorted(saves, key=lambda a: a.datetime): - latest_save[i.app_name] = i - - logger.info(f'Got {len(latest_save)} remote save game(s)') - - self.widgets = [] - for igame in self.igames: - game = self.core.get_game(igame.app_name) - if not game.supports_cloud_saves: - continue - if latest_save.get(igame.app_name): - sync_widget = SyncWidget(igame, latest_save[igame.app_name]) - else: - continue - sync_widget.reload.connect(self.reload) - self.main_layout.addWidget(sync_widget) - self.widgets.append(sync_widget) - - self.widget = QWidget() - self.main_layout.addStretch(1) - self.widget.setLayout(self.main_layout) - self.setWidgetResizable(True) - self.setWidget(self.widget) - - if auto: - self.save(app_name, True) - - def reload(self, app_name, auto=False): - self.finished.emit(app_name) - self.setWidget(QWidget()) - self.load_saves(auto) - - def sync_game(self, app_name, from_game_finish_auto=True): - self.setWidget(QWidget()) - self.load_saves(app_name, from_game_finish_auto) - - def save(self, app_name, from_game_finish_auto=True): - for w in self.widgets: - if w.igame.app_name == app_name: - widget = w - break - else: - logger.warning("An Error occurred. Game does not support cloud saves") - return - - if widget.res == SaveGameStatus.SAME_AGE: - logger.info("Game is up to date") - elif widget.res == SaveGameStatus.LOCAL_NEWER: - widget.upload() - elif widget.res == SaveGameStatus.REMOTE_NEWER: - if from_game_finish_auto: - if QMessageBox.question(self, "Really", self.tr("You finished playing game, but Remote game is newer. " - "Do you want to download anyway? This could remove " - "your game progress. Please check your save path or " - "make a backup"), - QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.Yes: - widget.download() - else: - logger.info("Cancel Download") - self.finished.emit(app_name) - - def sync_all(self): - logger.info("Sync all Games") - for w in self.widgets: - if not w.igame.save_path: - save_path = self.core.get_save_path(w.igame.app_name) - if '%' in save_path or '{' in save_path: - self.logger.info_label("Could not find save_path") - save_path = PathInputDialog(self.tr("Found no savepath"), - self.tr("No save path was found. Please select path or skip")) - if save_path == "": - continue - else: - w.igame.save_path = save_path - if w.res == SaveGameStatus.SAME_AGE: - continue - if w.res == SaveGameStatus.REMOTE_NEWER: - logger.info("Download") - w.download() - elif w.res == SaveGameStatus.LOCAL_NEWER: - logger.info("Upload") - w.upload() diff --git a/rare/components/tabs/cloud_saves/sync_widget.py b/rare/components/tabs/cloud_saves/sync_widget.py deleted file mode 100644 index 93399e2b..00000000 --- a/rare/components/tabs/cloud_saves/sync_widget.py +++ /dev/null @@ -1,231 +0,0 @@ -import os -from logging import getLogger - -from PyQt5.QtCore import QThread, pyqtSignal, Qt, QSettings -from PyQt5.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QLabel, QGroupBox, QMessageBox - -from legendary.core import LegendaryCore -from legendary.models.game import InstalledGame, SaveGameStatus -from rare import shared -from rare.components.dialogs.path_input_dialog import PathInputDialog - -logger = getLogger("Sync") - - -def get_raw_save_path(app_name, core): - game = core.lgd.get_game_meta(app_name) - save_path = game.metadata['customAttributes'].get('CloudSaveFolder', {}).get('value') - return save_path - - -class _UploadThread(QThread): - signal = pyqtSignal(bool) - - def __init__(self, app_name, date_time, save_path, core: LegendaryCore): - super(_UploadThread, self).__init__() - self.core = core - self.app_name = app_name - self.date_time = date_time - self.save_path = save_path - - def run(self) -> None: - try: - self.core.upload_save(self.app_name, self.save_path, self.date_time) - self.signal.emit(True) - except Exception as e: - logger.error(e) - self.signal.emit(False) - - -class _DownloadThread(QThread): - signal = pyqtSignal(bool) - - def __init__(self, app_name, latest_save, save_path, core: LegendaryCore): - super(_DownloadThread, self).__init__() - self.core = core - self.app_name = app_name - self.latest_save = latest_save - self.save_path = save_path - - def run(self) -> None: - try: - self.core.download_saves(self.app_name, self.latest_save.manifest_name, self.save_path, clean_dir=True) - self.signal.emit(True) - except Exception as e: - logger.error(e) - self.signal.emit(False) - - -class SyncWidget(QGroupBox): - reload = pyqtSignal(str) - - def __init__(self, igame: InstalledGame, save): - super(SyncWidget, self).__init__(igame.title) - self.setObjectName("group") - self.layout = QVBoxLayout() - self.setContentsMargins(10, 20, 10, 20) - self.thr = None - self.core = shared.core - self.save = save - self.logger = getLogger("Sync " + igame.app_name) - self.game = self.core.get_game(igame.app_name) - self.igame = igame - self.has_save_path = True - if not igame.save_path or igame.save_path is None: - try: - save_path = self.core.get_save_path(igame.app_name) - except Exception as e: - self.logger.error(e) - return - if '%' in save_path or '{' in save_path: - # status = self.tr("Path not found") - self.logger.info("Could not find save path") - igame.save_path = "" - - else: - igame.save_path = save_path - - if not igame.save_path: - igame.save_path = os.path.expanduser(f"~/{igame.app_name}/") - QMessageBox.warning(self, "Savepath error", - self.tr("Please edit save path of game {} manually in Cload saves tab").format( - igame.title)) - if igame.save_path and not os.path.exists(igame.save_path): - os.makedirs(igame.save_path) - self.core.lgd.set_installed_game(self.igame.app_name, self.igame) - - self.res, (self.dt_local, dt_remote) = self.core.check_savegame_state(igame.save_path, save) - if self.res == SaveGameStatus.NO_SAVE: - self.logger.debug('No cloud or local savegame found.') - return - - # game_title = QLabel(f"

{igame.title}

") - - if self.dt_local: - local_save_date = QLabel( - self.tr("Local Save date: ") + str(self.dt_local.strftime('%Y-%m-%d %H:%M:%S'))) - else: - local_save_date = QLabel(self.tr("No Local Save files")) - if dt_remote: - cloud_save_date = QLabel(self.tr("Cloud save date: ") + str(dt_remote.strftime('%Y-%m-%d %H:%M:%S'))) - else: - cloud_save_date = QLabel(self.tr("No Cloud saves")) - - if self.res == SaveGameStatus.SAME_AGE: - self.logger.debug(f'Save game for "{igame.title}" is up to date') - status = self.tr("Game is up to date") - self.upload_button = QPushButton(self.tr("Upload anyway")) - self.download_button = QPushButton(self.tr("Download anyway")) - elif self.res == SaveGameStatus.REMOTE_NEWER: - status = self.tr("Cloud save is newer") - self.download_button = QPushButton(self.tr("Download Cloud saves")) - self.download_button.setObjectName("success") - self.upload_button = QPushButton(self.tr("Upload Saves")) - self.logger.debug(f'Cloud save for "{igame.title}" is newer:') - self.logger.debug(f'- Cloud save date: {dt_remote.strftime("%Y-%m-%d %H:%M:%S")}') - if self.dt_local: - self.logger.debug(f'- Local save date: {self.dt_local.strftime("%Y-%m-%d %H:%M:%S")}') - else: - self.logger.debug('- Local save date: N/A') - self.upload_button.setDisabled(True) - self.upload_button.setToolTip("No local save") - - elif self.res == SaveGameStatus.LOCAL_NEWER: - status = self.tr("Local save is newer") - self.upload_button = QPushButton(self.tr("Upload saves")) - self.upload_button.setObjectName("success") - self.download_button = QPushButton(self.tr("Download saves")) - self.logger.info(f'Local save for "{igame.title}" is newer') - if dt_remote: - self.logger.debug(f'- Cloud save date: {dt_remote.strftime("%Y-%m-%d %H:%M:%S")}') - else: - self.logger.debug('- Cloud save date: N/A') - self.download_button.setDisabled(True) - self.logger.debug(f'- Local save date: {self.dt_local.strftime("%Y-%m-%d %H:%M:%S")}') - else: - self.logger.error(self.res) - return - - self.upload_button.clicked.connect(self.upload) - self.download_button.clicked.connect(self.download) - self.info_text = QLabel(status) - # self.layout.addWidget(game_title) - self.layout.addWidget(local_save_date) - self.layout.addWidget(cloud_save_date) - - save_path_layout = QHBoxLayout() - - self.raw_path = QLabel("Raw path: " + get_raw_save_path(self.game.app_name, self.core)) - self.raw_path.setTextInteractionFlags(Qt.TextSelectableByMouse) - self.layout.addWidget(self.raw_path) - - self.save_path_text = QLabel(igame.save_path) - self.save_path_text.setTextInteractionFlags(Qt.TextSelectableByMouse) - self.save_path_text.setWordWrap(True) - self.change_save_path = QPushButton(self.tr("Change path")) - self.change_save_path.setFixedWidth(100) - self.change_save_path.clicked.connect(self.change_path) - save_path_layout.addWidget(self.save_path_text) - save_path_layout.addWidget(self.change_save_path) - self.layout.addLayout(save_path_layout) - self.layout.addWidget(self.info_text) - button_layout = QHBoxLayout() - button_layout.addWidget(self.upload_button) - button_layout.addWidget(self.download_button) - self.layout.addLayout(button_layout) - self.layout.addStretch(1) - self.setLayout(self.layout) - - if self.res == SaveGameStatus.REMOTE_NEWER: - settings = QSettings() - if settings.value(f"{igame.app_name}/auto_sync_cloud", False, bool): - self.download() - - def change_path(self): - path = PathInputDialog("Select directory", "Select savepath. Warning: Do not change if you are not sure", - self.igame.save_path).get_path() - if path != "": - self.igame.save_path = path - self.core.lgd.set_installed_game(self.igame.app_name, self.igame) - self.save_path_text.setText(self.igame.save_path) - self.reload.emit(self.game.app_name) - - def upload(self): - self.logger.info("Uploading Saves for game " + self.igame.title) - self.info_text.setText(self.tr("Uploading...")) - self.upload_button.setDisabled(True) - self.download_button.setDisabled(True) - self.thr = _UploadThread(self.igame.app_name, self.dt_local, self.igame.save_path, self.core) - self.thr.signal.connect(self.uploaded) - self.thr.start() - - def uploaded(self, success: bool): - if success: - self.info_text.setText(self.tr("Upload finished")) - - else: - self.info_text.setText(self.tr("Upload failed")) - self.upload_button.setDisabled(False) - self.reload.emit(self.game.app_name) - - def download(self): - if not os.path.exists(self.igame.save_path): - os.makedirs(self.igame.save_path) - self.upload_button.setDisabled(True) - self.download_button.setDisabled(True) - self.logger.info("Downloading Saves for game " + self.igame.title) - self.info_text.setText(self.tr("Downloading...")) - self.thr = _DownloadThread(self.igame.app_name, self.save, self.igame.save_path, self.core) - self.thr.signal.connect(self.downloaded) - self.thr.start() - - def downloaded(self, success: bool): - if success: - self.info_text.setText(self.tr("Download finished")) - self.upload_button.setDisabled(True) - self.download_button.setDisabled(True) - self.download_button.setStyleSheet("QPushButton{background-color: black}") - self.reload.emit(self.game.app_name) - else: - self.info_text.setText("Error while downloading save") - self.download_button.setStyleSheet("QPushButton{background-color: black}") diff --git a/rare/components/tabs/games/__init__.py b/rare/components/tabs/games/__init__.py index 18a73282..7bc61ae9 100644 --- a/rare/components/tabs/games/__init__.py +++ b/rare/components/tabs/games/__init__.py @@ -103,6 +103,8 @@ class GamesTab(QStackedWidget, Ui_GamesTab): self.signals.installation_finished.connect(lambda x: self.installing_widget.setVisible(False)) self.signals.uninstall_game.connect(self.uninstall_game) + self.game_list_scroll_area.horizontalScrollBar().setDisabled(True) + def installation_started(self, app_name: str): game = self.core.get_game(app_name, False) if game.is_dlc: @@ -115,7 +117,9 @@ class GamesTab(QStackedWidget, Ui_GamesTab): i_widget, l_widget = self.widgets[igame.app_name] i_widget.igame = igame l_widget.igame = igame - i_widget.info_text = "" + + i_widget.leaveEvent(None) + l_widget.update_text() def uninstall_game(self, game: Game): infos = UninstallDialog(game).get_information() @@ -269,11 +273,8 @@ class GamesTab(QStackedWidget, Ui_GamesTab): igame = self.core.get_installed_game(app_name) for w in widgets: w.igame = igame - w.update_available = self.core.get_asset(w.game.app_name, - True).build_version != igame.version - widgets[0].info_label.setText("") - widgets[0].info_text = "" - + w.update_available = self.core.get_asset(w.game.app_name, True).build_version != igame.version + widgets[0].leaveEvent(None) # new installed elif self.core.is_installed(app_name) and isinstance(widgets[0], BaseUninstalledWidget): logger.debug("Update Gamelist: New installed " + app_name) @@ -405,3 +406,5 @@ class GamesTab(QStackedWidget, Ui_GamesTab): else: self.scroll_widget.layout().replaceWidget(self.icon_view, self.list_view) self.icon_view.setParent(None) + + self.game_list_scroll_area.verticalScrollBar().setValue(0) diff --git a/rare/components/tabs/games/cloud_save_utils.py b/rare/components/tabs/games/cloud_save_utils.py index 5c9b6685..7a1faff7 100644 --- a/rare/components/tabs/games/cloud_save_utils.py +++ b/rare/components/tabs/games/cloud_save_utils.py @@ -123,9 +123,6 @@ class CloudSaveUtils(QObject): igame = self.core.get_installed_game(app_name) res, (dt_local, dt_remote) = self.core.check_savegame_state(igame.save_path, self.latest_saves.get(app_name)) - # maybe i will add this - # if res == SaveGameStatus.REMOTE_NEWER: - # self.download_saves() if res != SaveGameStatus.SAME_AGE: newer = None if res == SaveGameStatus.REMOTE_NEWER: diff --git a/rare/components/tabs/games/game_utils.py b/rare/components/tabs/games/game_utils.py index 619a51a9..09bcf61e 100644 --- a/rare/components/tabs/games/game_utils.py +++ b/rare/components/tabs/games/game_utils.py @@ -34,7 +34,7 @@ class RunningGameModel: class GameUtils(QObject): running_games = dict() - finished = pyqtSignal(str) + finished = pyqtSignal(str, str) cloud_save_finished = pyqtSignal(str) launch_queue = dict() @@ -78,12 +78,15 @@ class GameUtils(QObject): else: if not game: logger.error("Game not found") + self.finished.emit(app_name, self.tr("Game not found in available games")) return if game.is_dlc: logger.error("Game is dlc") + self.finished.emit(app_name, self.tr("Game is a DLC. Please launch base game instead")) return if not os.path.exists(igame.install_path): logger.error("Game doesn't exist") + self.finished.emit(app_name, self.tr("Game files of {} do not exist. Please install game")) return process = GameProcess(app_name) @@ -96,11 +99,11 @@ class GameUtils(QObject): try: latest = self.core.get_asset(app_name, update=True) except ValueError: - print("Metadata doesn't exist") - return None + self.finished.emit(app_name, self.tr("Metadata doesn't exist")) + return if latest.build_version != igame.version: - print("Please update game") - return None + self.finished.emit(app_name, self.tr("Please update game")) + return params: LaunchParameters = self.core.get_launch_parameters(app_name=app_name, offline=offline, wine_bin=wine_bin, wine_pfx=wine_pfx) @@ -130,6 +133,7 @@ class GameUtils(QObject): logger.info("Launch Origin Game: ") if platform.system() == "Windows": webbrowser.open(origin_uri) + self.finished.emit(app_name, "") return wine_pfx = self.core.lgd.config.get(self.game.app_name, 'wine_prefix', fallback=os.path.expanduser("~/.wine")) @@ -137,9 +141,10 @@ class GameUtils(QObject): wine_bin = self.core.lgd.config.get(self.game.app_name, 'wine_executable', fallback="/usr/bin/wine") env = self.core.get_app_environment(self.game.app_name, wine_pfx=wine_pfx) - if not wine_bin or not env.get('WINEPREFIX'): + if not wine_bin or not env.get('WINEPREFIX') and not os.path.exists("/usr/bin/wine"): logger.error(f'In order to launch Origin correctly you must specify the wine binary and prefix ' f'to use in the configuration file or command line. See the README for details.') + self.finished.emit(app_name, self.tr("No wine executable selected. Please set it in settings")) return environment = QProcessEnvironment() @@ -175,7 +180,7 @@ class GameUtils(QObject): webbrowser.open("https://www.dm.origin.com/download") self.running_games.pop(app_name) - self.finished.emit(app_name) + self.finished.emit(app_name, "") if QSettings().value("show_console", False, bool): self.console.log(f"Game exited with code: {exit_code}") diff --git a/rare/components/tabs/games/game_widgets/base_installed_widget.py b/rare/components/tabs/games/game_widgets/base_installed_widget.py index 465af8ce..f31b38bf 100644 --- a/rare/components/tabs/games/game_widgets/base_installed_widget.py +++ b/rare/components/tabs/games/game_widgets/base_installed_widget.py @@ -26,13 +26,29 @@ class BaseInstalledWidget(QGroupBox): self.core = shared.core self.game_utils = game_utils self.game_utils.cloud_save_finished.connect(self.sync_finished) - self.sync_cloud_saves = False + self.syncing_cloud_saves = False + + self.texts = { + "needs_verification": self.tr("Please verify game before playing"), + "hover": { + "update_available": self.tr("Start game without version check"), + "launch": self.tr("Launch Game"), + "launch_origin": self.tr("Launch/Link"), + "running": self.tr("Game running") + }, + "default": { + "running": self.tr("Game running"), + "syncing": self.tr("Syncing cloud saves"), + "update_available": self.tr("Update available") + } + } self.game = self.core.get_game(app_name) if self.game.third_party_store != "Origin": self.igame = self.core.get_installed_game(app_name) self.is_origin = False else: + self.igame = None self.is_origin = True self.image = QLabel() @@ -129,13 +145,19 @@ class BaseInstalledWidget(QGroupBox): self.create_start_menu.setText(self.tr("Create Start menu link")) def launch(self, offline=False, skip_version_check=False): - if self.game.supports_cloud_saves: - self.sync_cloud_saves = True - self.game_utils.launch_game(self.game.app_name, offline=offline, skip_update_check=skip_version_check) + if not self.game_running: + if self.game.supports_cloud_saves: + self.syncing_cloud_saves = True + self.game_utils.prepare_launch(self.game.app_name, offline, skip_version_check) def sync_finished(self, app_name): if app_name == self.game.app_name: - self.sync_cloud_saves = False + self.syncing_cloud_saves = False def sync_game(self): - self.game_utils.cloud_save_utils.sync_before_launch_game(self.game.app_name) + if self.game_utils.cloud_save_utils.sync_before_launch_game(self.game.app_name): + self.syncing_cloud_saves = True + + def game_finished(self, app_name, error): + if error: + QMessageBox.warning(self, "Error", error) diff --git a/rare/components/tabs/games/game_widgets/installed_icon_widget.py b/rare/components/tabs/games/game_widgets/installed_icon_widget.py index 4e00ca94..42f78332 100644 --- a/rare/components/tabs/games/game_widgets/installed_icon_widget.py +++ b/rare/components/tabs/games/game_widgets/installed_icon_widget.py @@ -21,12 +21,9 @@ class InstalledIconWidget(BaseInstalledWidget): self.setContextMenuPolicy(Qt.ActionsContextMenu) self.layout = QVBoxLayout() self.core = shared.core - self.running = False - self.info_text = "" if self.update_available: logger.info("Update available for game: " + self.game.app_name) - self.info_text = self.tr("Update available") self.layout.addWidget(self.image) @@ -45,9 +42,8 @@ class InstalledIconWidget(BaseInstalledWidget): self.menu_btn.setIcon(icon("ei.info-circle")) # self.menu_btn.setObjectName("installed_menu_button") self.menu_btn.setIconSize(QSize(18, 18)) - self.menu_btn.enterEvent = lambda x: self.info_label.setText("Information") - self.menu_btn.leaveEvent = lambda x: self.info_label.setText( - "Please update Game") if self.update_available else self.info_label.setText("Start Game") + self.menu_btn.enterEvent = lambda x: self.info_label.setText(self.tr("Information")) + self.menu_btn.leaveEvent = lambda x: self.enterEvent(None) # remove Border self.menu_btn.setObjectName("menu_button") @@ -58,33 +54,37 @@ class InstalledIconWidget(BaseInstalledWidget): minilayout.addStretch(1) self.layout.addLayout(minilayout) - self.info_label = QLabel(self.info_text) + self.info_label = QLabel("") + self.leaveEvent(None) self.info_label.setAutoFillBackground(False) self.info_label.setObjectName("info_label") self.layout.addWidget(self.info_label) if not self.is_origin and self.igame.needs_verification: - self.info_text = self.tr("Game needs verification") - self.info_label.setText(self.info_text) + self.info_label.setText(self.texts["needs_verification"]) self.setLayout(self.layout) self.setFixedWidth(self.sizeHint().width()) - def enterEvent(self, a0: QEvent) -> None: + def enterEvent(self, a0: QEvent = None) -> None: if self.game_running: - self.info_label.setText(self.tr("Game running")) + self.info_label.setText(self.texts["hover"]["running"]) elif not self.is_origin and self.igame.needs_verification: - self.info_label.setText(self.tr("Please verify game before playing")) + self.info_label.setText(self.texts["hover"]["needs_verification"]) elif self.update_available: - self.info_label.setText(self.tr("Start game without version check")) + self.info_label.setText(self.texts["hover"]["update_available"]) else: - self.info_label.setText(self.tr("Start Game") if not self.is_origin else self.tr("Launch/Link")) + self.info_label.setText(self.texts["hover"]["launch" if not self.is_origin else "launch_origin"]) - def leaveEvent(self, a0: QEvent) -> None: - if self.running: - self.info_label.setText(self.tr("Game running")) + def leaveEvent(self, a0: QEvent = None) -> None: + if self.game_running: + self.info_label.setText(self.texts["default"]["running"]) + elif self.syncing_cloud_saves: + self.info_label.setText(self.texts["default"]["syncing"]) + elif self.update_available: + self.info_label.setText(self.texts["default"]["update_available"]) else: - self.info_label.setText(self.info_text) + self.info_label.setText("") def mousePressEvent(self, e: QMouseEvent): # left button @@ -100,9 +100,10 @@ class InstalledIconWidget(BaseInstalledWidget): elif e.button() == 2: pass # self.showMenu(e) - def game_finished(self, app_name): + def game_finished(self, app_name, error): if app_name != self.game.app_name: return - self.info_text = "" - self.info_label.setText("") + super().game_finished(app_name, error) + + self.leaveEvent(None) diff --git a/rare/components/tabs/games/game_widgets/installed_list_widget.py b/rare/components/tabs/games/game_widgets/installed_list_widget.py index f438eea3..de938a30 100644 --- a/rare/components/tabs/games/game_widgets/installed_list_widget.py +++ b/rare/components/tabs/games/game_widgets/installed_list_widget.py @@ -32,17 +32,22 @@ class InstalledListWidget(BaseInstalledWidget): self.layout.addWidget(self.image) play_icon = icon("ei.play") - self.title_widget = QLabel(f"

{self.game.app_title}

") + self.title_label = QLabel(f"

{self.game.app_title}

") + self.title_label.setWordWrap(True) + self.childLayout.addWidget(self.title_label) self.app_name_label = QLabel(self.game.app_name) self.launch_button = QPushButton(play_icon, self.tr("Launch") if not self.is_origin else self.tr("Link/Play")) self.launch_button.setObjectName("launch_game_button") - self.launch_button.setFixedWidth(120) + self.launch_button.setFixedWidth(150) self.info = QPushButton("Info") self.info.clicked.connect(lambda: self.show_info.emit(self.game)) self.info.setFixedWidth(80) - self.childLayout.addWidget(self.title_widget) + self.info_label = QLabel("") + self.childLayout.addWidget(self.info_label) + self.update_text() + self.launch_button.clicked.connect(self.launch) self.childLayout.addWidget(self.launch_button) @@ -57,15 +62,22 @@ class InstalledListWidget(BaseInstalledWidget): self.childLayout.addWidget(self.version_label) self.childLayout.addWidget(self.size_label) - self.info_label = QLabel("") - self.childLayout.addWidget(self.info_label) - # self.childLayout.addWidget(QPushButton("Settings")) - # self.childLayout.addWidget(QPushButton("Uninstall")) self.childLayout.addStretch(1) self.layout.addLayout(self.childLayout) self.layout.addStretch(1) self.setLayout(self.layout) - def launch(self): - if not self.game_running: - super(InstalledListWidget, self).launch(skip_version_check=self.update_available) + self.game_utils.cloud_save_finished.connect(self.sync_finished) + + self.leaveEvent = self.update_text + self.enterEvent = self.update_text + + def update_text(self, e=None): + if self.update_available: + self.info_label.setText(self.texts["default"]["update_available"]) + elif self.igame and self.igame.needs_verification: + self.info_label.setText(self.texts["needs_verification"]) + elif self.syncing_cloud_saves: + self.info_label.setText(self.texts["default"]["syncing"]) + else: + self.info_label.setText("") diff --git a/rare/components/tabs/tab_widget.py b/rare/components/tabs/tab_widget.py index a3e7d384..e69de29b 100644 --- a/rare/components/tabs/tab_widget.py +++ b/rare/components/tabs/tab_widget.py @@ -1,100 +0,0 @@ -from PyQt5.QtCore import QSize, pyqtSignal -from PyQt5.QtWidgets import QMenu, QTabWidget, QWidget, QWidgetAction, QShortcut -from qtawesome import icon - -from rare import shared -from rare.components.tabs.account import MiniWidget -from rare.components.tabs.downloads import DownloadTab -from rare.components.tabs.games import GamesTab -from rare.components.tabs.settings import SettingsTab -from rare.components.tabs.settings.debug import DebugSettings -from rare.components.tabs.shop import Shop -from rare.components.tabs.tab_utils import TabBar, TabButtonWidget - - -class TabWidget(QTabWidget): - delete_presence = pyqtSignal() - - def __init__(self, parent): - super(TabWidget, self).__init__(parent=parent) - disabled_tab = 3 if not shared.args.offline else 1 - self.core = shared.core - self.signals = shared.signals - self.setTabBar(TabBar(disabled_tab)) - # Generate Tabs - self.games_tab = GamesTab() - self.addTab(self.games_tab, self.tr("Games")) - if not shared.args.offline: - # updates = self.games_tab.default_widget.game_list.updates - self.downloadTab = DownloadTab(self.games_tab.updates) - self.addTab(self.downloadTab, "Downloads" + ( - " (" + str(len(self.games_tab.updates)) + ")" if len(self.games_tab.updates) != 0 else "")) - self.store = Shop(self.core) - self.addTab(self.store, self.tr("Store (Beta)")) - self.settings = SettingsTab(self) - - if shared.args.debug: - self.settings.addTab(DebugSettings(), "Debug") - - # Space Tab - self.addTab(QWidget(), "") - self.setTabEnabled(disabled_tab, False) - # Button - self.account = QWidget() - self.addTab(self.account, "") - self.setTabEnabled(disabled_tab + 1, False) - - self.mini_widget = MiniWidget() - account_action = QWidgetAction(self) - account_action.setDefaultWidget(self.mini_widget) - account_button = TabButtonWidget('mdi.account-circle', 'Account') - account_button.setMenu(QMenu()) - account_button.menu().addAction(account_action) - self.tabBar().setTabButton(disabled_tab + 1, self.tabBar().RightSide, account_button) - - self.addTab(self.settings, icon("fa.gear"), - "(!)" if self.settings.about.update_available else "") - - # Signals - # set current index - self.signals.set_main_tab_index.connect(self.setCurrentIndex) - - # update dl tab text - self.signals.update_download_tab_text.connect(self.update_dl_tab_text) - - # Open game list on click on Games tab button - self.tabBarClicked.connect(self.mouse_clicked) - self.setIconSize(QSize(25, 25)) - - # shortcuts - QShortcut("Alt+1", self).activated.connect(lambda: self.setCurrentIndex(0)) - QShortcut("Alt+2", self).activated.connect(lambda: self.setCurrentIndex(1)) - QShortcut("Alt+3", self).activated.connect(lambda: self.setCurrentIndex(2)) - QShortcut("Alt+4", self).activated.connect(lambda: self.setCurrentIndex(5)) - - def update_dl_tab_text(self): - num_downloads = len(set([i.options.app_name for i in self.downloadTab.dl_queue] + [i for i in - self.downloadTab.update_widgets.keys()])) - - if num_downloads != 0: - self.setTabText(1, f"Downloads ({num_downloads})") - else: - self.setTabText(1, "Downloads") - - def mouse_clicked(self, tab_num): - if tab_num == 0: - self.games_tab.layout().setCurrentIndex(0) - - if not shared.args.offline and tab_num == 3: - self.store.load() - - def resizeEvent(self, event): - self.tabBar().setMinimumWidth(self.width()) - super(TabWidget, self).resizeEvent(event) - - # Remove text "sync game" - def finished_sync(self, app_name): - if self.core.is_installed(app_name): - self.games_tab.widgets[app_name][0].info_text = "" - self.games_tab.widgets[app_name][0].info_label.setText("") - self.games_tab.widgets[app_name][1].info_label.setText("")