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("")