Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into feature/java-downloader
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
commit
0f311453e1
@ -79,6 +79,14 @@
|
|||||||
<string>curseforge</string>
|
<string>curseforge</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>Prismlauncher</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>prismlauncher</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -294,12 +294,17 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
QString adjustedBy;
|
QString adjustedBy;
|
||||||
QString dataPath;
|
QString dataPath;
|
||||||
// change folder
|
// change folder
|
||||||
|
QString dataDirEnv;
|
||||||
QString dirParam = parser.value("dir");
|
QString dirParam = parser.value("dir");
|
||||||
if (!dirParam.isEmpty()) {
|
if (!dirParam.isEmpty()) {
|
||||||
// the dir param. it makes multimc data path point to whatever the user specified
|
// the dir param. it makes multimc data path point to whatever the user specified
|
||||||
// on command line
|
// on command line
|
||||||
adjustedBy = "Command line";
|
adjustedBy = "Command line";
|
||||||
dataPath = dirParam;
|
dataPath = dirParam;
|
||||||
|
} else if (dataDirEnv = QProcessEnvironment::systemEnvironment().value(QString("%1_DATA_DIR").arg(BuildConfig.LAUNCHER_NAME.toUpper()));
|
||||||
|
!dataDirEnv.isEmpty()) {
|
||||||
|
adjustedBy = "System environment";
|
||||||
|
dataPath = dataDirEnv;
|
||||||
} else {
|
} else {
|
||||||
QDir foo;
|
QDir foo;
|
||||||
if (DesktopServices::isSnap()) {
|
if (DesktopServices::isSnap()) {
|
||||||
@ -445,7 +450,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
// search the dataPath()
|
// search the dataPath()
|
||||||
// seach app data standard path
|
// seach app data standard path
|
||||||
if (!foundLoggingRules && !isPortable() && dirParam.isEmpty()) {
|
if (!foundLoggingRules && !isPortable() && dirParam.isEmpty() && dataDirEnv.isEmpty()) {
|
||||||
logRulesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, FS::PathCombine("..", logRulesFile));
|
logRulesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, FS::PathCombine("..", logRulesFile));
|
||||||
if (!logRulesPath.isEmpty()) {
|
if (!logRulesPath.isEmpty()) {
|
||||||
qDebug() << "Found" << logRulesPath << "...";
|
qDebug() << "Found" << logRulesPath << "...";
|
||||||
@ -556,6 +561,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
m_settings->registerSetting("NumberOfConcurrentTasks", 10);
|
m_settings->registerSetting("NumberOfConcurrentTasks", 10);
|
||||||
m_settings->registerSetting("NumberOfConcurrentDownloads", 6);
|
m_settings->registerSetting("NumberOfConcurrentDownloads", 6);
|
||||||
|
m_settings->registerSetting("RequestTimeout", 60);
|
||||||
|
|
||||||
QString defaultMonospace;
|
QString defaultMonospace;
|
||||||
int defaultSize = 11;
|
int defaultSize = 11;
|
||||||
|
@ -48,7 +48,6 @@
|
|||||||
#include <BaseInstance.h>
|
#include <BaseInstance.h>
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftServerTarget.h"
|
||||||
#include "ui/themes/CatPack.h"
|
|
||||||
|
|
||||||
class LaunchController;
|
class LaunchController;
|
||||||
class LocalPeer;
|
class LocalPeer;
|
||||||
@ -194,6 +193,8 @@ class Application : public QApplication {
|
|||||||
void globalSettingsClosed();
|
void globalSettingsClosed();
|
||||||
int currentCatChanged(int index);
|
int currentCatChanged(int index);
|
||||||
|
|
||||||
|
void oauthReplyRecieved(QVariantMap);
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
void clickedOnDock();
|
void clickedOnDock();
|
||||||
#endif
|
#endif
|
||||||
|
@ -59,6 +59,9 @@ void AuthFlow::executeTask()
|
|||||||
|
|
||||||
void AuthFlow::nextStep()
|
void AuthFlow::nextStep()
|
||||||
{
|
{
|
||||||
|
if (!Task::isRunning()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (m_steps.size() == 0) {
|
if (m_steps.size() == 0) {
|
||||||
// we got to the end without an incident... assume this is all.
|
// we got to the end without an incident... assume this is all.
|
||||||
m_currentStep.reset();
|
m_currentStep.reset();
|
||||||
@ -143,4 +146,11 @@ bool AuthFlow::changeState(AccountTaskState newState, QString reason)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
bool AuthFlow::abort()
|
||||||
|
{
|
||||||
|
emitAborted();
|
||||||
|
if (m_currentStep)
|
||||||
|
m_currentStep->abort();
|
||||||
|
return true;
|
||||||
}
|
}
|
@ -24,6 +24,9 @@ class AuthFlow : public Task {
|
|||||||
|
|
||||||
AccountTaskState taskState() { return m_taskState; }
|
AccountTaskState taskState() { return m_taskState; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool abort() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void authorizeWithBrowser(const QUrl& url);
|
void authorizeWithBrowser(const QUrl& url);
|
||||||
void authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn);
|
void authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn);
|
||||||
|
@ -34,6 +34,7 @@ class AuthStep : public QObject {
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void perform() = 0;
|
virtual void perform() = 0;
|
||||||
|
virtual void abort() {}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished(AccountTaskState resultingState, QString message);
|
void finished(AccountTaskState resultingState, QString message);
|
||||||
|
@ -29,5 +29,5 @@ void GetSkinStep::onRequestDone()
|
|||||||
{
|
{
|
||||||
if (m_task->error() == QNetworkReply::NoError)
|
if (m_task->error() == QNetworkReply::NoError)
|
||||||
m_data->minecraftProfile.skin.data = *m_response;
|
m_data->minecraftProfile.skin.data = *m_response;
|
||||||
emit finished(AccountTaskState::STATE_SUCCEEDED, tr("Got skin"));
|
emit finished(AccountTaskState::STATE_WORKING, tr("Got skin"));
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,8 @@
|
|||||||
MSADeviceCodeStep::MSADeviceCodeStep(AccountData* data) : AuthStep(data)
|
MSADeviceCodeStep::MSADeviceCodeStep(AccountData* data) : AuthStep(data)
|
||||||
{
|
{
|
||||||
m_clientId = APPLICATION->getMSAClientID();
|
m_clientId = APPLICATION->getMSAClientID();
|
||||||
|
connect(&m_expiration_timer, &QTimer::timeout, this, &MSADeviceCodeStep::abort);
|
||||||
|
connect(&m_pool_timer, &QTimer::timeout, this, &MSADeviceCodeStep::authenticateUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MSADeviceCodeStep::describe()
|
QString MSADeviceCodeStep::describe()
|
||||||
@ -133,9 +135,7 @@ void MSADeviceCodeStep::deviceAutorizationFinished()
|
|||||||
m_expiration_timer.setTimerType(Qt::VeryCoarseTimer);
|
m_expiration_timer.setTimerType(Qt::VeryCoarseTimer);
|
||||||
m_expiration_timer.setInterval(rsp.expires_in * 1000);
|
m_expiration_timer.setInterval(rsp.expires_in * 1000);
|
||||||
m_expiration_timer.setSingleShot(true);
|
m_expiration_timer.setSingleShot(true);
|
||||||
connect(&m_expiration_timer, &QTimer::timeout, this, &MSADeviceCodeStep::abort);
|
|
||||||
m_expiration_timer.start();
|
m_expiration_timer.start();
|
||||||
|
|
||||||
m_pool_timer.setTimerType(Qt::VeryCoarseTimer);
|
m_pool_timer.setTimerType(Qt::VeryCoarseTimer);
|
||||||
m_pool_timer.setSingleShot(true);
|
m_pool_timer.setSingleShot(true);
|
||||||
startPoolTimer();
|
startPoolTimer();
|
||||||
@ -157,8 +157,12 @@ void MSADeviceCodeStep::startPoolTimer()
|
|||||||
if (m_is_aborted) {
|
if (m_is_aborted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (m_expiration_timer.remainingTime() < interval * 1000) {
|
||||||
|
perform();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_pool_timer.setInterval(interval * 1000);
|
m_pool_timer.setInterval(interval * 1000);
|
||||||
connect(&m_pool_timer, &QTimer::timeout, this, &MSADeviceCodeStep::authenticateUser);
|
|
||||||
m_pool_timer.start();
|
m_pool_timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ class MSADeviceCodeStep : public AuthStep {
|
|||||||
QString describe() override;
|
QString describe() override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void abort();
|
void abort() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void authorizeWithBrowser(QString url, QString code, int expiresIn);
|
void authorizeWithBrowser(QString url, QString code, int expiresIn);
|
||||||
|
@ -35,22 +35,74 @@
|
|||||||
|
|
||||||
#include "MSAStep.h"
|
#include "MSAStep.h"
|
||||||
|
|
||||||
#include <QtNetworkAuth/qoauthhttpserverreplyhandler.h>
|
|
||||||
#include <QAbstractOAuth2>
|
#include <QAbstractOAuth2>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
|
#include <QOAuthHttpServerReplyHandler>
|
||||||
|
#include <QOAuthOobReplyHandler>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "BuildConfig.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
bool isSchemeHandlerRegistered()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QProcess process;
|
||||||
|
process.start("xdg-mime", { "query", "default", "x-scheme-handler/" + BuildConfig.LAUNCHER_APP_BINARY_NAME });
|
||||||
|
process.waitForFinished();
|
||||||
|
QString output = process.readAllStandardOutput().trimmed();
|
||||||
|
|
||||||
|
return output.contains(BuildConfig.LAUNCHER_APP_BINARY_NAME);
|
||||||
|
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
|
QString regPath = QString("HKEY_CURRENT_USER\\Software\\Classes\\%1").arg(BuildConfig.LAUNCHER_APP_BINARY_NAME);
|
||||||
|
QSettings settings(regPath, QSettings::NativeFormat);
|
||||||
|
|
||||||
|
return settings.contains("shell/open/command/.");
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomOAuthOobReplyHandler : public QOAuthOobReplyHandler {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CustomOAuthOobReplyHandler(QObject* parent = nullptr) : QOAuthOobReplyHandler(parent)
|
||||||
|
{
|
||||||
|
connect(APPLICATION, &Application::oauthReplyRecieved, this, &QOAuthOobReplyHandler::callbackReceived);
|
||||||
|
}
|
||||||
|
~CustomOAuthOobReplyHandler() override
|
||||||
|
{
|
||||||
|
disconnect(APPLICATION, &Application::oauthReplyRecieved, this, &QOAuthOobReplyHandler::callbackReceived);
|
||||||
|
}
|
||||||
|
QString callback() const override { return BuildConfig.LAUNCHER_APP_BINARY_NAME + "://oauth/microsoft"; }
|
||||||
|
};
|
||||||
|
|
||||||
MSAStep::MSAStep(AccountData* data, bool silent) : AuthStep(data), m_silent(silent)
|
MSAStep::MSAStep(AccountData* data, bool silent) : AuthStep(data), m_silent(silent)
|
||||||
{
|
{
|
||||||
m_clientId = APPLICATION->getMSAClientID();
|
m_clientId = APPLICATION->getMSAClientID();
|
||||||
|
if (QCoreApplication::applicationFilePath().startsWith("/tmp/.mount_") ||
|
||||||
|
QFile::exists(FS::PathCombine(APPLICATION->root(), "portable.txt")) || !isSchemeHandlerRegistered())
|
||||||
|
|
||||||
auto replyHandler = new QOAuthHttpServerReplyHandler(1337, this);
|
{
|
||||||
replyHandler->setCallbackText(
|
auto replyHandler = new QOAuthHttpServerReplyHandler(this);
|
||||||
" <iframe src=\"https://prismlauncher.org/successful-login\" title=\"PrismLauncher Microsoft login\" style=\"position:fixed; "
|
replyHandler->setCallbackText(R"XXX(
|
||||||
"top:0; left:0; bottom:0; right:0; width:100%; height:100%; border:none; margin:0; padding:0; overflow:hidden; "
|
<noscript>
|
||||||
"z-index:999999;\"/> ");
|
<meta http-equiv="Refresh" content="0; URL=https://prismlauncher.org/successful-login" />
|
||||||
oauth2.setReplyHandler(replyHandler);
|
</noscript>
|
||||||
|
Login Successful, redirecting...
|
||||||
|
<script>
|
||||||
|
window.location.replace("https://prismlauncher.org/successful-login");
|
||||||
|
</script>
|
||||||
|
)XXX");
|
||||||
|
oauth2.setReplyHandler(replyHandler);
|
||||||
|
} else {
|
||||||
|
oauth2.setReplyHandler(new CustomOAuthOobReplyHandler(this));
|
||||||
|
}
|
||||||
oauth2.setAuthorizationUrl(QUrl("https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize"));
|
oauth2.setAuthorizationUrl(QUrl("https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize"));
|
||||||
oauth2.setAccessTokenUrl(QUrl("https://login.microsoftonline.com/consumers/oauth2/v2.0/token"));
|
oauth2.setAccessTokenUrl(QUrl("https://login.microsoftonline.com/consumers/oauth2/v2.0/token"));
|
||||||
oauth2.setScope("XboxLive.SignIn XboxLive.offline_access");
|
oauth2.setScope("XboxLive.SignIn XboxLive.offline_access");
|
||||||
@ -67,9 +119,27 @@ MSAStep::MSAStep(AccountData* data, bool silent) : AuthStep(data), m_silent(sile
|
|||||||
emit finished(AccountTaskState::STATE_WORKING, tr("Got "));
|
emit finished(AccountTaskState::STATE_WORKING, tr("Got "));
|
||||||
});
|
});
|
||||||
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, this, &MSAStep::authorizeWithBrowser);
|
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, this, &MSAStep::authorizeWithBrowser);
|
||||||
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::requestFailed, this, [this](const QAbstractOAuth2::Error err) {
|
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::requestFailed, this, [this, silent](const QAbstractOAuth2::Error err) {
|
||||||
emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Microsoft user authentication failed."));
|
auto state = AccountTaskState::STATE_FAILED_HARD;
|
||||||
|
if (oauth2.status() == QAbstractOAuth::Status::Granted || silent) {
|
||||||
|
if (err == QAbstractOAuth2::Error::NetworkError) {
|
||||||
|
state = AccountTaskState::STATE_OFFLINE;
|
||||||
|
} else {
|
||||||
|
state = AccountTaskState::STATE_FAILED_SOFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto message = tr("Microsoft user authentication failed.");
|
||||||
|
if (silent) {
|
||||||
|
message = tr("Failed to refresh token.");
|
||||||
|
}
|
||||||
|
qWarning() << message;
|
||||||
|
emit finished(state, message);
|
||||||
});
|
});
|
||||||
|
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::error, this,
|
||||||
|
[this](const QString& error, const QString& errorDescription, const QUrl& uri) {
|
||||||
|
qWarning() << "Failed to login because" << error << errorDescription;
|
||||||
|
emit finished(AccountTaskState::STATE_FAILED_HARD, errorDescription);
|
||||||
|
});
|
||||||
|
|
||||||
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::extraTokensChanged, this,
|
connect(&oauth2, &QOAuth2AuthorizationCodeFlow::extraTokensChanged, this,
|
||||||
[this](const QVariantMap& tokens) { m_data->msaToken.extra = tokens; });
|
[this](const QVariantMap& tokens) { m_data->msaToken.extra = tokens; });
|
||||||
@ -89,20 +159,27 @@ void MSAStep::perform()
|
|||||||
if (m_data->msaClientID != m_clientId) {
|
if (m_data->msaClientID != m_clientId) {
|
||||||
emit finished(AccountTaskState::STATE_DISABLED,
|
emit finished(AccountTaskState::STATE_DISABLED,
|
||||||
tr("Microsoft user authentication failed - client identification has changed."));
|
tr("Microsoft user authentication failed - client identification has changed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_data->msaToken.refresh_token.isEmpty()) {
|
||||||
|
emit finished(AccountTaskState::STATE_DISABLED, tr("Microsoft user authentication failed - refresh token is empty."));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
oauth2.setRefreshToken(m_data->msaToken.refresh_token);
|
oauth2.setRefreshToken(m_data->msaToken.refresh_token);
|
||||||
oauth2.refreshAccessToken();
|
oauth2.refreshAccessToken();
|
||||||
} else {
|
} else {
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // QMultiMap param changed in 6.0
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // QMultiMap param changed in 6.0
|
||||||
oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMultiMap<QString, QVariant>* map) {
|
oauth2.setModifyParametersFunction(
|
||||||
|
[](QAbstractOAuth::Stage stage, QMultiMap<QString, QVariant>* map) { map->insert("prompt", "select_account"); });
|
||||||
#else
|
#else
|
||||||
oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMap<QString, QVariant>* map) {
|
oauth2.setModifyParametersFunction(
|
||||||
|
[](QAbstractOAuth::Stage stage, QMap<QString, QVariant>* map) { map->insert("prompt", "select_account"); });
|
||||||
#endif
|
#endif
|
||||||
map->insert("prompt", "select_account");
|
|
||||||
});
|
|
||||||
|
|
||||||
*m_data = AccountData();
|
*m_data = AccountData();
|
||||||
m_data->msaClientID = m_clientId;
|
m_data->msaClientID = m_clientId;
|
||||||
oauth2.grant();
|
oauth2.grant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "MSAStep.moc"
|
@ -36,7 +36,7 @@ void MinecraftProfileStep::onRequestDone()
|
|||||||
if (m_task->error() == QNetworkReply::ContentNotFoundError) {
|
if (m_task->error() == QNetworkReply::ContentNotFoundError) {
|
||||||
// NOTE: Succeed even if we do not have a profile. This is a valid account state.
|
// NOTE: Succeed even if we do not have a profile. This is a valid account state.
|
||||||
m_data->minecraftProfile = MinecraftProfile();
|
m_data->minecraftProfile = MinecraftProfile();
|
||||||
emit finished(AccountTaskState::STATE_SUCCEEDED, tr("Account has no Minecraft profile."));
|
emit finished(AccountTaskState::STATE_WORKING, tr("Account has no Minecraft profile."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_task->error() != QNetworkReply::NoError) {
|
if (m_task->error() != QNetworkReply::NoError) {
|
||||||
|
@ -107,7 +107,11 @@ void NetRequest::executeTask()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||||
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
|
request.setTransferTimeout(APPLICATION->settings()->get("RequestTimeout").toInt() * 1000);
|
||||||
|
#else
|
||||||
request.setTransferTimeout();
|
request.setTransferTimeout();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_last_progress_time = m_clock.now();
|
m_last_progress_time = m_clock.now();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<RCC version="1.0">
|
<RCC version="1.0">
|
||||||
<qresource prefix="/documents">
|
<qresource prefix="/documents">
|
||||||
<file>../../../COPYING.md</file>
|
<file>../../../COPYING.md</file>
|
||||||
|
<file>login-qr.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
||||||
|
8
launcher/resources/documents/login-qr.svg
Normal file
8
launcher/resources/documents/login-qr.svg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<svg width="33" height="33" version="1.1" viewBox="0 0 8.7312 8.7312" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g transform="scale(.26458)">
|
||||||
|
<rect width="33" height="33" fill="#fff"/>
|
||||||
|
<g>
|
||||||
|
<path d="m29 29h-6v-1h1v-3h-1v2h-1v-1h-1v1h-2v-1h1v-2h-1v-1h1v-1h-1v-1h1v-1h1v-1h1v1h1v-1h1v-1h-5v3h-2v-1h1v-1h-1v1h-2v-1h1v-1h1v-1h-1v1h-1v1h-1v-2h1v-2h2v-2h1v2h2v1h-1v1h2v-2h-1v-3h-1v-1h1v-2h-2v-1h-1v-1h-1v2h-2v1h-1v-1h-1v-3h1v1h1v1h1v-2h2v-2h1v3h3v5h1v1h-1v1h2v-1h1v1h1v1h2v1h2v2h-1v-1h-2v-1h-1v4h3v-1h1v7h-1v1h-1v1h2zm-10 0h-5v-1h3v-1h1v1h1zm-6 0h-1v-4h3v-1h1v2h1v1h-2v-1h-2zm-2 0h-7v-7h7zm15-1v-2h-1v2zm-16 0v-5h-5v5zm-1-1h-3v-3h3zm9-1h-1v-1h1zm10-1v-1h-1v-1h-1v-2h-1v3h1v1zm-9 0h-1v-1h1zm5-1v-3h-3v3zm-7 0h-1v-2h-1v1h-2v-1h-1v-1h-3v-1h6v1h2v1h2v1h-2zm6-1h-1v-1h1zm5-1v-1h-1v1zm-21-1h-1v-2h1zm-2-1h-1v-1h1zm23-1h-2v-1h2zm-17 0h-4v-1h1v-1h1v1h2zm-5 0h-1v-3h1v-1h1v-1h-1v1h-2v-3h4v1h2v1h-2v1h2v1h2v-1h1v1h1v1h-5v-1h-1v1h-2zm18-2v-2h-2v1h1v1zm-13-2h-1v-1h1zm17-1h-1v-1h1zm-14 0h-1v-1h1zm-2 0h-1v-1h1zm17-1h-1v-1h1zm-2 0h-3v-1h3zm-8 0h-1v-1h1zm-6 0h-1v-1h1zm-2 0h-1v-1h1zm5-1h-1v-1h1zm-2 0h-1v-1h1zm15-1h-7v-7h7zm-10 0h-1v-1h1zm-2 0h-1v-2h1zm-2 0h-1v-1h1zm-2 0h-1v-1h1zm-2 0h-7v-7h7zm17-1v-5h-5v5zm-18 0v-5h-5v5zm17-1h-3v-3h3zm-18 0h-3v-3h3zm5-4h-2v-1h2z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -972,6 +972,14 @@ void MainWindow::processURLs(QList<QUrl> urls)
|
|||||||
dlUrlDialod.execWithTask(job.get());
|
dlUrlDialod.execWithTask(job.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (url.scheme() == BuildConfig.LAUNCHER_APP_BINARY_NAME) {
|
||||||
|
QVariantMap receivedData;
|
||||||
|
const QUrlQuery query(url.query());
|
||||||
|
const auto items = query.queryItems();
|
||||||
|
for (auto it = items.begin(), end = items.end(); it != end; ++it)
|
||||||
|
receivedData.insert(it->first, it->second);
|
||||||
|
emit APPLICATION->oauthReplyRecieved(receivedData);
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
dl_url = url;
|
dl_url = url;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MSALoginDialog.h"
|
#include "MSALoginDialog.h"
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
#include "ui_MSALoginDialog.h"
|
#include "ui_MSALoginDialog.h"
|
||||||
|
|
||||||
#include "DesktopServices.h"
|
#include "DesktopServices.h"
|
||||||
@ -41,6 +43,7 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
|
#include <QPixmap>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QtWidgets/QPushButton>
|
#include <QtWidgets/QPushButton>
|
||||||
|
|
||||||
@ -48,28 +51,48 @@ MSALoginDialog::MSALoginDialog(QWidget* parent) : QDialog(parent), ui(new Ui::MS
|
|||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
ui->cancel->setEnabled(false);
|
// make font monospace
|
||||||
ui->link->setVisible(false);
|
QFont font;
|
||||||
ui->copy->setVisible(false);
|
font.setPixelSize(ui->code->fontInfo().pixelSize());
|
||||||
ui->progressBar->setVisible(false);
|
font.setFamily(APPLICATION->settings()->get("ConsoleFont").toString());
|
||||||
|
font.setStyleHint(QFont::Monospace);
|
||||||
|
font.setFixedPitch(true);
|
||||||
|
ui->code->setFont(font);
|
||||||
|
|
||||||
connect(ui->cancel, &QPushButton::pressed, this, &QDialog::reject);
|
connect(ui->copyCode, &QPushButton::clicked, this, [this] { QApplication::clipboard()->setText(ui->code->text()); });
|
||||||
connect(ui->copy, &QPushButton::pressed, this, &MSALoginDialog::copyUrl);
|
ui->qr->setPixmap(QIcon((":/documents/login-qr.svg")).pixmap(QSize(150, 150)));
|
||||||
|
connect(ui->loginButton, &QPushButton::clicked, this, [this] {
|
||||||
|
if (m_url.isValid()) {
|
||||||
|
if (!DesktopServices::openUrl(m_url)) {
|
||||||
|
QApplication::clipboard()->setText(m_url.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int MSALoginDialog::exec()
|
int MSALoginDialog::exec()
|
||||||
{
|
{
|
||||||
// Setup the login task and start it
|
// Setup the login task and start it
|
||||||
m_account = MinecraftAccount::createBlankMSA();
|
m_account = MinecraftAccount::createBlankMSA();
|
||||||
m_task = m_account->login(m_using_device_code);
|
m_authflow_task = m_account->login(false);
|
||||||
connect(m_task.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed);
|
connect(m_authflow_task.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed);
|
||||||
connect(m_task.get(), &Task::succeeded, this, &MSALoginDialog::onTaskSucceeded);
|
connect(m_authflow_task.get(), &Task::succeeded, this, &QDialog::accept);
|
||||||
connect(m_task.get(), &Task::status, this, &MSALoginDialog::onTaskStatus);
|
connect(m_authflow_task.get(), &Task::aborted, this, &MSALoginDialog::reject);
|
||||||
connect(m_task.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser);
|
connect(m_authflow_task.get(), &Task::status, this, &MSALoginDialog::onTaskStatus);
|
||||||
connect(m_task.get(), &AuthFlow::authorizeWithBrowserWithExtra, this, &MSALoginDialog::authorizeWithBrowserWithExtra);
|
connect(m_authflow_task.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser);
|
||||||
connect(ui->cancel, &QPushButton::pressed, m_task.get(), &Task::abort);
|
connect(m_authflow_task.get(), &AuthFlow::authorizeWithBrowserWithExtra, this, &MSALoginDialog::authorizeWithBrowserWithExtra);
|
||||||
connect(&m_external_timer, &QTimer::timeout, this, &MSALoginDialog::externalLoginTick);
|
connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, m_authflow_task.get(), &Task::abort);
|
||||||
m_task->start();
|
|
||||||
|
m_devicecode_task.reset(new AuthFlow(m_account->accountData(), AuthFlow::Action::DeviceCode, this));
|
||||||
|
connect(m_devicecode_task.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed);
|
||||||
|
connect(m_devicecode_task.get(), &Task::succeeded, this, &QDialog::accept);
|
||||||
|
connect(m_devicecode_task.get(), &Task::aborted, this, &MSALoginDialog::reject);
|
||||||
|
connect(m_devicecode_task.get(), &Task::status, this, &MSALoginDialog::onTaskStatus);
|
||||||
|
connect(m_devicecode_task.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser);
|
||||||
|
connect(m_devicecode_task.get(), &AuthFlow::authorizeWithBrowserWithExtra, this, &MSALoginDialog::authorizeWithBrowserWithExtra);
|
||||||
|
connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, m_devicecode_task.get(), &Task::abort);
|
||||||
|
QMetaObject::invokeMethod(m_authflow_task.get(), &Task::start, Qt::QueuedConnection);
|
||||||
|
QMetaObject::invokeMethod(m_devicecode_task.get(), &Task::start, Qt::QueuedConnection);
|
||||||
|
|
||||||
return QDialog::exec();
|
return QDialog::exec();
|
||||||
}
|
}
|
||||||
@ -79,9 +102,12 @@ MSALoginDialog::~MSALoginDialog()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSALoginDialog::onTaskFailed(const QString& reason)
|
void MSALoginDialog::onTaskFailed(QString reason)
|
||||||
{
|
{
|
||||||
// Set message
|
// Set message
|
||||||
|
m_authflow_task->disconnect();
|
||||||
|
m_devicecode_task->disconnect();
|
||||||
|
ui->stackedWidget->setCurrentIndex(0);
|
||||||
auto lines = reason.split('\n');
|
auto lines = reason.split('\n');
|
||||||
QString processed;
|
QString processed;
|
||||||
for (auto line : lines) {
|
for (auto line : lines) {
|
||||||
@ -91,91 +117,53 @@ void MSALoginDialog::onTaskFailed(const QString& reason)
|
|||||||
processed += "<br />";
|
processed += "<br />";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui->message->setText(processed);
|
ui->status->setText(processed);
|
||||||
}
|
auto task = m_authflow_task;
|
||||||
|
if (task->failReason().isEmpty()) {
|
||||||
void MSALoginDialog::onTaskSucceeded()
|
task = m_devicecode_task;
|
||||||
{
|
|
||||||
QDialog::accept();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MSALoginDialog::onTaskStatus(const QString& status)
|
|
||||||
{
|
|
||||||
ui->message->setText(status);
|
|
||||||
ui->cancel->setEnabled(false);
|
|
||||||
ui->link->setVisible(false);
|
|
||||||
ui->copy->setVisible(false);
|
|
||||||
ui->progressBar->setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public interface
|
|
||||||
MinecraftAccountPtr MSALoginDialog::newAccount(QWidget* parent, QString msg, bool usingDeviceCode)
|
|
||||||
{
|
|
||||||
MSALoginDialog dlg(parent);
|
|
||||||
dlg.m_using_device_code = usingDeviceCode;
|
|
||||||
dlg.ui->message->setText(msg);
|
|
||||||
if (dlg.exec() == QDialog::Accepted) {
|
|
||||||
return dlg.m_account;
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
if (task) {
|
||||||
|
ui->loadingLabel->setText(task->getStatus());
|
||||||
|
}
|
||||||
|
disconnect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, m_authflow_task.get(), &Task::abort);
|
||||||
|
disconnect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, m_devicecode_task.get(), &Task::abort);
|
||||||
|
connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &MSALoginDialog::reject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSALoginDialog::authorizeWithBrowser(const QUrl& url)
|
void MSALoginDialog::authorizeWithBrowser(const QUrl& url)
|
||||||
{
|
{
|
||||||
ui->cancel->setEnabled(true);
|
ui->stackedWidget->setCurrentIndex(1);
|
||||||
ui->link->setVisible(true);
|
ui->loginButton->setToolTip(QString("<div style='width: 200px;'>%1</div>").arg(url.toString()));
|
||||||
ui->copy->setVisible(true);
|
m_url = url;
|
||||||
DesktopServices::openUrl(url);
|
|
||||||
ui->link->setText(url.toDisplayString());
|
|
||||||
ui->message->setText(
|
|
||||||
tr("Browser opened to complete the login process."
|
|
||||||
"<br /><br />"
|
|
||||||
"If your browser hasn't opened, please manually open the below link in your browser:"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MSALoginDialog::copyUrl()
|
|
||||||
{
|
|
||||||
QClipboard* cb = QApplication::clipboard();
|
|
||||||
cb->setText(ui->link->text());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSALoginDialog::authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn)
|
void MSALoginDialog::authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn)
|
||||||
{
|
{
|
||||||
m_external_elapsed = 0;
|
ui->stackedWidget->setCurrentIndex(1);
|
||||||
m_external_timeout = expiresIn;
|
|
||||||
|
|
||||||
m_external_timer.setInterval(1000);
|
const auto linkString = QString("<a href=\"%1\">%2</a>").arg(url, url);
|
||||||
m_external_timer.setSingleShot(false);
|
ui->code->setText(code);
|
||||||
m_external_timer.start();
|
auto isDefaultUrl = url == "https://www.microsoft.com/link";
|
||||||
|
ui->qr->setVisible(isDefaultUrl);
|
||||||
ui->progressBar->setMaximum(expiresIn);
|
if (isDefaultUrl) {
|
||||||
ui->progressBar->setValue(m_external_elapsed);
|
ui->qrMessage->setText(tr("Open %1 or scan the QR and enter the above code.").arg(linkString));
|
||||||
|
|
||||||
QString linkString = QString("<a href=\"%1\">%2</a>").arg(url, url);
|
|
||||||
if (url == "https://www.microsoft.com/link" && !code.isEmpty()) {
|
|
||||||
url += QString("?otc=%1").arg(code);
|
|
||||||
ui->message->setText(tr("<p>Please login in the opened browser. If no browser was opened, please open up %1 in "
|
|
||||||
"a browser and put in the code <b>%2</b> to proceed with login.</p>")
|
|
||||||
.arg(linkString, code));
|
|
||||||
} else {
|
} else {
|
||||||
ui->message->setText(
|
ui->qrMessage->setText(tr("Open %1 and enter the above code.").arg(linkString));
|
||||||
tr("<p>Please open up %1 in a browser and put in the code <b>%2</b> to proceed with login.</p>").arg(linkString, code));
|
|
||||||
}
|
}
|
||||||
ui->cancel->setEnabled(true);
|
|
||||||
ui->link->setVisible(true);
|
|
||||||
ui->copy->setVisible(true);
|
|
||||||
ui->progressBar->setVisible(true);
|
|
||||||
DesktopServices::openUrl(url);
|
|
||||||
ui->link->setText(code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSALoginDialog::externalLoginTick()
|
void MSALoginDialog::onTaskStatus(QString status)
|
||||||
{
|
{
|
||||||
m_external_elapsed++;
|
ui->stackedWidget->setCurrentIndex(0);
|
||||||
ui->progressBar->setValue(m_external_elapsed);
|
ui->status->setText(status);
|
||||||
ui->progressBar->repaint();
|
}
|
||||||
|
|
||||||
if (m_external_elapsed >= m_external_timeout) {
|
// Public interface
|
||||||
m_external_timer.stop();
|
MinecraftAccountPtr MSALoginDialog::newAccount(QWidget* parent)
|
||||||
|
{
|
||||||
|
MSALoginDialog dlg(parent);
|
||||||
|
if (dlg.exec() == QDialog::Accepted) {
|
||||||
|
return dlg.m_account;
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
@ -32,29 +32,23 @@ class MSALoginDialog : public QDialog {
|
|||||||
public:
|
public:
|
||||||
~MSALoginDialog();
|
~MSALoginDialog();
|
||||||
|
|
||||||
static MinecraftAccountPtr newAccount(QWidget* parent, QString message, bool usingDeviceCode = false);
|
static MinecraftAccountPtr newAccount(QWidget* parent);
|
||||||
int exec() override;
|
int exec() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit MSALoginDialog(QWidget* parent = 0);
|
explicit MSALoginDialog(QWidget* parent = 0);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void onTaskFailed(const QString& reason);
|
void onTaskFailed(QString reason);
|
||||||
void onTaskSucceeded();
|
void onTaskStatus(QString status);
|
||||||
void onTaskStatus(const QString& status);
|
|
||||||
void authorizeWithBrowser(const QUrl& url);
|
void authorizeWithBrowser(const QUrl& url);
|
||||||
void authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn);
|
void authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn);
|
||||||
void copyUrl();
|
|
||||||
void externalLoginTick();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MSALoginDialog* ui;
|
Ui::MSALoginDialog* ui;
|
||||||
MinecraftAccountPtr m_account;
|
MinecraftAccountPtr m_account;
|
||||||
shared_qobject_ptr<AuthFlow> m_task;
|
shared_qobject_ptr<AuthFlow> m_devicecode_task;
|
||||||
|
shared_qobject_ptr<AuthFlow> m_authflow_task;
|
||||||
|
|
||||||
int m_external_elapsed;
|
QUrl m_url;
|
||||||
int m_external_timeout;
|
|
||||||
QTimer m_external_timer;
|
|
||||||
|
|
||||||
bool m_using_device_code = false;
|
|
||||||
};
|
};
|
||||||
|
@ -6,87 +6,345 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>491</width>
|
<width>440</width>
|
||||||
<height>208</height>
|
<height>430</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="minimumSize">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="MinimumExpanding">
|
<size>
|
||||||
<horstretch>0</horstretch>
|
<width>0</width>
|
||||||
<verstretch>0</verstretch>
|
<height>430</height>
|
||||||
</sizepolicy>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Add Microsoft Account</string>
|
<string>Add Microsoft Account</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="message">
|
<widget class="QStackedWidget" name="stackedWidget">
|
||||||
<property name="sizePolicy">
|
<property name="currentIndex">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
<number>1</number>
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>500</width>
|
|
||||||
<height>500</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true"/>
|
|
||||||
</property>
|
|
||||||
<property name="textFormat">
|
|
||||||
<enum>Qt::RichText</enum>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="openExternalLinks">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="textInteractionFlags">
|
|
||||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
|
||||||
</property>
|
</property>
|
||||||
|
<widget class="QWidget" name="loadingPage">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="loadingLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>16</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Please wait...</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="status">
|
||||||
|
<property name="text">
|
||||||
|
<string>Status</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="mpPage">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0,0,0">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_5">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="loginButton">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>250</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Sign in with Microsoft</string>
|
||||||
|
</property>
|
||||||
|
<property name="default">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_6">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="orLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>16</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Or</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_4">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="qr">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>150</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>150</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="code">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>30</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="cursor">
|
||||||
|
<cursorShape>IBeamCursor</cursorShape>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>CODE</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::TextBrowserInteraction</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="copyCode">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Copy code to clipboard</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="copy">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="qrMessage">
|
||||||
|
<property name="text">
|
||||||
|
<string>Info</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::TextBrowserInteraction</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="linkLayout">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<item>
|
<property name="standardButtons">
|
||||||
<widget class="QLineEdit" name="link">
|
<set>QDialogButtonBox::Cancel</set>
|
||||||
<property name="readOnly">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="copy">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset theme="copy">
|
|
||||||
<normaloff>.</normaloff>.</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QProgressBar" name="progressBar">
|
|
||||||
<property name="value">
|
|
||||||
<number>24</number>
|
|
||||||
</property>
|
|
||||||
<property name="textVisible">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="cancel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Cancel</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -145,6 +145,7 @@ void ResourceDownloadDialog::confirm()
|
|||||||
confirm_dialog->retranslateUi(resourcesString());
|
confirm_dialog->retranslateUi(resourcesString());
|
||||||
|
|
||||||
QHash<QString, GetModDependenciesTask::PackDependencyExtraInfo> dependencyExtraInfo;
|
QHash<QString, GetModDependenciesTask::PackDependencyExtraInfo> dependencyExtraInfo;
|
||||||
|
QStringList depNames;
|
||||||
if (auto task = getModDependenciesTask(); task) {
|
if (auto task = getModDependenciesTask(); task) {
|
||||||
connect(task.get(), &Task::failed, this,
|
connect(task.get(), &Task::failed, this,
|
||||||
[&](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
|
[&](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
|
||||||
@ -167,8 +168,10 @@ void ResourceDownloadDialog::confirm()
|
|||||||
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
for (auto dep : task->getDependecies())
|
for (auto dep : task->getDependecies()) {
|
||||||
addResource(dep->pack, dep->version);
|
addResource(dep->pack, dep->version);
|
||||||
|
depNames << dep->pack->name;
|
||||||
|
}
|
||||||
dependencyExtraInfo = task->getExtraInfo();
|
dependencyExtraInfo = task->getExtraInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,6 +196,9 @@ void ResourceDownloadDialog::confirm()
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->accept();
|
this->accept();
|
||||||
|
} else {
|
||||||
|
for (auto name : depNames)
|
||||||
|
removeResource(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,20 +130,7 @@ void AccountListPage::listChanged()
|
|||||||
|
|
||||||
void AccountListPage::on_actionAddMicrosoft_triggered()
|
void AccountListPage::on_actionAddMicrosoft_triggered()
|
||||||
{
|
{
|
||||||
QMessageBox box(this);
|
auto account = MSALoginDialog::newAccount(this);
|
||||||
box.setWindowTitle(tr("Add account"));
|
|
||||||
box.setText(tr("How do you want to login?"));
|
|
||||||
box.setIcon(QMessageBox::Question);
|
|
||||||
auto deviceCode = box.addButton(tr("Legacy"), QMessageBox::ButtonRole::YesRole);
|
|
||||||
auto authCode = box.addButton(tr("Recommended"), QMessageBox::ButtonRole::NoRole);
|
|
||||||
auto cancel = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::RejectRole);
|
|
||||||
box.setDefaultButton(authCode);
|
|
||||||
box.exec();
|
|
||||||
if ((box.clickedButton() != deviceCode && box.clickedButton() != authCode) || box.clickedButton() == cancel)
|
|
||||||
return;
|
|
||||||
MinecraftAccountPtr account = MSALoginDialog::newAccount(
|
|
||||||
this, tr("Please enter your Mojang account email and password to add your account."), box.clickedButton() == deviceCode);
|
|
||||||
|
|
||||||
if (account) {
|
if (account) {
|
||||||
m_accounts->addAccount(account);
|
m_accounts->addAccount(account);
|
||||||
if (m_accounts->count() == 1) {
|
if (m_accounts->count() == 1) {
|
||||||
|
@ -213,6 +213,7 @@ void LauncherPage::applySettings()
|
|||||||
|
|
||||||
s->set("NumberOfConcurrentTasks", ui->numberOfConcurrentTasksSpinBox->value());
|
s->set("NumberOfConcurrentTasks", ui->numberOfConcurrentTasksSpinBox->value());
|
||||||
s->set("NumberOfConcurrentDownloads", ui->numberOfConcurrentDownloadsSpinBox->value());
|
s->set("NumberOfConcurrentDownloads", ui->numberOfConcurrentDownloadsSpinBox->value());
|
||||||
|
s->set("RequestTimeout", ui->timeoutSecondsSpinBox->value());
|
||||||
|
|
||||||
// Console settings
|
// Console settings
|
||||||
s->set("ShowConsole", ui->showConsoleCheck->isChecked());
|
s->set("ShowConsole", ui->showConsoleCheck->isChecked());
|
||||||
@ -270,6 +271,7 @@ void LauncherPage::loadSettings()
|
|||||||
|
|
||||||
ui->numberOfConcurrentTasksSpinBox->setValue(s->get("NumberOfConcurrentTasks").toInt());
|
ui->numberOfConcurrentTasksSpinBox->setValue(s->get("NumberOfConcurrentTasks").toInt());
|
||||||
ui->numberOfConcurrentDownloadsSpinBox->setValue(s->get("NumberOfConcurrentDownloads").toInt());
|
ui->numberOfConcurrentDownloadsSpinBox->setValue(s->get("NumberOfConcurrentDownloads").toInt());
|
||||||
|
ui->timeoutSecondsSpinBox->setValue(s->get("RequestTimeout").toInt());
|
||||||
|
|
||||||
// Console settings
|
// Console settings
|
||||||
ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool());
|
ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool());
|
||||||
|
@ -272,6 +272,13 @@
|
|||||||
<string>Miscellaneous</string>
|
<string>Miscellaneous</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QSpinBox" name="numberOfConcurrentDownloadsSpinBox">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="numberOfConcurrentTasksLabel">
|
<widget class="QLabel" name="numberOfConcurrentTasksLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -293,10 +300,20 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="2" column="0">
|
||||||
<widget class="QSpinBox" name="numberOfConcurrentDownloadsSpinBox">
|
<widget class="QLabel" name="timeoutSecondsLabel">
|
||||||
<property name="minimum">
|
<property name="toolTip">
|
||||||
<number>1</number>
|
<string>Seconds to wait until the requests are terminated</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Timeout for HTTP requests</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QSpinBox" name="timeoutSecondsSpinBox">
|
||||||
|
<property name="suffix">
|
||||||
|
<string>s</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -104,7 +104,7 @@ void ImportPage::updateState()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ui->modpackEdit->hasAcceptableInput()) {
|
if (ui->modpackEdit->hasAcceptableInput()) {
|
||||||
QString input = ui->modpackEdit->text();
|
QString input = ui->modpackEdit->text().trimmed();
|
||||||
auto url = QUrl::fromUserInput(input);
|
auto url = QUrl::fromUserInput(input);
|
||||||
if (url.isLocalFile()) {
|
if (url.isLocalFile()) {
|
||||||
// FIXME: actually do some validation of what's inside here... this is fake AF
|
// FIXME: actually do some validation of what's inside here... this is fake AF
|
||||||
|
@ -85,6 +85,11 @@ PrismExternalUpdater::~PrismExternalUpdater()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PrismExternalUpdater::checkForUpdates()
|
void PrismExternalUpdater::checkForUpdates()
|
||||||
|
{
|
||||||
|
checkForUpdates(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrismExternalUpdater::checkForUpdates(bool triggeredByUser)
|
||||||
{
|
{
|
||||||
QProgressDialog progress(tr("Checking for updates..."), "", 0, 0, priv->parent);
|
QProgressDialog progress(tr("Checking for updates..."), "", 0, 0, priv->parent);
|
||||||
progress.setCancelButton(nullptr);
|
progress.setCancelButton(nullptr);
|
||||||
@ -160,7 +165,7 @@ void PrismExternalUpdater::checkForUpdates()
|
|||||||
switch (exit_code) {
|
switch (exit_code) {
|
||||||
case 0:
|
case 0:
|
||||||
// no update available
|
// no update available
|
||||||
{
|
if (triggeredByUser) {
|
||||||
qDebug() << "No update available";
|
qDebug() << "No update available";
|
||||||
auto msgBox = QMessageBox(QMessageBox::Information, tr("No Update Available"), tr("You are running the latest version."),
|
auto msgBox = QMessageBox(QMessageBox::Information, tr("No Update Available"), tr("You are running the latest version."),
|
||||||
QMessageBox::Ok, priv->parent);
|
QMessageBox::Ok, priv->parent);
|
||||||
@ -288,7 +293,7 @@ void PrismExternalUpdater::disconnectTimer()
|
|||||||
void PrismExternalUpdater::autoCheckTimerFired()
|
void PrismExternalUpdater::autoCheckTimerFired()
|
||||||
{
|
{
|
||||||
qDebug() << "Auto update Timer fired";
|
qDebug() << "Auto update Timer fired";
|
||||||
checkForUpdates();
|
checkForUpdates(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrismExternalUpdater::offerUpdate(const QString& version_name, const QString& version_tag, const QString& release_notes)
|
void PrismExternalUpdater::offerUpdate(const QString& version_name, const QString& version_tag, const QString& release_notes)
|
||||||
|
@ -41,6 +41,7 @@ class PrismExternalUpdater : public ExternalUpdater {
|
|||||||
* Check for updates manually, showing the user a progress bar and an alert if no updates are found.
|
* Check for updates manually, showing the user a progress bar and an alert if no updates are found.
|
||||||
*/
|
*/
|
||||||
void checkForUpdates() override;
|
void checkForUpdates() override;
|
||||||
|
void checkForUpdates(bool triggeredByUser);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Indicates whether or not to check for updates automatically.
|
* Indicates whether or not to check for updates automatically.
|
||||||
|
@ -244,8 +244,9 @@ PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, ar
|
|||||||
|
|
||||||
auto updater_executable = QCoreApplication::applicationFilePath();
|
auto updater_executable = QCoreApplication::applicationFilePath();
|
||||||
|
|
||||||
if (BuildConfig.BUILD_ARTIFACT.toLower() == "macos")
|
#ifdef Q_OS_MACOS
|
||||||
showFatalErrorMessage(tr("MacOS Not Supported"), tr("The updater does not support installations on MacOS"));
|
showFatalErrorMessage(tr("MacOS Not Supported"), tr("The updater does not support installations on MacOS"));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (updater_executable.startsWith("/tmp/.mount_")) {
|
if (updater_executable.startsWith("/tmp/.mount_")) {
|
||||||
m_isAppimage = true;
|
m_isAppimage = true;
|
||||||
@ -327,6 +328,19 @@ PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, ar
|
|||||||
// on command line
|
// on command line
|
||||||
adjustedBy = "Command line";
|
adjustedBy = "Command line";
|
||||||
m_dataPath = dirParam;
|
m_dataPath = dirParam;
|
||||||
|
#ifndef Q_OS_MACOS
|
||||||
|
if (QDir(FS::PathCombine(m_rootPath, "UserData")).exists()) {
|
||||||
|
m_isPortable = true;
|
||||||
|
}
|
||||||
|
if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
||||||
|
m_isPortable = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (auto dataDirEnv =
|
||||||
|
QProcessEnvironment::systemEnvironment().value(QString("%1_DATA_DIR").arg(BuildConfig.LAUNCHER_NAME.toUpper()));
|
||||||
|
!dataDirEnv.isEmpty()) {
|
||||||
|
adjustedBy = "System environment";
|
||||||
|
m_dataPath = dataDirEnv;
|
||||||
#ifndef Q_OS_MACOS
|
#ifndef Q_OS_MACOS
|
||||||
if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
||||||
m_isPortable = true;
|
m_isPortable = true;
|
||||||
@ -338,7 +352,11 @@ PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, ar
|
|||||||
adjustedBy = "Persistent data path";
|
adjustedBy = "Persistent data path";
|
||||||
|
|
||||||
#ifndef Q_OS_MACOS
|
#ifndef Q_OS_MACOS
|
||||||
if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
if (auto portableUserData = FS::PathCombine(m_rootPath, "UserData"); QDir(portableUserData).exists()) {
|
||||||
|
m_dataPath = portableUserData;
|
||||||
|
adjustedBy = "Portable user data path";
|
||||||
|
m_isPortable = true;
|
||||||
|
} else if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
||||||
m_dataPath = m_rootPath;
|
m_dataPath = m_rootPath;
|
||||||
adjustedBy = "Portable data path";
|
adjustedBy = "Portable data path";
|
||||||
m_isPortable = true;
|
m_isPortable = true;
|
||||||
@ -580,12 +598,6 @@ void PrismUpdaterApp::run()
|
|||||||
return exit(result ? 0 : 1);
|
return exit(result ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BuildConfig.BUILD_ARTIFACT.toLower() == "linux" && !m_isPortable) {
|
|
||||||
showFatalErrorMessage(tr("Updating Not Supported"),
|
|
||||||
tr("Updating non-portable linux installations is not supported. Please use your system package manager"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (need_update || m_forceUpdate || !m_userSelectedVersion.isEmpty()) {
|
if (need_update || m_forceUpdate || !m_userSelectedVersion.isEmpty()) {
|
||||||
GitHubRelease update_release = latest;
|
GitHubRelease update_release = latest;
|
||||||
if (!m_userSelectedVersion.isEmpty()) {
|
if (!m_userSelectedVersion.isEmpty()) {
|
||||||
@ -787,6 +799,10 @@ QList<GitHubReleaseAsset> PrismUpdaterApp::validReleaseArtifacts(const GitHubRel
|
|||||||
if (BuildConfig.BUILD_ARTIFACT.isEmpty())
|
if (BuildConfig.BUILD_ARTIFACT.isEmpty())
|
||||||
qWarning() << "Build platform is not set!";
|
qWarning() << "Build platform is not set!";
|
||||||
for (auto asset : release.assets) {
|
for (auto asset : release.assets) {
|
||||||
|
if (asset.name.endsWith(".zsync")) {
|
||||||
|
qDebug() << "Rejecting zsync file" << asset.name;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!m_isAppimage && asset.name.toLower().endsWith("appimage")) {
|
if (!m_isAppimage && asset.name.toLower().endsWith("appimage")) {
|
||||||
qDebug() << "Rejecting" << asset.name << "because it is an AppImage";
|
qDebug() << "Rejecting" << asset.name << "because it is an AppImage";
|
||||||
continue;
|
continue;
|
||||||
@ -1020,7 +1036,7 @@ void PrismUpdaterApp::performInstall(QFileInfo file)
|
|||||||
FS::write(changelog_path, m_install_release.body.toUtf8());
|
FS::write(changelog_path, m_install_release.body.toUtf8());
|
||||||
|
|
||||||
logUpdate(tr("Updating from %1 to %2").arg(m_prismVersion).arg(m_install_release.tag_name));
|
logUpdate(tr("Updating from %1 to %2").arg(m_prismVersion).arg(m_install_release.tag_name));
|
||||||
if (m_isPortable || file.suffix().toLower() == "zip") {
|
if (m_isPortable || file.fileName().endsWith(".zip") || file.fileName().endsWith(".tar.gz")) {
|
||||||
write_lock_file(update_lock_path, QDateTime::currentDateTime(), m_prismVersion, m_install_release.tag_name, m_rootPath, m_dataPath);
|
write_lock_file(update_lock_path, QDateTime::currentDateTime(), m_prismVersion, m_install_release.tag_name, m_rootPath, m_dataPath);
|
||||||
logUpdate(tr("Updating portable install at %1").arg(m_rootPath));
|
logUpdate(tr("Updating portable install at %1").arg(m_rootPath));
|
||||||
unpackAndInstall(file);
|
unpackAndInstall(file);
|
||||||
@ -1094,7 +1110,7 @@ void PrismUpdaterApp::backupAppDir()
|
|||||||
|
|
||||||
if (file_list.isEmpty()) {
|
if (file_list.isEmpty()) {
|
||||||
// best guess
|
// best guess
|
||||||
if (BuildConfig.BUILD_ARTIFACT.toLower() == "linux") {
|
if (BuildConfig.BUILD_ARTIFACT.toLower().contains("linux")) {
|
||||||
file_list.append({ "PrismLauncher", "bin", "share", "lib" });
|
file_list.append({ "PrismLauncher", "bin", "share", "lib" });
|
||||||
} else { // windows by process of elimination
|
} else { // windows by process of elimination
|
||||||
file_list.append({
|
file_list.append({
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Version=1.0
|
Version=1.0
|
||||||
Name=Prism Launcher
|
Name=@Launcher_DisplayName@
|
||||||
Comment=Discover, manage, and play Minecraft instances
|
Comment=Discover, manage, and play Minecraft instances
|
||||||
Type=Application
|
Type=Application
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Exec=@Launcher_APP_BINARY_NAME@ %U
|
Exec=@Launcher_APP_BINARY_NAME@ %U
|
||||||
StartupNotify=true
|
StartupNotify=true
|
||||||
Icon=org.prismlauncher.PrismLauncher
|
Icon=org.@Launcher_APP_BINARY_NAME@.@Launcher_CommonName@
|
||||||
Categories=Game;ActionGame;AdventureGame;Simulation;
|
Categories=Game;ActionGame;AdventureGame;Simulation;
|
||||||
Keywords=game;minecraft;mc;
|
Keywords=game;minecraft;mc;
|
||||||
StartupWMClass=PrismLauncher
|
StartupWMClass=@Launcher_CommonName@
|
||||||
MimeType=application/zip;application/x-modrinth-modpack+zip;x-scheme-handler/curseforge;
|
MimeType=application/zip;application/x-modrinth-modpack+zip;x-scheme-handler/curseforge;x-scheme-handler/@Launcher_APP_BINARY_NAME@;
|
||||||
|
@ -368,6 +368,10 @@ Section "@Launcher_DisplayName@"
|
|||||||
WriteRegStr HKCU Software\Classes\curseforge "URL Protocol" ""
|
WriteRegStr HKCU Software\Classes\curseforge "URL Protocol" ""
|
||||||
WriteRegStr HKCU Software\Classes\curseforge\shell\open\command "" '"$INSTDIR\@Launcher_APP_BINARY_NAME@.exe" "%1"'
|
WriteRegStr HKCU Software\Classes\curseforge\shell\open\command "" '"$INSTDIR\@Launcher_APP_BINARY_NAME@.exe" "%1"'
|
||||||
|
|
||||||
|
; Write the URL Handler into registry for prismlauncher
|
||||||
|
WriteRegStr HKCU Software\Classes\prismlauncher "URL Protocol" ""
|
||||||
|
WriteRegStr HKCU Software\Classes\prismlauncher\shell\open\command "" '"$INSTDIR\@Launcher_APP_BINARY_NAME@.exe" "%1"'
|
||||||
|
|
||||||
; Write the uninstall keys for Windows
|
; Write the uninstall keys for Windows
|
||||||
${GetParameters} $R0
|
${GetParameters} $R0
|
||||||
${GetOptions} $R0 "/NoUninstaller" $R1
|
${GetOptions} $R0 "/NoUninstaller" $R1
|
||||||
|
Loading…
Reference in New Issue
Block a user