diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7e542d4e5..8077ea59a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -501,7 +501,7 @@ jobs: export SIGN=1 export SIGN_KEY=${{ secrets.GPG_PRIVATE_KEY_ID }} mkdir -p ~/.gnupg/ - printf "$GPG_PRIVATE_KEY" | base64 --decode > ~/.gnupg/private.key + echo "$GPG_PRIVATE_KEY" > ~/.gnupg/private.key gpg --import ~/.gnupg/private.key else echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY diff --git a/CMakeLists.txt b/CMakeLists.txt index be443fe31..faeb1c44e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -347,6 +347,11 @@ add_subdirectory(program_info) ####################################### Install layout ####################################### set(Launcher_ENABLE_UPDATER NO) +set(Launcher_BUILD_UPDATER NO) + +if (NOT APPLE AND (NOT Launcher_UPDATER_GITHUB_REPO STREQUAL "" AND NOT Launcher_BUILD_ARTIFACT STREQUAL "")) + set(Launcher_BUILD_UPDATER YES) +endif() if(NOT (UNIX AND APPLE)) # Install "portable.txt" if selected component is "portable" diff --git a/README.md b/README.md index 093bc94da..61bf4c20b 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ For **Arch**, **Debian**, **Fedora**, **OpenSUSE (Tumbleweed)** and **Gentoo**, [![prismlauncher-git](https://img.shields.io/badge/aur-prismlauncher--git-1793D1?label=AUR&logo=archlinux&logoColor=white)](https://aur.archlinux.org/packages/prismlauncher-git) [![prismlauncher-git](https://img.shields.io/badge/aur-prismlauncher--qt5--git-1793D1?label=AUR&logo=archlinux&logoColor=white)](https://aur.archlinux.org/packages/prismlauncher-qt5-git) [![prismlauncher-git](https://img.shields.io/badge/mpr-prismlauncher--git-A80030?label=MPR&logo=debian&logoColor=white)](https://mpr.makedeb.org/packages/prismlauncher-git)
[![prismlauncher-nightly](https://img.shields.io/badge/copr-prismlauncher--nightly-51A2DA?label=COPR&logo=fedora&logoColor=white)](https://copr.fedorainfracloud.org/coprs/g3tchoo/prismlauncher/) [![prismlauncher-nightly](https://img.shields.io/badge/OBS-prismlauncher--nightly-3AB6A9?logo=opensuse&logoColor=white)](https://build.opensuse.org/project/show/home:getchoo) [![prismlauncher-9999](https://img.shields.io/badge/gentoo-prismlauncher--9999-4D4270?label=Gentoo&logo=gentoo&logoColor=white)](https://packages.gentoo.org/packages/games-action/prismlauncher) -These packages are also availiable to all the distributions based on the ones mentioned above. +These packages are also available to all the distributions based on the ones mentioned above. ## Community & Support diff --git a/flake.lock b/flake.lock index ad18ff615..d71403358 100644 --- a/flake.lock +++ b/flake.lock @@ -106,11 +106,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1697009197, - "narHash": "sha256-viVRhBTFT8fPJTb1N3brQIpFZnttmwo3JVKNuWRVc3s=", + "lastModified": 1697886341, + "narHash": "sha256-AdE67xPty9M9wn36nPVp6aDntIdigrs7UbyaGv1VAaM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "01441e14af5e29c9d27ace398e6dd0b293e25a54", + "rev": "44881e03af1c730cbb1d72a4d41274a2c957813a", "type": "github" }, "original": { @@ -153,11 +153,11 @@ ] }, "locked": { - "lastModified": 1696846637, - "narHash": "sha256-0hv4kbXxci2+pxhuXlVgftj/Jq79VSmtAyvfabCCtYk=", + "lastModified": 1697746376, + "narHash": "sha256-gu77VkgdfaHgNCVufeb6WP9oqFLjwK4jHcoPZmBVF3E=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "42e1b6095ef80a51f79595d9951eb38e91c4e6ca", + "rev": "8cc349bfd082da8782b989cad2158c9ad5bd70fd", "type": "github" }, "original": { diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 906ab16cd..86e9541bd 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -1311,7 +1311,7 @@ install(TARGETS ${Launcher_Name} FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime ) -if(NOT APPLE OR (DEFINED Launcher_BUILD_UPDATER AND Launcher_BUILD_UPDATER)) +if(Launcher_BUILD_UPDATER) # Updater add_library(prism_updater_logic STATIC ${PRISMUPDATER_SOURCES} ${TASKS_SOURCES} ${PRISMUPDATER_UI}) target_include_directories(prism_updater_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 21a146062..9fb385777 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -106,7 +106,7 @@ void LaunchController::decideAccount() // Select the account to use. If the instance has a specific account set, that will be used. Otherwise, the default account will be used auto instanceAccountId = m_instance->settings()->get("InstanceAccountId").toString(); auto instanceAccountIndex = accounts->findAccountByProfileId(instanceAccountId); - if (instanceAccountIndex == -1) { + if (instanceAccountIndex == -1 || instanceAccountId.isEmpty()) { m_accountToUse = accounts->defaultAccount(); } else { m_accountToUse = accounts->at(instanceAccountIndex); diff --git a/launcher/minecraft/AssetsUtils.cpp b/launcher/minecraft/AssetsUtils.cpp index 4ef007075..48e150d16 100644 --- a/launcher/minecraft/AssetsUtils.cpp +++ b/launcher/minecraft/AssetsUtils.cpp @@ -48,6 +48,7 @@ #include "FileSystem.h" #include "net/ApiDownload.h" #include "net/ChecksumValidator.h" +#include "net/Download.h" #include "Application.h" diff --git a/launcher/net/StaticHeaderProxy.h b/launcher/net/StaticHeaderProxy.h index aabbc9c92..2c0d5ecc8 100644 --- a/launcher/net/StaticHeaderProxy.h +++ b/launcher/net/StaticHeaderProxy.h @@ -36,4 +36,4 @@ class StaticHeaderProxy : public HeaderProxy { QList m_hdrs; }; -} // namespace Net \ No newline at end of file +} // namespace Net diff --git a/launcher/screenshots/ImgurAlbumCreation.cpp b/launcher/screenshots/ImgurAlbumCreation.cpp index d548c89ae..7e42ff40c 100644 --- a/launcher/screenshots/ImgurAlbumCreation.cpp +++ b/launcher/screenshots/ImgurAlbumCreation.cpp @@ -39,87 +39,76 @@ #include #include #include +#include #include #include #include +#include -#include "Application.h" #include "BuildConfig.h" +#include "net/StaticHeaderProxy.h" -ImgurAlbumCreation::ImgurAlbumCreation(QList screenshots) : NetAction(), m_screenshots(screenshots) +Net::NetRequest::Ptr ImgurAlbumCreation::make(std::shared_ptr output, QList screenshots) { - m_url = BuildConfig.IMGUR_BASE_URL + "album.json"; - m_state = State::Inactive; + auto up = makeShared(); + up->m_url = BuildConfig.IMGUR_BASE_URL + "album.json"; + up->m_sink.reset(new Sink(output)); + up->m_screenshots = screenshots; + return up; } -void ImgurAlbumCreation::executeTask() +QNetworkReply* ImgurAlbumCreation::getReply(QNetworkRequest& request) { - m_state = State::Running; - QNetworkRequest request(m_url); - request.setHeader(QNetworkRequest::UserAgentHeader, APPLICATION->getUserAgentUncached().toUtf8()); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - request.setRawHeader("Authorization", QString("Client-ID %1").arg(BuildConfig.IMGUR_CLIENT_ID).toStdString().c_str()); - request.setRawHeader("Accept", "application/json"); - QStringList hashes; for (auto shot : m_screenshots) { hashes.append(shot->m_imgurDeleteHash); } - const QByteArray data = "deletehashes=" + hashes.join(',').toUtf8() + "&title=Minecraft%20Screenshots&privacy=hidden"; + return m_network->post(request, data); +}; - QNetworkReply* rep = APPLICATION->network()->post(request, data); - - m_reply.reset(rep); - connect(rep, &QNetworkReply::uploadProgress, this, &ImgurAlbumCreation::downloadProgress); - connect(rep, &QNetworkReply::finished, this, &ImgurAlbumCreation::downloadFinished); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 - connect(rep, &QNetworkReply::errorOccurred, this, &ImgurAlbumCreation::downloadError); -#else - connect(rep, QOverload::of(&QNetworkReply::error), this, &ImgurAlbumCreation::downloadError); -#endif - connect(rep, &QNetworkReply::sslErrors, this, &ImgurAlbumCreation::sslErrors); +void ImgurAlbumCreation::init() +{ + qDebug() << "Setting up imgur upload"; + auto api_headers = new Net::StaticHeaderProxy( + QList{ { "Content-Type", "application/x-www-form-urlencoded" }, + { "Authorization", QString("Client-ID %1").arg(BuildConfig.IMGUR_CLIENT_ID).toStdString().c_str() }, + { "Accept", "application/json" } }); + addHeaderProxy(api_headers); } -void ImgurAlbumCreation::downloadError([[maybe_unused]] QNetworkReply::NetworkError error) +auto ImgurAlbumCreation::Sink::init(QNetworkRequest& request) -> Task::State { - qDebug() << m_reply->errorString(); - m_state = State::Failed; + m_output.clear(); + return Task::State::Running; +}; + +auto ImgurAlbumCreation::Sink::write(QByteArray& data) -> Task::State +{ + m_output.append(data); + return Task::State::Running; } -void ImgurAlbumCreation::downloadFinished() +auto ImgurAlbumCreation::Sink::abort() -> Task::State { - if (m_state != State::Failed) { - QByteArray data = m_reply->readAll(); - m_reply.reset(); - QJsonParseError jsonError; - QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); - if (jsonError.error != QJsonParseError::NoError) { - qDebug() << jsonError.errorString(); - emitFailed(); - return; - } - auto object = doc.object(); - if (!object.value("success").toBool()) { - qDebug() << doc.toJson(); - emitFailed(); - return; - } - m_deleteHash = object.value("data").toObject().value("deletehash").toString(); - m_id = object.value("data").toObject().value("id").toString(); - m_state = State::Succeeded; - emit succeeded(); - return; - } else { - qDebug() << m_reply->readAll(); - m_reply.reset(); - emitFailed(); - return; + m_output.clear(); + return Task::State::Failed; +} + +auto ImgurAlbumCreation::Sink::finalize(QNetworkReply&) -> Task::State +{ + QJsonParseError jsonError; + QJsonDocument doc = QJsonDocument::fromJson(m_output, &jsonError); + if (jsonError.error != QJsonParseError::NoError) { + qDebug() << jsonError.errorString(); + return Task::State::Failed; } -} - -void ImgurAlbumCreation::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) -{ - setProgress(bytesReceived, bytesTotal); - emit progress(bytesReceived, bytesTotal); -} + auto object = doc.object(); + if (!object.value("success").toBool()) { + qDebug() << doc.toJson(); + return Task::State::Failed; + } + m_result->deleteHash = object.value("data").toObject().value("deletehash").toString(); + m_result->id = object.value("data").toObject().value("id").toString(); + return Task::State::Succeeded; +} \ No newline at end of file diff --git a/launcher/screenshots/ImgurAlbumCreation.h b/launcher/screenshots/ImgurAlbumCreation.h index bb71bec2b..7c292db73 100644 --- a/launcher/screenshots/ImgurAlbumCreation.h +++ b/launcher/screenshots/ImgurAlbumCreation.h @@ -36,34 +36,39 @@ #pragma once #include "Screenshot.h" -#include "net/NetAction.h" +#include "net/NetRequest.h" -typedef shared_qobject_ptr ImgurAlbumCreationPtr; -class ImgurAlbumCreation : public NetAction { +class ImgurAlbumCreation : public Net::NetRequest { public: - explicit ImgurAlbumCreation(QList screenshots); - static ImgurAlbumCreationPtr make(QList screenshots) - { - return ImgurAlbumCreationPtr(new ImgurAlbumCreation(screenshots)); - } + virtual ~ImgurAlbumCreation() = default; - QString deleteHash() const { return m_deleteHash; } - QString id() const { return m_id; } + struct Result { + QString deleteHash; + QString id; + }; - void init() override{}; + class Sink : public Net::Sink { + public: + Sink(std::shared_ptr res) : m_result(res){}; + virtual ~Sink() = default; - protected slots: - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; - void downloadError(QNetworkReply::NetworkError error) override; - void downloadFinished() override; - void downloadReadyRead() override {} + public: + auto init(QNetworkRequest& request) -> Task::State override; + auto write(QByteArray& data) -> Task::State override; + auto abort() -> Task::State override; + auto finalize(QNetworkReply& reply) -> Task::State override; + auto hasLocalData() -> bool override { return false; } - public slots: - void executeTask() override; + private: + std::shared_ptr m_result; + QByteArray m_output; + }; + + static NetRequest::Ptr make(std::shared_ptr output, QList screenshots); + QNetworkReply* getReply(QNetworkRequest& request) override; + + void init() override; private: QList m_screenshots; - - QString m_deleteHash; - QString m_id; }; diff --git a/launcher/screenshots/ImgurUpload.cpp b/launcher/screenshots/ImgurUpload.cpp index 29499a20d..7ed672eb7 100644 --- a/launcher/screenshots/ImgurUpload.cpp +++ b/launcher/screenshots/ImgurUpload.cpp @@ -35,8 +35,8 @@ */ #include "ImgurUpload.h" -#include "Application.h" #include "BuildConfig.h" +#include "net/StaticHeaderProxy.h" #include #include @@ -47,104 +47,84 @@ #include #include -ImgurUpload::ImgurUpload(ScreenShot::Ptr shot) : NetAction(), m_shot(shot) +void ImgurUpload::init() { - m_url = BuildConfig.IMGUR_BASE_URL + "upload.json"; - m_state = State::Inactive; + qDebug() << "Setting up imgur upload"; + auto api_headers = new Net::StaticHeaderProxy( + QList{ { "Authorization", QString("Client-ID %1").arg(BuildConfig.IMGUR_CLIENT_ID).toStdString().c_str() }, + { "Accept", "application/json" } }); + addHeaderProxy(api_headers); } -void ImgurUpload::executeTask() +QNetworkReply* ImgurUpload::getReply(QNetworkRequest& request) { - finished = false; - m_state = Task::State::Running; - QNetworkRequest request(m_url); - request.setHeader(QNetworkRequest::UserAgentHeader, APPLICATION->getUserAgentUncached().toUtf8()); - request.setRawHeader("Authorization", QString("Client-ID %1").arg(BuildConfig.IMGUR_CLIENT_ID).toStdString().c_str()); - request.setRawHeader("Accept", "application/json"); + auto file = new QFile(m_fileInfo.absoluteFilePath()); - QFile f(m_shot->m_file.absoluteFilePath()); - if (!f.open(QFile::ReadOnly)) { + if (!file->open(QFile::ReadOnly)) { emitFailed(); - return; + return nullptr; } QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + file->setParent(multipart); QHttpPart filePart; - filePart.setBody(f.readAll().toBase64()); + filePart.setBodyDevice(file); filePart.setHeader(QNetworkRequest::ContentTypeHeader, "image/png"); filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"image\""); multipart->append(filePart); QHttpPart typePart; typePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"type\""); - typePart.setBody("base64"); + typePart.setBody("file"); multipart->append(typePart); QHttpPart namePart; namePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"name\""); - namePart.setBody(m_shot->m_file.baseName().toUtf8()); + namePart.setBody(m_fileInfo.baseName().toUtf8()); multipart->append(namePart); - QNetworkReply* rep = m_network->post(request, multipart); + return m_network->post(request, multipart); +}; - m_reply.reset(rep); - connect(rep, &QNetworkReply::uploadProgress, this, &ImgurUpload::downloadProgress); - connect(rep, &QNetworkReply::finished, this, &ImgurUpload::downloadFinished); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 - connect(rep, &QNetworkReply::errorOccurred, this, &ImgurUpload::downloadError); -#else - connect(rep, QOverload::of(&QNetworkReply::error), this, &ImgurUpload::downloadError); -#endif - connect(rep, &QNetworkReply::sslErrors, this, &ImgurUpload::sslErrors); +auto ImgurUpload::Sink::init(QNetworkRequest& request) -> Task::State +{ + m_output.clear(); + return Task::State::Running; +}; + +auto ImgurUpload::Sink::write(QByteArray& data) -> Task::State +{ + m_output.append(data); + return Task::State::Running; } -void ImgurUpload::downloadError([[maybe_unused]] QNetworkReply::NetworkError error) +auto ImgurUpload::Sink::abort() -> Task::State { - qCritical() << "ImgurUpload failed with error" << m_reply->errorString() << "Server reply:\n" << m_reply->readAll(); - if (finished) { - qCritical() << "Double finished ImgurUpload!"; - return; - } - m_state = Task::State::Failed; - finished = true; - m_reply.reset(); - emitFailed(); + m_output.clear(); + return Task::State::Failed; } -void ImgurUpload::downloadFinished() +auto ImgurUpload::Sink::finalize(QNetworkReply&) -> Task::State { - if (finished) { - qCritical() << "Double finished ImgurUpload!"; - return; - } - QByteArray data = m_reply->readAll(); - m_reply.reset(); QJsonParseError jsonError; - QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); + QJsonDocument doc = QJsonDocument::fromJson(m_output, &jsonError); if (jsonError.error != QJsonParseError::NoError) { qDebug() << "imgur server did not reply with JSON" << jsonError.errorString(); - finished = true; - m_reply.reset(); - emitFailed(); - return; + return Task::State::Failed; } auto object = doc.object(); if (!object.value("success").toBool()) { qDebug() << "Screenshot upload not successful:" << doc.toJson(); - finished = true; - m_reply.reset(); - emitFailed(); - return; + return Task::State::Failed; } m_shot->m_imgurId = object.value("data").toObject().value("id").toString(); m_shot->m_url = object.value("data").toObject().value("link").toString(); m_shot->m_imgurDeleteHash = object.value("data").toObject().value("deletehash").toString(); - m_state = Task::State::Succeeded; - finished = true; - emit succeeded(); - return; + return Task::State::Succeeded; } -void ImgurUpload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) +Net::NetRequest::Ptr ImgurUpload::make(ScreenShot::Ptr m_shot) { - setProgress(bytesReceived, bytesTotal); - emit progress(bytesReceived, bytesTotal); + auto up = makeShared(m_shot->m_file); + up->m_url = std::move(BuildConfig.IMGUR_BASE_URL + "upload.json"); + up->m_sink.reset(new Sink(m_shot)); + return up; } diff --git a/launcher/screenshots/ImgurUpload.h b/launcher/screenshots/ImgurUpload.h index 542255b2d..5867ad306 100644 --- a/launcher/screenshots/ImgurUpload.h +++ b/launcher/screenshots/ImgurUpload.h @@ -35,27 +35,36 @@ #pragma once +#include #include "Screenshot.h" -#include "net/NetAction.h" +#include "net/NetRequest.h" -class ImgurUpload : public NetAction { +class ImgurUpload : public Net::NetRequest { public: - using Ptr = shared_qobject_ptr; + class Sink : public Net::Sink { + public: + Sink(ScreenShot::Ptr shot) : m_shot(shot){}; + virtual ~Sink() = default; - explicit ImgurUpload(ScreenShot::Ptr shot); - static Ptr make(ScreenShot::Ptr shot) { return Ptr(new ImgurUpload(shot)); } - void init() override{}; + public: + auto init(QNetworkRequest& request) -> Task::State override; + auto write(QByteArray& data) -> Task::State override; + auto abort() -> Task::State override; + auto finalize(QNetworkReply& reply) -> Task::State override; + auto hasLocalData() -> bool override { return false; } - protected slots: - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; - void downloadError(QNetworkReply::NetworkError error) override; - void downloadFinished() override; - void downloadReadyRead() override {} + private: + ScreenShot::Ptr m_shot; + QByteArray m_output; + }; + ImgurUpload(QFileInfo info) : m_fileInfo(info) {} + virtual ~ImgurUpload() = default; - public slots: - void executeTask() override; + static NetRequest::Ptr make(ScreenShot::Ptr m_shot); + + void init() override; private: - ScreenShot::Ptr m_shot; - bool finished = true; + virtual QNetworkReply* getReply(QNetworkRequest&) override; + const QFileInfo m_fileInfo; }; diff --git a/launcher/ui/dialogs/AboutDialog.cpp b/launcher/ui/dialogs/AboutDialog.cpp index 3c6f6ef16..f5eaff7a1 100644 --- a/launcher/ui/dialogs/AboutDialog.cpp +++ b/launcher/ui/dialogs/AboutDialog.cpp @@ -85,6 +85,7 @@ QString getCreditsHtml() stream << QString("

TayouVR %1

\n").arg(getGitHub("TayouVR")); stream << QString("

TheKodeToad %1

\n").arg(getGitHub("TheKodeToad")); stream << QString("

getchoo %1

\n").arg(getGitHub("getchoo")); + stream << QString("

Alexandru Tripon (Trial97) %1

\n").arg(getGitHub("Trial97")); stream << "
\n"; // TODO: possibly retrieve from git history at build time? diff --git a/launcher/ui/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp index 690dc917b..7530fdfba 100644 --- a/launcher/ui/instanceview/InstanceView.cpp +++ b/launcher/ui/instanceview/InstanceView.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -478,6 +479,38 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event) #endif option.widget = this; + if (model()->rowCount() == 0) { + painter.save(); + const QString line1 = tr("Welcome!"); + const QString line2 = tr("Click \"Add Instance\" to get started."); + auto rect = this->viewport()->rect(); + auto font = option.font; + font.setPointSize(37); + painter.setFont(font); + auto fm = painter.fontMetrics(); + + if (rect.height() <= (fm.height() * 5) || rect.width() <= fm.horizontalAdvance(line2)) { + auto s = rect.height() / (5. * fm.height()); + auto sx = rect.width() * 1. / fm.horizontalAdvance(line2); + if (s >= sx) + s = sx; + auto ps = font.pointSize() * s; + if (ps <= 0) + ps = 1; + font.setPointSize(ps); + painter.setFont(font); + fm = painter.fontMetrics(); + } + + // text + rect.setTop(rect.top() + fm.height() * 1.5); + painter.drawText(rect, Qt::AlignHCenter, line1); + rect.setTop(rect.top() + fm.height()); + painter.drawText(rect, Qt::AlignHCenter, line2); + painter.restore(); + return; + } + int wpWidth = viewport()->width(); option.rect.setWidth(wpWidth); for (int i = 0; i < m_groups.size(); ++i) { diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp index 29c835fc1..25f978cea 100644 --- a/launcher/ui/pages/instance/ScreenshotsPage.cpp +++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp @@ -383,20 +383,31 @@ void ScreenshotsPage::on_actionUpload_triggered() QList uploaded; auto job = NetJob::Ptr(new NetJob("Screenshot Upload", APPLICATION->network())); + + ProgressDialog dialog(this); + dialog.setSkipButton(true, tr("Abort")); + if (selection.size() < 2) { auto item = selection.at(0); auto info = m_model->fileInfo(item); auto screenshot = std::make_shared(info); job->addNetAction(ImgurUpload::make(screenshot)); - m_uploadActive = true; - ProgressDialog dialog(this); + connect(job.get(), &Task::failed, [this](QString reason) { + CustomMessageBox::selectable(this, tr("Failed to upload screenshots!"), reason, QMessageBox::Critical)->show(); + }); + connect(job.get(), &Task::aborted, [this] { + CustomMessageBox::selectable(this, tr("Screenshots upload aborted"), tr("The task has been aborted by the user."), + QMessageBox::Information) + ->show(); + }); - if (dialog.execWithTask(job.get()) != QDialog::Accepted) { - CustomMessageBox::selectable(this, tr("Failed to upload screenshots!"), tr("Unknown error"), QMessageBox::Warning)->exec(); - } else { + m_uploadActive = true; + + if (dialog.execWithTask(job.get()) == QDialog::Accepted) { auto link = screenshot->m_url; QClipboard* clipboard = QApplication::clipboard(); + qDebug() << "ImgurUpload link" << link; clipboard->setText(link); CustomMessageBox::selectable( this, tr("Upload finished"), @@ -417,22 +428,36 @@ void ScreenshotsPage::on_actionUpload_triggered() } SequentialTask task; auto albumTask = NetJob::Ptr(new NetJob("Imgur Album Creation", APPLICATION->network())); - auto imgurAlbum = ImgurAlbumCreation::make(uploaded); + auto imgurResult = std::make_shared(); + auto imgurAlbum = ImgurAlbumCreation::make(imgurResult, uploaded); albumTask->addNetAction(imgurAlbum); task.addTask(job); task.addTask(albumTask); - m_uploadActive = true; - ProgressDialog prog(this); - if (prog.execWithTask(&task) != QDialog::Accepted) { - CustomMessageBox::selectable(this, tr("Failed to upload screenshots!"), tr("Unknown error"), QMessageBox::Warning)->exec(); - } else { - auto link = QString("https://imgur.com/a/%1").arg(imgurAlbum->id()); - QClipboard* clipboard = QApplication::clipboard(); - clipboard->setText(link); - CustomMessageBox::selectable(this, tr("Upload finished"), - tr("The link to the uploaded album has been placed in your clipboard.").arg(link), + + connect(&task, &Task::failed, [this](QString reason) { + CustomMessageBox::selectable(this, tr("Failed to upload screenshots!"), reason, QMessageBox::Critical)->show(); + }); + connect(&task, &Task::aborted, [this] { + CustomMessageBox::selectable(this, tr("Screenshots upload aborted"), tr("The task has been aborted by the user."), QMessageBox::Information) - ->exec(); + ->show(); + }); + + m_uploadActive = true; + if (dialog.execWithTask(&task) == QDialog::Accepted) { + if (imgurResult->id.isEmpty()) { + CustomMessageBox::selectable(this, tr("Failed to upload screenshots!"), tr("Unknown error"), QMessageBox::Warning)->exec(); + } else { + auto link = QString("https://imgur.com/a/%1").arg(imgurResult->id); + qDebug() << "ImgurUpload link" << link; + QClipboard* clipboard = QApplication::clipboard(); + clipboard->setText(link); + CustomMessageBox::selectable( + this, tr("Upload finished"), + tr("The link to the uploaded album has been placed in your clipboard.").arg(link), + QMessageBox::Information) + ->exec(); + } } m_uploadActive = false; } diff --git a/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.cpp b/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.cpp index 43ff1c0fe..d46f16b4d 100644 --- a/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.cpp +++ b/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.cpp @@ -90,7 +90,7 @@ void ImportFTBPage::suggestCurrent() } dialog->setSuggestedPack(selected.name, new PackInstallTask(selected)); - QString editedLogoName = QString("ftb_%1_%2,jpg").arg(selected.name, selected.id); + QString editedLogoName = QString("ftb_%1_%2.jpg").arg(selected.name, QString::number(selected.id)); dialog->setSuggestedIconFromFile(FS::PathCombine(selected.path, "folder.jpg"), editedLogoName); } diff --git a/launcher/ui/themes/CustomTheme.cpp b/launcher/ui/themes/CustomTheme.cpp index 29ecf6254..4859983c6 100644 --- a/launcher/ui/themes/CustomTheme.cpp +++ b/launcher/ui/themes/CustomTheme.cpp @@ -165,11 +165,15 @@ CustomTheme::CustomTheme(ITheme* baseTheme, QFileInfo& fileInfo, bool isManifest QString path = FS::PathCombine("themes", m_id); QString pathResources = FS::PathCombine("themes", m_id, "resources"); - if (!FS::ensureFolderPathExists(path) || !FS::ensureFolderPathExists(pathResources)) { - themeWarningLog() << "couldn't create folder for theme!"; + if (!FS::ensureFolderPathExists(path)) { + themeWarningLog() << "Theme directory for" << m_id << "could not be created. This theme might be invalid"; return; } + if (!FS::ensureFolderPathExists(pathResources)) { + themeWarningLog() << "Resources directory for" << m_id << "could not be created"; + } + auto themeFilePath = FS::PathCombine(path, themeFile); bool jsonDataIncomplete = false; @@ -230,7 +234,11 @@ CustomTheme::CustomTheme(ITheme* baseTheme, QFileInfo& fileInfo, bool isManifest QStringList CustomTheme::searchPaths() { - return { FS::PathCombine("themes", m_id, "resources") }; + QString pathResources = FS::PathCombine("themes", m_id, "resources"); + if (QFileInfo::exists(pathResources)) + return { pathResources }; + + return {}; } QString CustomTheme::id()