mirror of
https://github.com/redstrate/Astra.git
synced 2025-04-22 04:37:46 +00:00
Overhaul parts of the initial setup flow
This removes the separate "download new game" page and rolls in into the main profile setup. Also adds a feature to install the game from an existing executable, in the event the official servers are down or missing. Also shifts around some of the buttons and text.
This commit is contained in:
parent
becb5b9289
commit
dc01f3e214
9 changed files with 137 additions and 116 deletions
|
@ -105,7 +105,6 @@ qt_target_qml_sources(astra
|
|||
ui/Setup/AccountSetup.qml
|
||||
ui/Setup/AddSapphire.qml
|
||||
ui/Setup/AddSquareEnix.qml
|
||||
ui/Setup/DownloadSetup.qml
|
||||
ui/Setup/ExistingSetup.qml
|
||||
ui/Setup/InstallProgress.qml
|
||||
ui/Setup/SetupPage.qml
|
||||
|
|
|
@ -18,14 +18,18 @@ class GameInstaller : public QObject
|
|||
|
||||
public:
|
||||
GameInstaller(LauncherCore &launcher, Profile &profile, QObject *parent = nullptr);
|
||||
GameInstaller(LauncherCore &launcher, Profile &profile, const QString &filePath, QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void installGame();
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
Q_SIGNALS:
|
||||
void installFinished();
|
||||
void error(QString message);
|
||||
|
||||
private:
|
||||
void installGame();
|
||||
|
||||
LauncherCore &m_launcher;
|
||||
Profile &m_profile;
|
||||
QString m_localInstallerPath;
|
||||
};
|
|
@ -86,6 +86,7 @@ public:
|
|||
Q_INVOKABLE bool autoLogin(Profile *profile);
|
||||
|
||||
Q_INVOKABLE GameInstaller *createInstaller(Profile *profile);
|
||||
Q_INVOKABLE GameInstaller *createInstallerFromExisting(Profile *profile, const QString &filePath);
|
||||
Q_INVOKABLE CompatibilityToolInstaller *createCompatInstaller();
|
||||
|
||||
Q_INVOKABLE void clearAvatarCache();
|
||||
|
@ -121,6 +122,7 @@ Q_SIGNALS:
|
|||
void gameClosed();
|
||||
void loginError(QString message);
|
||||
void dalamudError(QString message);
|
||||
void miscError(QString message);
|
||||
void stageChanged(QString message, QString explanation = {});
|
||||
void stageIndeterminate();
|
||||
void stageDeterminate(int min, int max, int value);
|
||||
|
|
|
@ -24,18 +24,23 @@ GameInstaller::GameInstaller(LauncherCore &launcher, Profile &profile, QObject *
|
|||
{
|
||||
}
|
||||
|
||||
void GameInstaller::installGame()
|
||||
GameInstaller::GameInstaller(LauncherCore &launcher, Profile &profile, const QString &filePath, QObject *parent)
|
||||
: GameInstaller(launcher, profile, parent)
|
||||
{
|
||||
const QDir installDirectory = m_profile.gamePath();
|
||||
m_localInstallerPath = filePath;
|
||||
}
|
||||
|
||||
void GameInstaller::start()
|
||||
{
|
||||
if (m_localInstallerPath.isEmpty()) {
|
||||
const QNetworkRequest request = QNetworkRequest(QUrl(installerUrl));
|
||||
Utility::printRequest(QStringLiteral("GET"), request);
|
||||
|
||||
auto reply = m_launcher.mgr()->get(request);
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, [this, reply, installDirectory] {
|
||||
QObject::connect(reply, &QNetworkReply::finished, [this, reply] {
|
||||
if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
||||
Q_EMIT error(i18n("An error has occurred when downloading the installer.\n\n%1", reply->errorString()));
|
||||
Q_EMIT error(reply->errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -45,16 +50,30 @@ void GameInstaller::installGame()
|
|||
QCryptographicHash hash(QCryptographicHash::Sha256);
|
||||
hash.addData(data);
|
||||
|
||||
// TODO: turn into a proper error
|
||||
Q_ASSERT(hash.result() == installerSha256);
|
||||
if (hash.result() != installerSha256) {
|
||||
Q_EMIT error(i18n("The installer failed the integrity check!"));
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(dataDir.absoluteFilePath(QStringLiteral("ffxivsetup.exe")));
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.write(data);
|
||||
file.close();
|
||||
|
||||
m_localInstallerPath = file.fileName();
|
||||
installGame();
|
||||
});
|
||||
} else {
|
||||
installGame();
|
||||
}
|
||||
}
|
||||
|
||||
void GameInstaller::installGame()
|
||||
{
|
||||
const QDir installDirectory = m_profile.gamePath();
|
||||
|
||||
const std::string installDirectoryStd = installDirectory.absolutePath().toStdString();
|
||||
const std::string fileNameStd = file.fileName().toStdString();
|
||||
const std::string fileNameStd = m_localInstallerPath.toStdString();
|
||||
|
||||
physis_install_game(fileNameStd.c_str(), installDirectoryStd.c_str());
|
||||
|
||||
|
@ -62,7 +81,6 @@ void GameInstaller::installGame()
|
|||
|
||||
Q_EMIT installFinished();
|
||||
qInfo(ASTRA_LOG) << "Installed game in" << installDirectory;
|
||||
});
|
||||
}
|
||||
|
||||
#include "moc_gameinstaller.cpp"
|
|
@ -105,6 +105,13 @@ GameInstaller *LauncherCore::createInstaller(Profile *profile)
|
|||
return new GameInstaller(*this, *profile, this);
|
||||
}
|
||||
|
||||
GameInstaller *LauncherCore::createInstallerFromExisting(Profile *profile, const QString &filePath)
|
||||
{
|
||||
Q_ASSERT(profile != nullptr);
|
||||
|
||||
return new GameInstaller(*this, *profile, filePath, this);
|
||||
}
|
||||
|
||||
CompatibilityToolInstaller *LauncherCore::createCompatInstaller()
|
||||
{
|
||||
return new CompatibilityToolInstaller(*this, this);
|
||||
|
|
|
@ -25,7 +25,7 @@ FormCard.FormCardPage {
|
|||
FormCard.FormTextDelegate {
|
||||
id: helpTextDelegate
|
||||
|
||||
text: i18n("Select an account to use for '%1'", LauncherCore.currentProfile.name)
|
||||
text: i18n("Select an account to use for '%1'.", LauncherCore.currentProfile.name)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,16 +39,6 @@ FormCard.FormCardPage {
|
|||
|
||||
Layout.fillWidth: true
|
||||
|
||||
FormCard.FormTextDelegate {
|
||||
id: existingHelpDelegate
|
||||
|
||||
text: i18n("You can select an existing account.")
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
above: existingHelpDelegate
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: LauncherCore.accountManager
|
||||
|
||||
|
@ -65,6 +55,11 @@ FormCard.FormCardPage {
|
|||
}
|
||||
}
|
||||
|
||||
FormCard.FormHeader {
|
||||
title: i18n("Create New Account")
|
||||
visible: LauncherCore.accountManager.hasAnyAccounts()
|
||||
}
|
||||
|
||||
FormCard.FormCard {
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.fillWidth: true
|
||||
|
@ -72,7 +67,8 @@ FormCard.FormCardPage {
|
|||
FormCard.FormButtonDelegate {
|
||||
id: addSquareEnixButton
|
||||
|
||||
text: i18n("Add Square Enix Account")
|
||||
text: i18n("Add Square Enix Account…")
|
||||
description: i18n("Used for logging into the official game servers.")
|
||||
icon.name: "list-add-symbolic"
|
||||
onClicked: page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "AddSquareEnix"), {
|
||||
profile: page.profile
|
||||
|
@ -87,7 +83,8 @@ FormCard.FormCardPage {
|
|||
FormCard.FormButtonDelegate {
|
||||
id: addSapphireButton
|
||||
|
||||
text: i18n("Add Sapphire Account")
|
||||
text: i18n("Add Sapphire Account…")
|
||||
description: i18n("Only used for Sapphire servers, don't select this if unless you plan to connect to one.")
|
||||
icon.name: "list-add-symbolic"
|
||||
onClicked: page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "AddSapphire"), {
|
||||
profile: page.profile
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kirigamiaddons.formcard as FormCard
|
||||
|
||||
import zone.xiv.astra
|
||||
|
||||
FormCard.FormCardPage {
|
||||
id: page
|
||||
|
||||
property var profile
|
||||
|
||||
title: i18n("Download Game")
|
||||
|
||||
FormCard.FormCard {
|
||||
Layout.topMargin: Kirigami.Units.largeSpacing
|
||||
Layout.fillWidth: true
|
||||
|
||||
FormCard.FormTextDelegate {
|
||||
id: helpTextDelegate
|
||||
|
||||
text: i18n("Press the button below to download and setup the game.")
|
||||
description: i18n("This only installs the base files required for the initial update. Astra can only download patches with a legitimate Square Enix account.")
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
above: helpTextDelegate
|
||||
below: buttonDelegate
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
id: buttonDelegate
|
||||
|
||||
text: i18n("Begin installation")
|
||||
icon.name: "cloud-download"
|
||||
onClicked: page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "InstallProgress"), {
|
||||
gameInstaller: LauncherCore.createInstaller(page.profile)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Window
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
@ -18,32 +19,33 @@ Kirigami.Page {
|
|||
Kirigami.LoadingPlaceholder {
|
||||
anchors.centerIn: parent
|
||||
|
||||
text: i18n("Installing...")
|
||||
text: i18n("Installing…")
|
||||
}
|
||||
|
||||
Kirigami.PromptDialog {
|
||||
id: errorDialog
|
||||
title: i18n("Install error")
|
||||
title: i18n("Installation Error")
|
||||
|
||||
showCloseButton: false
|
||||
standardButtons: Kirigami.Dialog.Ok
|
||||
|
||||
onAccepted: applicationWindow().pageStack.layers.pop()
|
||||
onRejected: applicationWindow().pageStack.layers.pop()
|
||||
onAccepted: page.Window.window.pageStack.layers.pop()
|
||||
onRejected: page.Window.window.pageStack.layers.pop()
|
||||
}
|
||||
|
||||
Component.onCompleted: gameInstaller.installGame()
|
||||
Component.onCompleted: gameInstaller.start()
|
||||
|
||||
Connections {
|
||||
target: page.gameInstaller
|
||||
|
||||
function onInstallFinished() {
|
||||
applicationWindow().checkSetup();
|
||||
// Prevents it from failing to push the page if the install happens too quickly.
|
||||
Qt.callLater(() => applicationWindow().checkSetup());
|
||||
}
|
||||
|
||||
function onError(message) {
|
||||
errorDialog.subtitle = message
|
||||
errorDialog.open()
|
||||
errorDialog.subtitle = i18n("An error has occurred while installing the game:\n\n%1", message);
|
||||
errorDialog.open();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
@ -35,14 +37,14 @@ FormCard.FormCardPage {
|
|||
if (page.isInitialSetup) {
|
||||
return i18n("You must have a legitimate installation of the FFXIV to continue.");
|
||||
} else {
|
||||
return i18n("You must select a legitimate installation of FFXIV for '%1'", page.profile.name);
|
||||
return i18n("Select a game installation of FFXIV for '%1'.", page.profile.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormHeader {
|
||||
title: i18n("Existing Installations")
|
||||
title: i18n("Existing Installation")
|
||||
visible: LauncherCore.profileManager.hasAnyExistingInstallations()
|
||||
}
|
||||
|
||||
|
@ -54,7 +56,7 @@ FormCard.FormCardPage {
|
|||
FormCard.FormTextDelegate {
|
||||
id: existingHelpDelegate
|
||||
|
||||
text: i18n("You can select an existing installation from another profile.")
|
||||
text: i18n("You can select an existing game installation from another profile.")
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
|
@ -77,6 +79,26 @@ FormCard.FormCardPage {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
below: importDelegate
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
id: importDelegate
|
||||
|
||||
text: i18n("Import Existing Installation…")
|
||||
description: i18n("Select an existing installation on disk or import from another launcher.")
|
||||
icon.name: "document-import-symbolic"
|
||||
onClicked: page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "ExistingSetup"), {
|
||||
profile: page.profile
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormHeader {
|
||||
title: i18n("Install Game")
|
||||
visible: LauncherCore.accountManager.hasAnyAccounts()
|
||||
}
|
||||
|
||||
FormCard.FormCard {
|
||||
|
@ -84,28 +106,43 @@ FormCard.FormCardPage {
|
|||
Layout.fillWidth: true
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
id: findExistingDelegate
|
||||
id: downloadDelegate
|
||||
|
||||
text: i18n("Find Existing Installation")
|
||||
icon.name: "edit-find"
|
||||
onClicked: page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "ExistingSetup"), {
|
||||
profile: page.profile
|
||||
text: i18n("Download & Install Game")
|
||||
description: i18n("Download the retail installer online from Square Enix.")
|
||||
icon.name: "cloud-download"
|
||||
onClicked: page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "InstallProgress"), {
|
||||
gameInstaller: LauncherCore.createInstaller(page.profile)
|
||||
})
|
||||
}
|
||||
|
||||
FormCard.FormDelegateSeparator {
|
||||
above: findExistingDelegate
|
||||
below: downloadDelegate
|
||||
above: downloadDelegate
|
||||
below: selectInstallDelegate
|
||||
}
|
||||
|
||||
FormCard.FormButtonDelegate {
|
||||
id: downloadDelegate
|
||||
id: selectInstallDelegate
|
||||
|
||||
text: i18n("Download Game")
|
||||
icon.name: "cloud-download"
|
||||
onClicked: page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "DownloadSetup"), {
|
||||
profile: page.profile
|
||||
})
|
||||
text: i18n("Select Existing Installer…")
|
||||
description: i18n("Use a previously downloaded installer. Useful if offline or can't otherwise access the official servers.")
|
||||
icon.name: "edit-find"
|
||||
|
||||
FileDialog {
|
||||
id: dialog
|
||||
|
||||
currentFolder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
|
||||
nameFilters: [i18n("Windows executable (*.exe)")]
|
||||
|
||||
onAccepted: {
|
||||
const url = decodeURIComponent(selectedFile.toString().replace("file://", ""));
|
||||
page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "InstallProgress"), {
|
||||
gameInstaller: LauncherCore.createInstallerFromExisting(page.profile, url)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: dialog.open()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue