Download Games, update List
This commit is contained in:
parent
a566e836e5
commit
75b39cb189
|
@ -2,4 +2,4 @@
|
|||
GUI for legendary. An Epic Games Launcher open source alternative
|
||||
|
||||
## This is a new version with better Styles. It has not many features, but i work on it.
|
||||
It will take some time, because I want to reinmplement some features on a smoother way.
|
||||
It will take some time, because I want to reimplement some features on a smoother way.
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QTabWidget, QTabBar, QWidget, QToolButton, QWidgetAction, QMenu
|
||||
|
||||
from Rare import style_path
|
||||
from Rare.Components.Tabs.Account.AccountWidget import MiniWidget
|
||||
from Rare.Components.Tabs.Games.Games import Games
|
||||
from Rare.Components.Tabs.Downloads.DownloadTab import DownloadTab
|
||||
from Rare.Components.Tabs.Games.GamesTab import Games
|
||||
|
||||
|
||||
class TabWidget(QTabWidget):
|
||||
|
@ -11,12 +13,12 @@ class TabWidget(QTabWidget):
|
|||
self.setTabBar(TabBar(2))
|
||||
|
||||
self.game_list = Games(core)
|
||||
|
||||
self.addTab(self.game_list, self.tr("Games"))
|
||||
|
||||
self.downloads = QWidget()
|
||||
self.addTab(self.downloads, "Downloads")
|
||||
|
||||
self.downloadTab = DownloadTab(core)
|
||||
self.addTab(self.downloadTab, "Downloads")
|
||||
self.downloadTab.finished.connect(self.game_list.game_list.update_list)
|
||||
self.game_list.game_list.install_game.connect(lambda x: self.downloadTab.install_game(x))
|
||||
# Space Tab
|
||||
self.addTab(QWidget(), "")
|
||||
self.setTabEnabled(2, False)
|
||||
|
@ -35,9 +37,6 @@ class TabWidget(QTabWidget):
|
|||
self.tabBar().setMinimumWidth(self.width())
|
||||
super(TabWidget, self).resizeEvent(event)
|
||||
|
||||
def download(self):
|
||||
self.downloads.download()
|
||||
|
||||
|
||||
class TabBar(QTabBar):
|
||||
def __init__(self, expanded):
|
||||
|
@ -59,7 +58,7 @@ class TabButtonWidget(QToolButton):
|
|||
super(TabButtonWidget, self).__init__()
|
||||
self.setText("Icon")
|
||||
self.setPopupMode(QToolButton.InstantPopup)
|
||||
self.setIcon(QIcon(style_path+"/Icons/account.png"))
|
||||
self.setIcon(QIcon(style_path + "/Icons/account.png"))
|
||||
self.setToolTip("Account")
|
||||
self.setMenu(QMenu())
|
||||
action = QWidgetAction(self)
|
||||
|
|
|
@ -1,6 +1,152 @@
|
|||
from PyQt5.QtWidgets import QWidget
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QVBoxLayout, QLabel, QGridLayout, QProgressBar
|
||||
from legendary.core import LegendaryCore
|
||||
|
||||
from Rare.utils.Dialogs.InstallDialog import InstallInfoDialog
|
||||
|
||||
logger = getLogger("Download")
|
||||
|
||||
|
||||
class DownloadThread(QThread):
|
||||
status = pyqtSignal(str)
|
||||
|
||||
def __init__(self, dlm, core: LegendaryCore, igame):
|
||||
super(DownloadThread, self).__init__()
|
||||
self.dlm = dlm
|
||||
self.core = core
|
||||
self.igame = igame
|
||||
|
||||
def run(self):
|
||||
start_time = time.time()
|
||||
try:
|
||||
|
||||
self.dlm.start()
|
||||
self.dlm.join()
|
||||
except:
|
||||
logger.error(f"Installation failed after{time.time() - start_time:.02f} seconds.")
|
||||
self.status.emit("error")
|
||||
return
|
||||
|
||||
else:
|
||||
self.status.emit("dl_finished")
|
||||
end_t = time.time()
|
||||
game = self.core.get_game(self.igame.app_name)
|
||||
postinstall = self.core.install_game(self.igame)
|
||||
if postinstall:
|
||||
self._handle_postinstall(postinstall, self.igame)
|
||||
dlcs = self.core.get_dlc_for_game(self.igame.app_name)
|
||||
if dlcs:
|
||||
print('The following DLCs are available for this game:')
|
||||
for dlc in dlcs:
|
||||
print(f' - {dlc.app_title} (App name: {dlc.app_name}, version: {dlc.app_version})')
|
||||
print('Manually installing DLCs works the same; just use the DLC app name instead.')
|
||||
|
||||
# install_dlcs = QMessageBox.question(self, "", "Do you want to install the prequisites", QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes
|
||||
# TODO
|
||||
if game.supports_cloud_saves and not game.is_dlc:
|
||||
logger.info('This game supports cloud saves, syncing is handled by the "sync-saves" command.')
|
||||
logger.info(f'To download saves for this game run "legendary sync-saves {game.app_name}"')
|
||||
|
||||
self.status.emit("finish")
|
||||
|
||||
def _handle_postinstall(self, postinstall, igame):
|
||||
print('This game lists the following prequisites to be installed:')
|
||||
print(f'- {postinstall["name"]}: {" ".join((postinstall["path"], postinstall["args"]))}')
|
||||
if os.name == 'nt':
|
||||
if QMessageBox.question(self, "", "Do you want to install the prequisites",
|
||||
QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
|
||||
self.core.prereq_installed(igame.app_name)
|
||||
req_path, req_exec = os.path.split(postinstall['path'])
|
||||
work_dir = os.path.join(igame.install_path, req_path)
|
||||
fullpath = os.path.join(work_dir, req_exec)
|
||||
subprocess.call([fullpath, postinstall['args']], cwd=work_dir)
|
||||
else:
|
||||
self.core.prereq_installed(self.igame.app_name)
|
||||
|
||||
else:
|
||||
logger.info('Automatic installation not available on Linux.')
|
||||
|
||||
|
||||
class DownloadTab(QWidget):
|
||||
def __init__(self):
|
||||
finished = pyqtSignal()
|
||||
thread: QThread
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(DownloadTab, self).__init__()
|
||||
self.core = core
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
self.installing_game = QLabel("Installing Game: None")
|
||||
self.dl_speed = QLabel("Download speed: 0MB/s")
|
||||
self.cache_used = QLabel("Cache used: 0MB")
|
||||
self.downloaded = QLabel("Downloaded: 0MB")
|
||||
|
||||
self.info_layout = QGridLayout()
|
||||
|
||||
self.info_layout.addWidget(self.installing_game, 0, 0)
|
||||
self.info_layout.addWidget(self.dl_speed, 0, 1)
|
||||
self.info_layout.addWidget(self.cache_used, 1,0)
|
||||
self.info_layout.addWidget(self.downloaded, 1,1)
|
||||
|
||||
self.layout.addLayout(self.info_layout)
|
||||
self.prog_bar = QProgressBar()
|
||||
self.layout.addWidget(self.prog_bar)
|
||||
|
||||
self.layout.addWidget(QLabel("WARNING: This feature is not implemented. It is normal, if there is no progress. The progress is in console"))
|
||||
|
||||
self.installing_game_widget = QLabel("No active Download")
|
||||
self.layout.addWidget(self.installing_game_widget)
|
||||
|
||||
self.layout.addStretch(1)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def install_game(self, options: {}):
|
||||
game = self.core.get_game(options["app_name"])
|
||||
dlm, analysis, igame = self.core.prepare_download(
|
||||
game=game,
|
||||
base_path=options["options"]["path"],
|
||||
max_workers=options["options"]["max_workers"])
|
||||
if not analysis.dl_size:
|
||||
QMessageBox.information(self, "Warning", "Download size is 0")
|
||||
return
|
||||
# Information
|
||||
if not InstallInfoDialog(dl_size=analysis.dl_size, install_size=analysis.install_size).get_accept():
|
||||
return
|
||||
|
||||
self.installing_game_widget.setText("")
|
||||
self.installing_game.setText("Installing Game: "+ game.app_title)
|
||||
res = self.core.check_installation_conditions(analysis=analysis, install=igame, game=game,
|
||||
updating=self.core.is_installed(options["app_name"]),
|
||||
)
|
||||
if res.warnings:
|
||||
for w in sorted(res.warnings):
|
||||
logger.warning(w)
|
||||
if res.failures:
|
||||
for msg in sorted(res.failures):
|
||||
logger.error(msg)
|
||||
logger.error('Installation cannot proceed, exiting.')
|
||||
QMessageBox.warning(self, "Installation failed", "Installation failed. See logs for more information")
|
||||
return
|
||||
|
||||
self.thread = DownloadThread(dlm, self.core, igame)
|
||||
self.thread.status.connect(self.status)
|
||||
self.thread.start()
|
||||
|
||||
def status(self, text):
|
||||
if text == "dl_finished":
|
||||
pass
|
||||
elif text == "finish":
|
||||
QMessageBox.information(self, "Info", "Download finished")
|
||||
self.finished.emit()
|
||||
self.installing_game.setText("Installing Game: No running download")
|
||||
elif text == "error":
|
||||
QMessageBox.warning(self, "warn", "Download error")
|
||||
|
||||
def update_game(self, app_name: str):
|
||||
print("Update ", app_name)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from PyQt5.QtWidgets import *
|
||||
from legendary.core import LegendaryCore
|
||||
|
||||
|
@ -8,30 +8,45 @@ from Rare.utils.QtExtensions import FlowLayout
|
|||
|
||||
|
||||
class GameList(QScrollArea):
|
||||
install_game = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(GameList, self).__init__()
|
||||
self.core = core
|
||||
self.widget = QWidget()
|
||||
self .setObjectName("list_widget")
|
||||
self.widgets = []
|
||||
|
||||
self.setObjectName("list_widget")
|
||||
self.setWidgetResizable(True)
|
||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
self.init_ui()
|
||||
|
||||
|
||||
def init_ui(self):
|
||||
self.widget = QWidget()
|
||||
self.widgets=[]
|
||||
self.layout = FlowLayout()
|
||||
|
||||
for i in self.core.get_installed_list():
|
||||
# Installed Games
|
||||
for game in self.core.get_installed_list():
|
||||
# continue
|
||||
self.layout.addWidget(GameWidgetInstalled(core, i))
|
||||
widget = GameWidgetInstalled(self.core, game)
|
||||
self.layout.addWidget(widget)
|
||||
widget.update_list.connect(self.update_list)
|
||||
|
||||
uninstalled_games = []
|
||||
installed = [i.app_name for i in core.get_installed_list()]
|
||||
for game in sorted(core.get_game_list(), key=lambda x: x.app_title):
|
||||
installed = []
|
||||
installed = [i.app_name for i in self.core.get_installed_list()]
|
||||
print(len(installed))
|
||||
# get Uninstalled games
|
||||
print(len(self.core.get_game_list()))
|
||||
for game in sorted(self.core.get_game_list(), key=lambda x: x.app_title):
|
||||
if not game.app_name in installed:
|
||||
uninstalled_games.append(game)
|
||||
self.widgets = []
|
||||
|
||||
for i in uninstalled_games:
|
||||
widget = GameWidgetUninstalled(core, i)
|
||||
# add uninstalled to gui
|
||||
print(len(uninstalled_games))
|
||||
for game in uninstalled_games:
|
||||
widget = GameWidgetUninstalled(self.core, game)
|
||||
widget.install_game.connect(lambda options: self.install_game.emit(options))
|
||||
self.layout.addWidget(widget)
|
||||
self.widgets.append(widget)
|
||||
|
||||
|
@ -49,3 +64,10 @@ class GameList(QScrollArea):
|
|||
# TODO save state
|
||||
for w in self.widgets:
|
||||
w.setVisible(not i_o)
|
||||
|
||||
def update_list(self):
|
||||
print("Updating List")
|
||||
self.setWidget(QWidget())
|
||||
self.core.login()
|
||||
self.init_ui()
|
||||
self.update()
|
|
@ -1,8 +1,8 @@
|
|||
import os
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import Qt, QEvent
|
||||
from PyQt5.QtGui import QPixmap, QIcon, QMouseEvent
|
||||
from PyQt5.QtCore import QEvent, pyqtSignal
|
||||
from PyQt5.QtGui import QPixmap, QIcon
|
||||
from PyQt5.QtWidgets import *
|
||||
from legendary.core import LegendaryCore
|
||||
from legendary.models.game import InstalledGame
|
||||
|
@ -16,6 +16,8 @@ logger = getLogger("GameWidgetInstalled")
|
|||
|
||||
|
||||
class GameWidgetInstalled(QWidget):
|
||||
update_list = pyqtSignal()
|
||||
|
||||
def __init__(self, core: LegendaryCore, game: InstalledGame):
|
||||
super(GameWidgetInstalled, self).__init__()
|
||||
self.setObjectName("game_widget_parent")
|
||||
|
@ -26,7 +28,7 @@ class GameWidgetInstalled(QWidget):
|
|||
|
||||
self.update_available = self.core.get_asset(self.game.app_name, True).build_version != game.version
|
||||
if self.update_available:
|
||||
logger.info("Update available for game: "+ self.game.app_name)
|
||||
logger.info("Update available for game: " + self.game.app_name)
|
||||
|
||||
if os.path.exists(f"{IMAGE_DIR}/{game.app_name}/FinalArt.png"):
|
||||
pixmap = QPixmap(f"{IMAGE_DIR}/{game.app_name}/FinalArt.png")
|
||||
|
@ -40,7 +42,6 @@ class GameWidgetInstalled(QWidget):
|
|||
if pixmap:
|
||||
w = 200
|
||||
pixmap = pixmap.scaled(w, int(w * 4 / 3))
|
||||
|
||||
self.image = ClickableLabel()
|
||||
self.image.setObjectName("game_widget")
|
||||
self.image.setPixmap(pixmap)
|
||||
|
@ -53,11 +54,13 @@ class GameWidgetInstalled(QWidget):
|
|||
self.title_label.setObjectName("game_widget")
|
||||
minilayout.addWidget(self.title_label)
|
||||
# minilayout.addStretch(1)
|
||||
self.menu = QPushButton(QIcon(style_path + "/Icons/menu.png"), "")
|
||||
self.menu.setMenu(Menu())
|
||||
self.menu.setObjectName("menu")
|
||||
self.menu.setFixedWidth(10)
|
||||
minilayout.addWidget(self.menu)
|
||||
self.menu_btn = QPushButton(QIcon(style_path + "/Icons/menu.png"), "")
|
||||
self.menu = Menu()
|
||||
self.menu.action.connect(self.menu_action)
|
||||
self.menu_btn.setMenu(self.menu)
|
||||
self.menu_btn.setObjectName("menu")
|
||||
self.menu_btn.setFixedWidth(10)
|
||||
minilayout.addWidget(self.menu_btn)
|
||||
minilayout.addStretch(1)
|
||||
self.layout.addLayout(minilayout)
|
||||
|
||||
|
@ -93,11 +96,22 @@ class GameWidgetInstalled(QWidget):
|
|||
self.info_label.setText("")
|
||||
self.running = False
|
||||
|
||||
def menu_action(self, action: str):
|
||||
if action == "uninstall":
|
||||
if QMessageBox.question(self, "Uninstall", f"Do you want to uninstall {self.game.title}",
|
||||
QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
|
||||
logger.info("Uninstalling " + self.game.title)
|
||||
self.core.uninstall_game(self.game)
|
||||
self.update_list.emit()
|
||||
|
||||
|
||||
class Menu(QMenu):
|
||||
action = pyqtSignal(str)
|
||||
|
||||
def __init__(self):
|
||||
super(Menu, self).__init__()
|
||||
self.addAction("Game info", self.info)
|
||||
self.addAction("Uninstall", self.uninstall)
|
||||
self.addAction("Game info", lambda: self.action.emit("info"))
|
||||
self.addAction("Uninstall", lambda: self.action.emit("uninstall"))
|
||||
|
||||
def info(self):
|
||||
pass
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import os
|
||||
from logging import getLogger
|
||||
from multiprocessing import Queue as MPQueue
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QInputDialog
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel
|
||||
from legendary.core import LegendaryCore
|
||||
from legendary.models.game import Game
|
||||
|
||||
|
@ -14,6 +16,8 @@ logger = getLogger("Uninstalled")
|
|||
|
||||
|
||||
class GameWidgetUninstalled(QWidget):
|
||||
install_game = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, core: LegendaryCore, game: Game):
|
||||
super(GameWidgetUninstalled, self).__init__()
|
||||
self.layout = QVBoxLayout()
|
||||
|
@ -57,7 +61,16 @@ class GameWidgetUninstalled(QWidget):
|
|||
|
||||
def install(self):
|
||||
logger.info("Install " + self.game.app_title)
|
||||
|
||||
|
||||
infos = InstallDialog().get_information()
|
||||
if infos != 0:
|
||||
path, max_workers = infos
|
||||
print(path, max_workers)
|
||||
self.install_game.emit({
|
||||
"app_name": self.game.app_name,
|
||||
"options": {
|
||||
"path": path,
|
||||
"max_workers": max_workers
|
||||
}
|
||||
})
|
||||
# wait for update of legendary to get progress
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QLineEdit, QLabel
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QLineEdit, QLabel, QPushButton, QStyle
|
||||
|
||||
from Rare.Components.Tabs.Games.GameList import GameList
|
||||
|
||||
|
@ -12,13 +12,13 @@ class Games(QWidget):
|
|||
self.head_bar.setObjectName("head_bar")
|
||||
self.game_list = GameList(core)
|
||||
|
||||
|
||||
self.head_bar.search_bar.textChanged.connect(
|
||||
lambda: self.game_list.filter(self.head_bar.search_bar.text()))
|
||||
|
||||
self.head_bar.installed_only.stateChanged.connect(lambda :
|
||||
self.game_list.installed_only(self.head_bar.installed_only.isChecked()))
|
||||
|
||||
self.head_bar.installed_only.stateChanged.connect(lambda:
|
||||
self.game_list.installed_only(
|
||||
self.head_bar.installed_only.isChecked()))
|
||||
self.head_bar.refresh_list.clicked.connect(lambda: self.game_list.update_list())
|
||||
self.layout.addWidget(self.head_bar)
|
||||
self.layout.addWidget(self.game_list)
|
||||
# self.layout.addStretch(1)
|
||||
|
@ -45,4 +45,8 @@ class GameListHeadBar(QWidget):
|
|||
self.view = QCheckBox("Icon view")
|
||||
self.layout.addWidget(self.view)
|
||||
|
||||
self.refresh_list = QPushButton()
|
||||
self.refresh_list.setIcon(self.style().standardIcon(getattr(QStyle, "SP_BrowserReload"))) # Reload icon
|
||||
self.layout.addWidget(self.refresh_list)
|
||||
|
||||
self.setLayout(self.layout)
|
|
@ -6,27 +6,31 @@ from Rare.utils.QtExtensions import PathEdit
|
|||
|
||||
|
||||
class InstallDialog(QDialog):
|
||||
infos = 0
|
||||
|
||||
def __init__(self):
|
||||
super(InstallDialog, self).__init__()
|
||||
self.layout = QVBoxLayout()
|
||||
|
||||
self.form = QFormLayout()
|
||||
default_path = os.path.expanduser("~/legendary")
|
||||
#TODO read from config
|
||||
# TODO read from config
|
||||
self.install_path_field = PathEdit(text=default_path, type_of_file=QFileDialog.DirectoryOnly)
|
||||
self.form.addRow(QLabel("Install directory"), self.install_path_field)
|
||||
|
||||
self.max_workes = QSpinBox()
|
||||
self.form.addRow(QLabel("Max workers"), self.max_workes)
|
||||
self.form.addRow(QLabel("Max workers (0: Default)"), self.max_workes)
|
||||
|
||||
self.layout.addLayout(self.form)
|
||||
|
||||
self.ok = QPushButton("Install")
|
||||
self.ok_btn = QPushButton("Get Download infos")
|
||||
self.ok_btn.clicked.connect(self.ok)
|
||||
self.cancel = QPushButton("Cancel")
|
||||
self.cancel.clicked.connect(lambda: self.close())
|
||||
|
||||
self.button_layout = QHBoxLayout()
|
||||
self.button_layout.addStretch(1)
|
||||
self.button_layout.addWidget(self.ok)
|
||||
self.button_layout.addWidget(self.ok_btn)
|
||||
self.button_layout.addWidget(self.cancel)
|
||||
|
||||
self.layout.addLayout(self.button_layout)
|
||||
|
@ -35,4 +39,42 @@ class InstallDialog(QDialog):
|
|||
|
||||
def get_information(self):
|
||||
self.exec_()
|
||||
return self.install_path_field.text(), self.max_workes.value()
|
||||
return self.infos
|
||||
|
||||
def ok(self):
|
||||
self.infos = self.install_path_field.text(), self.max_workes.value()
|
||||
self.close()
|
||||
|
||||
|
||||
class InstallInfoDialog(QDialog):
|
||||
accept: bool = False
|
||||
|
||||
def __init__(self, dl_size, install_size):
|
||||
super(InstallInfoDialog, self).__init__()
|
||||
self.layout = QVBoxLayout()
|
||||
self.infos = QLabel(f"Download size: {(dl_size/1024**3):.02f}GB\nInstall size: {(install_size/1024**3):.02f}GB")
|
||||
self.layout.addWidget(self.infos)
|
||||
|
||||
self.btn_layout = QHBoxLayout()
|
||||
self.install_btn = QPushButton("Install")
|
||||
self.install_btn.clicked.connect(self.install)
|
||||
self.cancel_button = QPushButton("Cancel")
|
||||
self.cancel_button.clicked.connect(self.cancel)
|
||||
self.btn_layout.addStretch(1)
|
||||
self.btn_layout.addWidget(self.install_btn)
|
||||
self.btn_layout.addWidget(self.cancel_button)
|
||||
self.layout.addLayout(self.btn_layout)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def get_accept(self):
|
||||
self.exec_()
|
||||
return self.accept
|
||||
|
||||
def install(self):
|
||||
self.accept = True
|
||||
self.close()
|
||||
|
||||
def cancel(self):
|
||||
self.accept = False
|
||||
self.close()
|
||||
|
|
Loading…
Reference in a new issue