mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-09 03:14:20 +02:00
Add qt launcher states, download, and install
This commit is contained in:
parent
93367ce8a4
commit
93c443abc8
7 changed files with 428 additions and 63 deletions
|
@ -62,6 +62,8 @@ Item {
|
|||
width: 394
|
||||
height: 8
|
||||
|
||||
value: LauncherState.downloadProgress;
|
||||
|
||||
anchors {
|
||||
top: secondText.bottom
|
||||
topMargin: 30
|
||||
|
@ -88,14 +90,14 @@ Item {
|
|||
}
|
||||
|
||||
|
||||
PropertyAnimation {
|
||||
target: progressBar;
|
||||
loops: Animation.Infinite
|
||||
property: "value"
|
||||
from: 0;
|
||||
to: 1;
|
||||
duration: 5000
|
||||
running: true
|
||||
}
|
||||
//PropertyAnimation {
|
||||
//target: progressBar;
|
||||
//loops: Animation.Infinite
|
||||
//property: "value"
|
||||
//from: 0;
|
||||
//to: 1;
|
||||
//duration: 5000
|
||||
//running: true
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ TextField {
|
|||
horizontalAlignment: TextInput.AlignLeft
|
||||
placeholderText: "PlaceHolder"
|
||||
property string seperatorColor: "#FFFFFF"
|
||||
selectByMouse: true
|
||||
background: Item {
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
|
|
|
@ -4,6 +4,7 @@ import QtQuick 2.3
|
|||
import QtQuick.Controls 2.1
|
||||
import HQLauncher 1.0
|
||||
import "HFControls"
|
||||
|
||||
Image {
|
||||
id: root
|
||||
width: 515
|
||||
|
@ -21,4 +22,14 @@ Image {
|
|||
loader.source = url;
|
||||
});
|
||||
}
|
||||
|
||||
Text {
|
||||
font.pixelSize: 12
|
||||
|
||||
anchors.right: root.right
|
||||
anchors.bottom: root.bottom
|
||||
|
||||
color: "#FFFFFF"
|
||||
text: LauncherState.uiState.toString() + " - " + LauncherState.applicationState
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ Launcher::Launcher(int& argc, char**argv) : QGuiApplication(argc, argv) {
|
|||
QString resourceBinaryLocation = QGuiApplication::applicationDirPath() + "/resources.rcc";
|
||||
QResource::registerResource(resourceBinaryLocation);
|
||||
_launcherState = std::make_shared<LauncherState>();
|
||||
_launcherState->setUIState(LauncherState::SPLASH_SCREEN);
|
||||
//_launcherState->setUIState(LauncherState::SPLASH_SCREEN);
|
||||
_launcherWindow = std::make_unique<LauncherWindow>();
|
||||
_launcherWindow->rootContext()->setContextProperty("LauncherState", _launcherState.get());
|
||||
_launcherWindow->setFlags(Qt::FramelessWindowHint);
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#include "LauncherState.h"
|
||||
|
||||
#include "Unzipper.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <QNetworkRequest>
|
||||
|
@ -13,18 +17,56 @@
|
|||
#include <QDebug>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include <QThreadPool>
|
||||
|
||||
#include <QStandardPaths>
|
||||
|
||||
|
||||
bool LatestBuilds::getBuild(QString tag, Build* outBuild) {
|
||||
if (tag.isNull()) {
|
||||
tag = defaultTag;
|
||||
}
|
||||
|
||||
for (auto& build : builds) {
|
||||
if (build.tag == tag) {
|
||||
*outBuild = build;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const std::array<QString, LauncherState::UIState::UI_STATE_NUM> QML_FILE_FOR_UI_STATE =
|
||||
{ { "qrc:/qml/SplashScreen.qml", "qrc:/qml/Login.qml", "qrc:/qml/DisplayName.qml",
|
||||
"qrc:/qml/Download.qml", "qrc:/qml/DownloadFinshed.qml", "qrc:/qml/Error.qml" } };
|
||||
|
||||
void LauncherState::ASSERT_STATE(LauncherState::ApplicationState state) const {
|
||||
if (_appState != state) {
|
||||
void LauncherState::ASSERT_STATE(LauncherState::ApplicationState state) {
|
||||
if (_applicationState != state) {
|
||||
#ifdef Q_OS_WIN
|
||||
__debugbreak();
|
||||
exit(0);
|
||||
#endif
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherState::ASSERT_STATE(std::vector<LauncherState::ApplicationState> states) {
|
||||
for (auto state : states) {
|
||||
if (_applicationState == state) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
__debugbreak();
|
||||
#endif
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
}
|
||||
|
||||
LauncherState::LauncherState() {
|
||||
_launcherDirectory = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
// TODO Fix launcher directory
|
||||
qDebug() << "Launcher directory: " << _launcherDirectory.absolutePath();
|
||||
_launcherDirectory.mkpath(_launcherDirectory.absolutePath());
|
||||
requestBuilds();
|
||||
}
|
||||
|
||||
|
@ -36,13 +78,29 @@ void LauncherState::declareQML() {
|
|||
qmlRegisterType<LauncherState>("HQLauncher", 1, 0, "LauncherStateEnums");
|
||||
}
|
||||
|
||||
void LauncherState::setUIState(UIState state) {
|
||||
_uiState = state;
|
||||
emit updateSourceUrl(getCurrentUISource());
|
||||
}
|
||||
|
||||
LauncherState::UIState LauncherState::getUIState() const {
|
||||
return _uiState;
|
||||
switch (_applicationState) {
|
||||
case ApplicationState::Init:
|
||||
case ApplicationState::RequestingBuilds:
|
||||
return SPLASH_SCREEN;
|
||||
case ApplicationState::WaitingForLogin:
|
||||
case ApplicationState::RequestingLogin:
|
||||
return LOGIN_SCREEN;
|
||||
case ApplicationState::DownloadingClient:
|
||||
case ApplicationState::InstallingClient:
|
||||
case ApplicationState::DownloadingContentCache:
|
||||
case ApplicationState::InstallingContentCache:
|
||||
return DOWNLOAD_SCREEN;
|
||||
case ApplicationState::LaunchingHighFidelity:
|
||||
return DOWNLOAD_FINSISHED;
|
||||
case ApplicationState::UnexpectedError:
|
||||
__debugbreak();
|
||||
return ERROR_SCREEN;
|
||||
default:
|
||||
qDebug() << "FATAL: No UI for" << _applicationState;
|
||||
__debugbreak();
|
||||
return ERROR_SCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherState::setLastLoginError(LastLoginError lastLoginError) {
|
||||
|
@ -54,8 +112,8 @@ LauncherState::LastLoginError LauncherState::getLastLoginError() const {
|
|||
}
|
||||
|
||||
void LauncherState::requestBuilds() {
|
||||
ASSERT_STATE(ApplicationState::INIT);
|
||||
_appState = ApplicationState::REQUESTING_BUILDS;
|
||||
ASSERT_STATE(ApplicationState::Init);
|
||||
setApplicationState(ApplicationState::RequestingBuilds);
|
||||
|
||||
// TODO Show splash screen until this request is complete
|
||||
auto request = new QNetworkRequest(QUrl("https://thunder.highfidelity.com/builds/api/tags/latest/?format=json"));
|
||||
|
@ -67,7 +125,7 @@ void LauncherState::requestBuilds() {
|
|||
void LauncherState::receivedBuildsReply() {
|
||||
auto reply = static_cast<QNetworkReply*>(sender());
|
||||
|
||||
ASSERT_STATE(ApplicationState::REQUESTING_BUILDS);
|
||||
ASSERT_STATE(ApplicationState::RequestingBuilds);
|
||||
|
||||
if (reply->error()) {
|
||||
qDebug() << "Error getting builds from thunder: " << reply->errorString();
|
||||
|
@ -81,8 +139,7 @@ void LauncherState::receivedBuildsReply() {
|
|||
} else {
|
||||
auto root = doc.object();
|
||||
if (!root.contains("default_tag")) {
|
||||
_appState = ApplicationState::REQUESTING_BUILDS_FAILED;
|
||||
setUIState(LauncherState::ERROR_SCREEN);
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -90,8 +147,7 @@ void LauncherState::receivedBuildsReply() {
|
|||
|
||||
auto results = root["results"];
|
||||
if (!results.isArray()) {
|
||||
_appState = ApplicationState::REQUESTING_BUILDS_FAILED;
|
||||
setUIState(LauncherState::ERROR_SCREEN);
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -112,14 +168,13 @@ void LauncherState::receivedBuildsReply() {
|
|||
}
|
||||
}
|
||||
}
|
||||
_appState = ApplicationState::WAITING_FOR_LOGIN;
|
||||
setUIState(LauncherState::LOGIN_SCREEN);
|
||||
setApplicationState(ApplicationState::WaitingForLogin);
|
||||
}
|
||||
|
||||
void LauncherState::login(QString username, QString password) {
|
||||
ASSERT_STATE(ApplicationState::WAITING_FOR_LOGIN);
|
||||
ASSERT_STATE(ApplicationState::WaitingForLogin);
|
||||
|
||||
_appState = ApplicationState::REQUESTING_LOGIN;
|
||||
setApplicationState(ApplicationState::RequestingLogin);
|
||||
|
||||
qDebug() << "Got login: " << username << password;
|
||||
|
||||
|
@ -133,32 +188,287 @@ void LauncherState::login(QString username, QString password) {
|
|||
query.addQueryItem("scope", "owner");
|
||||
|
||||
auto reply = _networkAccessManager.post(*request, query.toString().toUtf8());
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, this, &LauncherState::receivedLoginReply);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void LauncherState::receivedLoginReply() {
|
||||
ASSERT_STATE(ApplicationState::RequestingLogin);
|
||||
|
||||
// TODO Check for errors
|
||||
auto reply = static_cast<QNetworkReply*>(sender());
|
||||
|
||||
ASSERT_STATE(ApplicationState::REQUESTING_LOGIN);
|
||||
if (reply->error()) {
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Got response for login: " << reply->readAll();
|
||||
auto data = reply->readAll();
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(data, &parseError);
|
||||
auto root = doc.object();
|
||||
|
||||
if (!root.contains("access_token")
|
||||
|| !root.contains("token_type")
|
||||
|| !root.contains("expires_in")
|
||||
|| !root.contains("refresh_token")
|
||||
|| !root.contains("scope")
|
||||
|| !root.contains("created_at")) {
|
||||
|
||||
download();
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
|
||||
_loginResponse.accessToken = root["access_token"].toString();
|
||||
_loginResponse.refreshToken = root["refresh_token"].toString();
|
||||
_loginResponse.tokenType = root["token_type"].toString();
|
||||
|
||||
qDebug() << "Got response for login: " << data;
|
||||
|
||||
downloadClient();
|
||||
}
|
||||
|
||||
void LauncherState::download() {
|
||||
_appState = ApplicationState::DOWNLOADING_CONTENT;
|
||||
setUIState(LauncherState::DOWNLOAD_SCREEN);
|
||||
QString LauncherState::getContentCachePath() const {
|
||||
return _launcherDirectory.filePath("cache");
|
||||
}
|
||||
|
||||
void LauncherState::contentDownloadComplete() {
|
||||
bool LauncherState::shouldDownloadContentCache() const {
|
||||
return !_contentCacheURL.isNull() && !QFile::exists(getContentCachePath());
|
||||
}
|
||||
|
||||
void LauncherState::downloadClient() {
|
||||
ASSERT_STATE(ApplicationState::RequestingLogin);
|
||||
|
||||
Build build;
|
||||
if (!_latestBuilds.getBuild(_buildTag, &build)) {
|
||||
qDebug() << "Cannot determine latest build";
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
|
||||
_downloadProgress = 0;
|
||||
setApplicationState(ApplicationState::DownloadingClient);
|
||||
|
||||
// Start client download
|
||||
{
|
||||
qDebug() << "Latest build: " << build.tag << build.buildNumber << build.latestVersion << build.installerZipURL;
|
||||
auto request = new QNetworkRequest(QUrl(build.installerZipURL));
|
||||
auto reply = _networkAccessManager.get(*request);
|
||||
|
||||
_clientZipFile.setFileName(_launcherDirectory.absoluteFilePath("client.zip"));
|
||||
|
||||
qDebug() << "Opening " << _clientZipFile.fileName();
|
||||
if (!_clientZipFile.open(QIODevice::WriteOnly)) {
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, &LauncherState::clientDownloadComplete);
|
||||
connect(reply, &QNetworkReply::readyRead, this, [this, reply]() {
|
||||
char buf[4096];
|
||||
while (reply->bytesAvailable() > 0) {
|
||||
qint64 size;
|
||||
size = reply->read(buf, (qint64)sizeof(buf));
|
||||
if (size == 0) {
|
||||
break;
|
||||
}
|
||||
_clientZipFile.write(buf, size);
|
||||
}
|
||||
});
|
||||
connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 received, qint64 total) {
|
||||
_downloadProgress = (float)received / (float)total;
|
||||
emit downloadProgressChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherState::clientDownloadComplete() {
|
||||
ASSERT_STATE(ApplicationState::DownloadingClient);
|
||||
|
||||
_clientZipFile.close();
|
||||
|
||||
installClient();
|
||||
}
|
||||
|
||||
void LauncherState::installClient() {
|
||||
ASSERT_STATE(ApplicationState::DownloadingClient);
|
||||
setApplicationState(ApplicationState::InstallingClient);
|
||||
|
||||
auto installDir = _launcherDirectory.absoluteFilePath("interface_install");
|
||||
_launcherDirectory.mkpath("interface_install");
|
||||
|
||||
_downloadProgress = 0;
|
||||
|
||||
qDebug() << "Unzipping " << _clientZipFile.fileName() << " to " << installDir;
|
||||
|
||||
auto unzipper = new Unzipper(_clientZipFile.fileName(), QDir(installDir));
|
||||
unzipper->setAutoDelete(true);
|
||||
connect(unzipper, &Unzipper::progress, this, [this](float progress) {
|
||||
qDebug() << "Unzipper progress: " << progress;
|
||||
_downloadProgress = progress;
|
||||
emit downloadProgressChanged();
|
||||
});
|
||||
connect(unzipper, &Unzipper::finished, this, [this](bool error, QString errorMessage) {
|
||||
if (error) {
|
||||
qDebug() << "Unzipper finished with error: " << errorMessage;
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
} else {
|
||||
qDebug() << "Unzipper finished without error";
|
||||
downloadContentCache();
|
||||
}
|
||||
});
|
||||
QThreadPool::globalInstance()->start(unzipper);
|
||||
|
||||
//launchClient();
|
||||
}
|
||||
|
||||
void LauncherState::downloadContentCache() {
|
||||
ASSERT_STATE(ApplicationState::InstallingClient);
|
||||
|
||||
// Start content set cache download
|
||||
if (shouldDownloadContentCache()) {
|
||||
setApplicationState(ApplicationState::DownloadingContentCache);
|
||||
|
||||
_downloadProgress = 0;
|
||||
|
||||
auto request = new QNetworkRequest(QUrl(_contentCacheURL));
|
||||
auto reply = _networkAccessManager.get(*request);
|
||||
|
||||
_contentZipFile.setFileName(_launcherDirectory.absoluteFilePath("content_cache.zip"));
|
||||
|
||||
qDebug() << "Opening " << _contentZipFile.fileName();
|
||||
if (!_contentZipFile.open(QIODevice::WriteOnly)) {
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, &LauncherState::contentCacheDownloadComplete);
|
||||
connect(reply, &QNetworkReply::readyRead, this, [this, reply]() {
|
||||
char buf[4096];
|
||||
while (reply->bytesAvailable() > 0) {
|
||||
qint64 size;
|
||||
size = reply->read(buf, (qint64)sizeof(buf));
|
||||
if (size == 0) {
|
||||
break;
|
||||
}
|
||||
_contentZipFile.write(buf, size);
|
||||
}
|
||||
});
|
||||
connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 received, qint64 total) {
|
||||
_downloadProgress = (float)received / (float)total;
|
||||
emit downloadProgressChanged();
|
||||
});
|
||||
} else {
|
||||
launchClient();
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherState::contentCacheDownloadComplete() {
|
||||
ASSERT_STATE(ApplicationState::DownloadingContentCache);
|
||||
|
||||
_contentZipFile.close();
|
||||
|
||||
installContentCache();
|
||||
}
|
||||
|
||||
|
||||
void LauncherState::installContentCache() {
|
||||
ASSERT_STATE(ApplicationState::DownloadingContentCache);
|
||||
setApplicationState(ApplicationState::InstallingContentCache);
|
||||
|
||||
auto installDir = getContentCachePath();
|
||||
|
||||
qDebug() << "Unzipping " << _contentZipFile.fileName() << " to " << installDir;
|
||||
|
||||
_downloadProgress = 0;
|
||||
|
||||
auto unzipper = new Unzipper(_contentZipFile.fileName(), QDir(installDir));
|
||||
unzipper->setAutoDelete(true);
|
||||
connect(unzipper, &Unzipper::progress, this, [this](float progress) {
|
||||
qDebug() << "Unzipper progress (content cache): " << progress;
|
||||
_downloadProgress = progress;
|
||||
emit downloadProgressChanged();
|
||||
});
|
||||
connect(unzipper, &Unzipper::finished, this, [this](bool error, QString errorMessage) {
|
||||
if (error) {
|
||||
qDebug() << "Unzipper finished with error: " << errorMessage;
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
} else {
|
||||
qDebug() << "Unzipper finished without error";
|
||||
launchClient();
|
||||
}
|
||||
});
|
||||
QThreadPool::globalInstance()->start(unzipper);
|
||||
|
||||
}
|
||||
|
||||
void LauncherState::launchClient() {
|
||||
_appState = ApplicationState::LAUNCHING_HIGH_FIDELITY;
|
||||
ASSERT_STATE({ ApplicationState::InstallingClient, ApplicationState::InstallingContentCache });
|
||||
|
||||
setApplicationState(ApplicationState::LaunchingHighFidelity);
|
||||
|
||||
QDir installDirectory = _launcherDirectory.filePath("interface_install");
|
||||
auto clientPath = installDirectory.absoluteFilePath("interface.exe");
|
||||
|
||||
QString homePath = "hifi://hq";
|
||||
QString defaultScriptsPath = installDirectory.filePath("scripts/simplifiedUIBootstrapper");
|
||||
QString displayName = "fixMe";
|
||||
QString contentCachePath = _launcherDirectory.filePath("cache");
|
||||
|
||||
// TODO Fix parameters
|
||||
QString params = "--url " + homePath
|
||||
+ " --setBookmark hqhome=\"" + homePath + "\""
|
||||
+ " --defaultScriptsOverride " + QDir::toNativeSeparators(defaultScriptsPath)
|
||||
+ " --displayName " + displayName
|
||||
+ " --cache " + contentCachePath;
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
// set the size of the structures
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
// start the program up
|
||||
BOOL success = CreateProcess(
|
||||
clientPath.toUtf8().data(),
|
||||
params.toUtf8().data(),
|
||||
nullptr, // Process handle not inheritable
|
||||
nullptr, // Thread handle not inheritable
|
||||
FALSE, // Set handle inheritance to FALSE
|
||||
CREATE_NEW_CONSOLE, // Opens file in a separate console
|
||||
nullptr, // Use parent's environment block
|
||||
nullptr, // Use parent's starting directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&pi // Pointer to PROCESS_INFORMATION structure
|
||||
);
|
||||
// Close process and thread handles.
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
exit(0);
|
||||
#elif defined(Q_OS_MACOS)
|
||||
// TODO Implement launching of client
|
||||
#else
|
||||
#error UNSUPPORTED PLATFORM
|
||||
#endif
|
||||
}
|
||||
|
||||
void LauncherState::setApplicationState(ApplicationState state) {
|
||||
qDebug() << "Changing application state: " << _applicationState << " -> " << state;
|
||||
|
||||
if (state == ApplicationState::UnexpectedError) {
|
||||
__debugbreak();
|
||||
}
|
||||
|
||||
_applicationState = state;
|
||||
|
||||
emit uiStateChanged();
|
||||
emit updateSourceUrl(getCurrentUISource());
|
||||
|
||||
emit applicationStateChanged();
|
||||
}
|
||||
|
||||
LauncherState::ApplicationState LauncherState::getApplicationState() const {
|
||||
return _applicationState;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDir>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QFile>
|
||||
|
||||
struct Build {
|
||||
QString tag;
|
||||
|
@ -10,12 +14,24 @@ struct Build {
|
|||
};
|
||||
|
||||
struct LatestBuilds {
|
||||
bool getBuild(QString tag, Build* outBuild);
|
||||
|
||||
QString defaultTag;
|
||||
std::vector<Build> builds;
|
||||
};
|
||||
|
||||
struct LoginResponse {
|
||||
QString accessToken;
|
||||
QString tokenType;
|
||||
QString refreshToken;
|
||||
};
|
||||
|
||||
class LauncherState : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(UIState uiState READ getUIState NOTIFY uiStateChanged);
|
||||
Q_PROPERTY(ApplicationState applicationState READ getApplicationState NOTIFY applicationStateChanged);
|
||||
|
||||
Q_PROPERTY(float downloadProgress READ getDownloadProgress NOTIFY downloadProgressChanged);
|
||||
|
||||
public:
|
||||
LauncherState();
|
||||
|
@ -30,29 +46,27 @@ public:
|
|||
ERROR_SCREEN,
|
||||
UI_STATE_NUM
|
||||
};
|
||||
Q_ENUMS(UIState);
|
||||
Q_ENUM(UIState);
|
||||
|
||||
enum class ApplicationState {
|
||||
INIT,
|
||||
Init,
|
||||
|
||||
REQUESTING_BUILDS,
|
||||
REQUESTING_BUILDS_FAILED,
|
||||
UnexpectedError,
|
||||
|
||||
WAITING_FOR_LOGIN,
|
||||
REQUESTING_LOGIN,
|
||||
RequestingBuilds,
|
||||
|
||||
WAITING_FOR_SIGNUP,
|
||||
REQUESTING_SIGNUP,
|
||||
WaitingForLogin,
|
||||
RequestingLogin,
|
||||
|
||||
DOWNLOADING_CONTENT,
|
||||
DOWNLOADING_HIGH_FIDELITY,
|
||||
DownloadingClient,
|
||||
DownloadingContentCache,
|
||||
|
||||
EXTRACTING_DATA,
|
||||
InstallingClient,
|
||||
InstallingContentCache,
|
||||
|
||||
LAUNCHING_HIGH_FIDELITY
|
||||
LaunchingHighFidelity
|
||||
};
|
||||
Q_ENUMS(ApplicationState);
|
||||
|
||||
Q_ENUM(ApplicationState);
|
||||
|
||||
enum LastLoginError {
|
||||
NONE = 0,
|
||||
|
@ -60,19 +74,23 @@ public:
|
|||
CREDENTIALS,
|
||||
LAST_ERROR_NUM
|
||||
};
|
||||
Q_ENUMS(LastLoginError);
|
||||
Q_ENUM(LastLoginError);
|
||||
|
||||
Q_INVOKABLE QString getCurrentUISource() const;
|
||||
|
||||
void LauncherState::ASSERT_STATE(LauncherState::ApplicationState state) const;
|
||||
void ASSERT_STATE(LauncherState::ApplicationState state);
|
||||
void ASSERT_STATE(std::vector<LauncherState::ApplicationState> states);
|
||||
|
||||
static void declareQML();
|
||||
|
||||
void setUIState(UIState state);
|
||||
UIState getUIState() const;
|
||||
|
||||
void setLastLoginError(LastLoginError lastLoginError);
|
||||
LastLoginError getLastLoginError() const;
|
||||
|
||||
void setApplicationState(ApplicationState state);
|
||||
ApplicationState getApplicationState() const;
|
||||
|
||||
// Request builds
|
||||
void requestBuilds();
|
||||
Q_INVOKABLE void receivedBuildsReply();
|
||||
|
@ -81,22 +99,45 @@ public:
|
|||
Q_INVOKABLE void login(QString username, QString password);
|
||||
Q_INVOKABLE void receivedLoginReply();
|
||||
|
||||
// Download
|
||||
void download();
|
||||
Q_INVOKABLE void contentDownloadComplete();
|
||||
Q_INVOKABLE void clientDownloadComplete();
|
||||
// Client
|
||||
void downloadClient();
|
||||
void installClient();
|
||||
|
||||
// Content Cache
|
||||
void downloadContentCache();
|
||||
void installContentCache();
|
||||
|
||||
// Launching
|
||||
void launchClient();
|
||||
|
||||
Q_INVOKABLE float getDownloadProgress() const { return _downloadProgress; }
|
||||
|
||||
signals:
|
||||
void updateSourceUrl(QString sourceUrl);
|
||||
void uiStateChanged();
|
||||
void applicationStateChanged();
|
||||
void downloadProgressChanged();
|
||||
|
||||
private slots:
|
||||
void clientDownloadComplete();
|
||||
void contentCacheDownloadComplete();
|
||||
|
||||
private:
|
||||
bool shouldDownloadContentCache() const;
|
||||
QString getContentCachePath() const;
|
||||
|
||||
QNetworkAccessManager _networkAccessManager;
|
||||
LatestBuilds _latestBuilds;
|
||||
QDir _launcherDirectory;
|
||||
|
||||
ApplicationState _appState { ApplicationState::INIT };
|
||||
UIState _uiState { SPLASH_SCREEN };
|
||||
// Application State
|
||||
ApplicationState _applicationState { ApplicationState::Init };
|
||||
LoginResponse _loginResponse;
|
||||
LastLoginError _lastLoginError { NONE };
|
||||
QString _buildTag { QString::null };
|
||||
QString _contentCacheURL{ "https://orgs.highfidelity.com/content-cache/content_cache_small-only_data8.zip" }; // QString::null }; // If null, there is no content cache to download
|
||||
QFile _clientZipFile;
|
||||
QFile _contentZipFile;
|
||||
|
||||
float _downloadProgress { 0 };
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ Q_IMPORT_PLUGIN(QtQuickControls2Plugin);
|
|||
Q_IMPORT_PLUGIN(QtQuickTemplates2Plugin);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QString name { "HQLauncher" };
|
||||
QString name { "High Fidelity" };
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QCoreApplication::setOrganizationName(name);
|
||||
|
||||
|
|
Loading…
Reference in a new issue