From e5c42f68c2429a924b22dbcfb0df5a497690b805 Mon Sep 17 00:00:00 2001 From: flow Date: Thu, 13 Oct 2022 19:55:21 -0300 Subject: feat: add basic ManagedPackPage classes The idea is to have a base class that defines common behavior, and subclasses for each modpack provider, adding specific behavior. Signed-off-by: flow --- launcher/ui/pages/instance/ManagedPackPage.h | 98 ++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 launcher/ui/pages/instance/ManagedPackPage.h (limited to 'launcher/ui/pages/instance/ManagedPackPage.h') diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h new file mode 100644 index 00000000..be49383c --- /dev/null +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -0,0 +1,98 @@ +#pragma once + +#include "BaseInstance.h" + +#include "modplatform/modrinth/ModrinthAPI.h" +#include "modplatform/modrinth/ModrinthPackManifest.h" + +#include "ui/pages/BasePage.h" + +#include + +namespace Ui { +class ManagedPackPage; +} + +class ManagedPackPage : public QWidget, public BasePage { + Q_OBJECT + + public: + inline static ManagedPackPage* createPage(BaseInstance* inst, QWidget* parent = nullptr) + { + return ManagedPackPage::createPage(inst, inst->getManagedPackType(), parent); + } + + static ManagedPackPage* createPage(BaseInstance* inst, QString type, QWidget* parent = nullptr); + ~ManagedPackPage() override; + + [[nodiscard]] QString displayName() const override; + [[nodiscard]] QIcon icon() const override; + [[nodiscard]] QString helpPage() const override; + [[nodiscard]] QString id() const override { return "managed_pack"; } + [[nodiscard]] bool shouldDisplay() const override; + + void openedImpl() override; + + bool apply() override { return true; } + void retranslate() override; + + /** Gets the necessary information about the managed pack, such as + * available versions*/ + virtual void parseManagedPack() {}; + + /** URL of the managed pack. + * Not the version-specific one. + */ + [[nodiscard]] virtual QString url() const { return {}; }; + + public slots: + /** Gets the current version selection and update the changelog. + */ + virtual void suggestVersion() {}; + + protected: + ManagedPackPage(BaseInstance* inst, QWidget* parent = nullptr); + + protected: + Ui::ManagedPackPage* ui; + BaseInstance* m_inst; + + bool m_loaded = false; +}; + +/** Simple page for when we aren't a managed pack. */ +class GenericManagedPackPage final : public ManagedPackPage { + Q_OBJECT + + public: + GenericManagedPackPage(BaseInstance* inst, QWidget* parent = nullptr) : ManagedPackPage(inst, parent) {} + ~GenericManagedPackPage() override = default; +}; + +class ModrinthManagedPackPage final : public ManagedPackPage { + Q_OBJECT + + public: + ModrinthManagedPackPage(BaseInstance* inst, QWidget* parent = nullptr); + ~ModrinthManagedPackPage() override = default; + + void parseManagedPack() override; + [[nodiscard]] QString url() const override; + + public slots: + void suggestVersion() override; +}; + +class FlameManagedPackPage final : public ManagedPackPage { + Q_OBJECT + + public: + FlameManagedPackPage(BaseInstance* inst, QWidget* parent = nullptr); + ~FlameManagedPackPage() override = default; + + void parseManagedPack() override; + [[nodiscard]] QString url() const override; + + public slots: + void suggestVersion() override; +}; -- cgit From cba2608c1c196c341275b32becc4a7c713e92bbf Mon Sep 17 00:00:00 2001 From: flow Date: Thu, 13 Oct 2022 19:57:23 -0300 Subject: feat: add logic for the modrinth instance modpack page Signed-off-by: flow --- .../modplatform/modrinth/ModrinthPackManifest.cpp | 1 + .../modplatform/modrinth/ModrinthPackManifest.h | 1 + launcher/ui/pages/instance/ManagedPackPage.cpp | 50 ++++++++++++++++++++++ launcher/ui/pages/instance/ManagedPackPage.h | 4 ++ 4 files changed, 56 insertions(+) (limited to 'launcher/ui/pages/instance/ManagedPackPage.h') diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index 96f54067..4dca786f 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -128,6 +128,7 @@ auto loadIndexedVersion(QJsonObject &obj) -> ModpackVersion file.name = Json::requireString(obj, "name"); file.version = Json::requireString(obj, "version_number"); + file.changelog = Json::ensureString(obj, "changelog"); file.id = Json::requireString(obj, "id"); file.project_id = Json::requireString(obj, "project_id"); diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index 035dc62e..2973dfba 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -80,6 +80,7 @@ struct ModpackExtra { struct ModpackVersion { QString name; QString version; + QString changelog; QString id; QString project_id; diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 725f8ce5..ead33136 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -5,6 +5,10 @@ #include #include "Application.h" +#include "BuildConfig.h" +#include "Json.h" + +#include "modplatform/modrinth/ModrinthPackManifest.h" /** This is just to override the combo box popup behavior so that the combo box doesn't take the whole screen. * ... thanks Qt. @@ -96,6 +100,48 @@ ModrinthManagedPackPage::ModrinthManagedPackPage(BaseInstance* inst, QWidget* pa void ModrinthManagedPackPage::parseManagedPack() { + qDebug() << "Parsing Modrinth pack"; + + auto netJob = new NetJob(QString("Modrinth::PackVersions(%1)").arg(m_inst->getManagedPackName()), APPLICATION->network()); + auto response = new QByteArray(); + + QString id = m_inst->getManagedPackID(); + + netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { + QJsonParseError parse_error{}; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + try { + Modrinth::loadIndexedVersions(m_pack, doc); + } catch (const JSONValidationError& e) { + qDebug() << *response; + qWarning() << "Error while reading modrinth modpack version: " << e.cause(); + } + + for (auto version : m_pack.versions) { + if (!version.name.contains(version.version)) + ui->versionsComboBox->addItem(QString("%1 — %2").arg(version.name, version.version), QVariant(version.id)); + else + ui->versionsComboBox->addItem(version.name, QVariant(version.id)); + } + + suggestVersion(); + + m_loaded = true; + }); + QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + netJob->start(); } QString ModrinthManagedPackPage::url() const @@ -105,6 +151,10 @@ QString ModrinthManagedPackPage::url() const void ModrinthManagedPackPage::suggestVersion() { + auto index = ui->versionsComboBox->currentIndex(); + auto version = m_pack.versions.at(index); + + ui->changelogTextBrowser->setText(version.changelog); } FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, QWidget* parent) : ManagedPackPage(inst, parent) diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h index be49383c..1a756d33 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.h +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -81,6 +81,10 @@ class ModrinthManagedPackPage final : public ManagedPackPage { public slots: void suggestVersion() override; + + private: + Modrinth::Modpack m_pack; + ModrinthAPI m_api; }; class FlameManagedPackPage final : public ManagedPackPage { -- cgit From 58d2c15ffa4a966b40ba2f741c90e1d32fdbe106 Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 14 Oct 2022 14:36:48 -0300 Subject: feat: add functionality to MR modpack update in the page :D Signed-off-by: flow --- launcher/InstanceImportTask.cpp | 2 + launcher/ui/InstanceWindow.cpp | 6 +++ launcher/ui/pages/instance/ManagedPackPage.cpp | 73 ++++++++++++++++++++++---- launcher/ui/pages/instance/ManagedPackPage.h | 26 +++++++-- 4 files changed, 94 insertions(+), 13 deletions(-) (limited to 'launcher/ui/pages/instance/ManagedPackPage.h') diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 5f459649..f5ef250e 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -264,6 +264,7 @@ void InstanceImportTask::processFlame() inst_creation_task->setName(*this); inst_creation_task->setIcon(m_instIcon); inst_creation_task->setGroup(m_instGroup); + inst_creation_task->setConfirmUpdate(shouldConfirmUpdate()); connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] { setOverride(inst_creation_task->shouldOverride()); @@ -328,6 +329,7 @@ void InstanceImportTask::processModrinth() inst_creation_task->setName(*this); inst_creation_task->setIcon(m_instIcon); inst_creation_task->setGroup(m_instGroup); + inst_creation_task->setConfirmUpdate(shouldConfirmUpdate()); connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] { setOverride(inst_creation_task->shouldOverride()); diff --git a/launcher/ui/InstanceWindow.cpp b/launcher/ui/InstanceWindow.cpp index 09ce0d67..c62b370f 100644 --- a/launcher/ui/InstanceWindow.cpp +++ b/launcher/ui/InstanceWindow.cpp @@ -132,6 +132,12 @@ InstanceWindow::InstanceWindow(InstancePtr instance, QWidget *parent) { connect(m_instance.get(), &BaseInstance::statusChanged, this, &InstanceWindow::on_instanceStatusChanged); } + + // add ourself as the modpack page's instance window + { + static_cast(m_container->getPage("managed_pack"))->setInstanceWindow(this); + } + show(); } diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 7c51cf38..348dd857 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -6,10 +6,17 @@ #include "Application.h" #include "BuildConfig.h" +#include "InstanceImportTask.h" +#include "InstanceList.h" +#include "InstanceTask.h" #include "Json.h" #include "modplatform/modrinth/ModrinthPackManifest.h" +#include "ui/InstanceWindow.h" +#include "ui/dialogs/CustomMessageBox.h" +#include "ui/dialogs/ProgressDialog.h" + /** This is just to override the combo box popup behavior so that the combo box doesn't take the whole screen. * ... thanks Qt. */ @@ -33,14 +40,15 @@ class NoBigComboBoxStyle : public QProxyStyle { ManagedPackPage* ManagedPackPage::createPage(BaseInstance* inst, QString type, QWidget* parent) { if (type == "modrinth") - return new ModrinthManagedPackPage(inst, parent); + return new ModrinthManagedPackPage(inst, nullptr, parent); if (type == "flame") - return new FlameManagedPackPage(inst, parent); + return new FlameManagedPackPage(inst, nullptr, parent); - return new GenericManagedPackPage(inst, parent); + return new GenericManagedPackPage(inst, nullptr, parent); } -ManagedPackPage::ManagedPackPage(BaseInstance* inst, QWidget* parent) : QWidget(parent), ui(new Ui::ManagedPackPage), m_inst(inst) +ManagedPackPage::ManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent) + : QWidget(parent), m_instance_window(instance_window), ui(new Ui::ManagedPackPage), m_inst(inst) { Q_ASSERT(inst); @@ -92,10 +100,37 @@ bool ManagedPackPage::shouldDisplay() const return m_inst->isManagedPack(); } -ModrinthManagedPackPage::ModrinthManagedPackPage(BaseInstance* inst, QWidget* parent) : ManagedPackPage(inst, parent) +bool ManagedPackPage::runUpdateTask(InstanceTask* task) +{ + Q_ASSERT(task); + + unique_qobject_ptr wrapped_task(APPLICATION->instances()->wrapInstanceTask(task)); + + connect(task, &Task::failed, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); }); + connect(task, &Task::succeeded, [this, task]() { + QStringList warnings = task->warnings(); + if (warnings.count()) + CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); + }); + connect(task, &Task::aborted, [this] { + CustomMessageBox::selectable(this, tr("Task aborted"), tr("The task has been aborted by the user."), QMessageBox::Information) + ->show(); + }); + + ProgressDialog loadDialog(this); + loadDialog.setSkipButton(true, tr("Abort")); + loadDialog.execWithTask(task); + + return task->wasSuccessful(); +} + +ModrinthManagedPackPage::ModrinthManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent) + : ManagedPackPage(inst, instance_window, parent) { Q_ASSERT(inst->isManagedPack()); connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion())); + connect(ui->updateButton, &QPushButton::pressed, this, &ModrinthManagedPackPage::update); } void ModrinthManagedPackPage::parseManagedPack() @@ -166,16 +201,36 @@ void ModrinthManagedPackPage::suggestVersion() ui->changelogTextBrowser->setText(version.changelog); } -FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, QWidget* parent) : ManagedPackPage(inst, parent) +void ModrinthManagedPackPage::update() { - Q_ASSERT(inst->isManagedPack()); - connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion())); + auto index = ui->versionsComboBox->currentIndex(); + auto version = m_pack.versions.at(index); + + auto extracted = new InstanceImportTask(version.download_url, this); + + InstanceName inst_name(m_inst->getManagedPackName(), version.version); + inst_name.setName(m_inst->name().replace(m_inst->getManagedPackVersionName(), version.version)); + extracted->setName(inst_name); + + extracted->setGroup(APPLICATION->instances()->getInstanceGroup(m_inst->id())); + extracted->setIcon(m_inst->iconKey()); + extracted->setConfirmUpdate(false); + + auto did_succeed = runUpdateTask(extracted); + + if (m_instance_window && did_succeed) + m_instance_window->close(); } -void FlameManagedPackPage::parseManagedPack() +FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent) + : ManagedPackPage(inst, instance_window, parent) { + Q_ASSERT(inst->isManagedPack()); + connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion())); } +void FlameManagedPackPage::parseManagedPack() {} + QString FlameManagedPackPage::url() const { return {}; diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h index 1a756d33..dc6ae118 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.h +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -13,6 +13,9 @@ namespace Ui { class ManagedPackPage; } +class InstanceTask; +class InstanceWindow; + class ManagedPackPage : public QWidget, public BasePage { Q_OBJECT @@ -45,15 +48,28 @@ class ManagedPackPage : public QWidget, public BasePage { */ [[nodiscard]] virtual QString url() const { return {}; }; + void setInstanceWindow(InstanceWindow* window) { m_instance_window = window; } + public slots: /** Gets the current version selection and update the changelog. */ virtual void suggestVersion() {}; + virtual void update() {}; + protected: - ManagedPackPage(BaseInstance* inst, QWidget* parent = nullptr); + ManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr); + + /** Run the InstanceTask, with a progress dialog and all. + * Similar to MainWindow::instanceFromInstanceTask + * + * Returns whether the task was successful. + */ + bool runUpdateTask(InstanceTask*); protected: + InstanceWindow* m_instance_window = nullptr; + Ui::ManagedPackPage* ui; BaseInstance* m_inst; @@ -65,7 +81,7 @@ class GenericManagedPackPage final : public ManagedPackPage { Q_OBJECT public: - GenericManagedPackPage(BaseInstance* inst, QWidget* parent = nullptr) : ManagedPackPage(inst, parent) {} + GenericManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr) : ManagedPackPage(inst, instance_window, parent) {} ~GenericManagedPackPage() override = default; }; @@ -73,7 +89,7 @@ class ModrinthManagedPackPage final : public ManagedPackPage { Q_OBJECT public: - ModrinthManagedPackPage(BaseInstance* inst, QWidget* parent = nullptr); + ModrinthManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr); ~ModrinthManagedPackPage() override = default; void parseManagedPack() override; @@ -82,6 +98,8 @@ class ModrinthManagedPackPage final : public ManagedPackPage { public slots: void suggestVersion() override; + void update() override; + private: Modrinth::Modpack m_pack; ModrinthAPI m_api; @@ -91,7 +109,7 @@ class FlameManagedPackPage final : public ManagedPackPage { Q_OBJECT public: - FlameManagedPackPage(BaseInstance* inst, QWidget* parent = nullptr); + FlameManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr); ~FlameManagedPackPage() override = default; void parseManagedPack() override; -- cgit From 95392309150079d73f4ee83ea7bdba98ef9caa2f Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 11 Nov 2022 16:58:37 -0300 Subject: fix: do not display managed pack page for providers without an impl. yet Signed-off-by: flow --- launcher/ui/pages/instance/ManagedPackPage.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'launcher/ui/pages/instance/ManagedPackPage.h') diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h index dc6ae118..7ad13533 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.h +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -83,6 +83,9 @@ class GenericManagedPackPage final : public ManagedPackPage { public: GenericManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr) : ManagedPackPage(inst, instance_window, parent) {} ~GenericManagedPackPage() override = default; + + // TODO: We may want to show this page with some useful info at some point. + [[nodiscard]] bool shouldDisplay() const override { return false; }; }; class ModrinthManagedPackPage final : public ManagedPackPage { -- cgit From d4979974b4f65d6662557e0415085c90f1ad5a11 Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 11 Nov 2022 17:44:16 -0300 Subject: fix(ManagedPackPage): better UX for when network requests fail / are pending Signed-off-by: flow --- launcher/ui/pages/instance/ManagedPackPage.cpp | 34 ++++++++++++++++++++++++++ launcher/ui/pages/instance/ManagedPackPage.h | 14 +++++++++-- launcher/ui/pages/instance/ManagedPackPage.ui | 5 +++- 3 files changed, 50 insertions(+), 3 deletions(-) (limited to 'launcher/ui/pages/instance/ManagedPackPage.h') diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 6d051760..be0b2f86 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -127,6 +127,30 @@ bool ManagedPackPage::runUpdateTask(InstanceTask* task) return task->wasSuccessful(); } +void ManagedPackPage::suggestVersion() +{ + ui->updateButton->setText(tr("Update pack")); + ui->updateButton->setDisabled(false); +} + +void ManagedPackPage::setFailState() +{ + qDebug() << "Setting fail state!"; + + // We block signals here so that suggestVersion() doesn't get called, causing an assertion fail. + ui->versionsComboBox->blockSignals(true); + ui->versionsComboBox->clear(); + ui->versionsComboBox->addItem(tr("Failed to search for available versions."), {}); + ui->versionsComboBox->blockSignals(false); + + ui->changelogTextBrowser->setText(tr("Failed to request changelog data for this modpack.")); + + ui->updateButton->setText(tr("Cannot update!")); + ui->updateButton->setDisabled(true); + + // TODO: Perhaps start a timer here when m_loaded is false to try and reload. +} + ModrinthManagedPackPage::ModrinthManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent) : ManagedPackPage(inst, instance_window, parent) { @@ -153,6 +177,9 @@ void ModrinthManagedPackPage::parseManagedPack() qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset << " reason: " << parse_error.errorString(); qWarning() << *response; + + setFailState(); + return; } @@ -161,6 +188,9 @@ void ModrinthManagedPackPage::parseManagedPack() } catch (const JSONValidationError& e) { qDebug() << *response; qWarning() << "Error while reading modrinth modpack version: " << e.cause(); + + setFailState(); + return; } for (auto version : m_pack.versions) { @@ -183,6 +213,8 @@ void ModrinthManagedPackPage::parseManagedPack() m_loaded = true; }); + QObject::connect(netJob, &NetJob::failed, this, &ModrinthManagedPackPage::setFailState); + QObject::connect(netJob, &NetJob::aborted, this, &ModrinthManagedPackPage::setFailState); QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); delete response; @@ -202,6 +234,8 @@ void ModrinthManagedPackPage::suggestVersion() HoeDown md_parser; ui->changelogTextBrowser->setHtml(md_parser.process(version.changelog.toUtf8())); + + ManagedPackPage::suggestVersion(); } void ModrinthManagedPackPage::update() diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h index 7ad13533..a81d24f0 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.h +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -51,12 +51,22 @@ class ManagedPackPage : public QWidget, public BasePage { void setInstanceWindow(InstanceWindow* window) { m_instance_window = window; } public slots: - /** Gets the current version selection and update the changelog. + /** Gets the current version selection and update the UI, including the update button and the changelog. */ - virtual void suggestVersion() {}; + virtual void suggestVersion(); virtual void update() {}; + protected slots: + /** Does the necessary UI changes for when something failed. + * + * This includes: + * - Setting an appropriate text on the version selector to indicate a fail; + * - Setting an appropriate text on the changelog text browser to indicate a fail; + * - Disable the update button. + */ + void setFailState(); + protected: ManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr); diff --git a/launcher/ui/pages/instance/ManagedPackPage.ui b/launcher/ui/pages/instance/ManagedPackPage.ui index 3f019606..14009b13 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.ui +++ b/launcher/ui/pages/instance/ManagedPackPage.ui @@ -133,6 +133,9 @@ + + false + 0 @@ -140,7 +143,7 @@ - Update pack + Fetching versions... -- cgit From 527c1113f1c92b8afe59eb0df0dbac8a1d508d98 Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 12 Nov 2022 12:19:05 -0300 Subject: feat(ManagedPackPage): add Flame UI Signed-off-by: flow --- buildconfig/BuildConfig.h | 2 + launcher/ui/pages/instance/ManagedPackPage.cpp | 66 +++++++++++++++++++++++++- launcher/ui/pages/instance/ManagedPackPage.h | 7 +++ 3 files changed, 74 insertions(+), 1 deletion(-) (limited to 'launcher/ui/pages/instance/ManagedPackPage.h') diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h index 4a309073..a05d7a9e 100644 --- a/buildconfig/BuildConfig.h +++ b/buildconfig/BuildConfig.h @@ -161,6 +161,8 @@ class Config { QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2"; QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2"; + QString FLAME_BASE_URL = "https://api.curseforge.com/v1"; + QString versionString() const; /** * \brief Converts the Version to a string. diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 2f1e4ff0..45be7c71 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -269,7 +269,65 @@ FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, InstanceWindow* i connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion())); } -void FlameManagedPackPage::parseManagedPack() {} +void FlameManagedPackPage::parseManagedPack() { + qDebug() << "Parsing Flame pack"; + + auto netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(m_inst->getManagedPackName()), APPLICATION->network()); + auto response = new QByteArray(); + + QString id = m_inst->getManagedPackID(); + + netJob->addNetAction(Net::Download::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { + QJsonParseError parse_error{}; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Flame at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + + setFailState(); + + return; + } + + try { + auto obj = doc.object(); + auto data = Json::ensureArray(obj, "data"); + Flame::loadIndexedPackVersions(m_pack, data); + } catch (const JSONValidationError& e) { + qDebug() << *response; + qWarning() << "Error while reading modrinth modpack version: " << e.cause(); + + setFailState(); + return; + } + + for (auto version : m_pack.versions) { + QString name; + + name = version.version; + + if (version.fileId == m_inst->getManagedPackVersionID().toInt()) + name.append(tr(" (Current)")); + + ui->versionsComboBox->addItem(name, QVariant(version.fileId)); + } + + suggestVersion(); + + m_loaded = true; + }); + QObject::connect(netJob, &NetJob::failed, this, &FlameManagedPackPage::setFailState); + QObject::connect(netJob, &NetJob::aborted, this, &FlameManagedPackPage::setFailState); + QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + + netJob->start(); +} QString FlameManagedPackPage::url() const { @@ -278,6 +336,12 @@ QString FlameManagedPackPage::url() const void FlameManagedPackPage::suggestVersion() { + auto index = ui->versionsComboBox->currentIndex(); + auto version = m_pack.versions.at(index); + + ui->changelogTextBrowser->setHtml(m_api.getModFileChangelog(m_inst->getManagedPackID().toInt(), version.fileId)); + + ManagedPackPage::suggestVersion(); } #include "ManagedPackPage.moc" diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h index a81d24f0..6d487820 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.h +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -5,6 +5,9 @@ #include "modplatform/modrinth/ModrinthAPI.h" #include "modplatform/modrinth/ModrinthPackManifest.h" +#include "modplatform/flame/FlameAPI.h" +#include "modplatform/flame/FlamePackIndex.h" + #include "ui/pages/BasePage.h" #include @@ -130,4 +133,8 @@ class FlameManagedPackPage final : public ManagedPackPage { public slots: void suggestVersion() override; + + private: + Flame::IndexedPack m_pack; + FlameAPI m_api; }; -- cgit From 57b905be2493f68ab49482a45ab63249bb6468fa Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 12 Nov 2022 13:03:50 -0300 Subject: feat(ManagedPackPage): implement Flame modpack updating button Signed-off-by: flow --- launcher/ui/pages/instance/ManagedPackPage.cpp | 26 ++++++++++++++++++++++++++ launcher/ui/pages/instance/ManagedPackPage.h | 2 ++ 2 files changed, 28 insertions(+) (limited to 'launcher/ui/pages/instance/ManagedPackPage.h') diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index f00a2bdd..5f108cf1 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -271,6 +271,7 @@ FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, InstanceWindow* i { Q_ASSERT(inst->isManagedPack()); connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion())); + connect(ui->updateButton, &QPushButton::pressed, this, &FlameManagedPackPage::update); } void FlameManagedPackPage::parseManagedPack() { @@ -367,4 +368,29 @@ void FlameManagedPackPage::suggestVersion() ManagedPackPage::suggestVersion(); } +void FlameManagedPackPage::update() +{ + auto index = ui->versionsComboBox->currentIndex(); + auto version = m_pack.versions.at(index); + + QMap extra_info; + extra_info.insert("pack_id", m_inst->getManagedPackID()); + extra_info.insert("pack_version_id", QString::number(version.fileId)); + + auto extracted = new InstanceImportTask(version.downloadUrl, this, extra_info); + + InstanceName inst_name(m_inst->getManagedPackName(), version.version); + inst_name.setName(m_inst->name().replace(m_inst->getManagedPackVersionName(), version.version)); + extracted->setName(inst_name); + + extracted->setGroup(APPLICATION->instances()->getInstanceGroup(m_inst->id())); + extracted->setIcon(m_inst->iconKey()); + extracted->setConfirmUpdate(false); + + auto did_succeed = runUpdateTask(extracted); + + if (m_instance_window && did_succeed) + m_instance_window->close(); +} + #include "ManagedPackPage.moc" diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h index 6d487820..9ad5e34a 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.h +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -134,6 +134,8 @@ class FlameManagedPackPage final : public ManagedPackPage { public slots: void suggestVersion() override; + void update() override; + private: Flame::IndexedPack m_pack; FlameAPI m_api; -- cgit From c5c426ecbc5811fb2a5c0ea8d22e65c43d7b9ff2 Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 12 Nov 2022 13:27:09 -0300 Subject: chore(ManagedPackPage): format and add headers Signed-off-by: flow --- launcher/ui/pages/instance/ManagedPackPage.cpp | 37 +++++++++++++++++--------- launcher/ui/pages/instance/ManagedPackPage.h | 12 ++++++--- 2 files changed, 33 insertions(+), 16 deletions(-) (limited to 'launcher/ui/pages/instance/ManagedPackPage.h') diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 0b141a1f..cf782606 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2022 flow +// +// SPDX-License-Identifier: GPL-3.0-only + #include "ManagedPackPage.h" #include "ui_ManagedPackPage.h" @@ -79,6 +83,8 @@ QString ManagedPackPage::displayName() const auto type = m_inst->getManagedPackType(); if (type.isEmpty()) return {}; + if (type == "flame") + type = "CurseForge"; return type.replace(0, 1, type[0].toUpper()); } @@ -159,6 +165,8 @@ ModrinthManagedPackPage::ModrinthManagedPackPage(BaseInstance* inst, InstanceWin connect(ui->updateButton, &QPushButton::pressed, this, &ModrinthManagedPackPage::update); } +// MODRINTH + void ModrinthManagedPackPage::parseManagedPack() { qDebug() << "Parsing Modrinth pack"; @@ -271,6 +279,8 @@ void ModrinthManagedPackPage::update() m_instance_window->close(); } +// FLAME + FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent) : ManagedPackPage(inst, instance_window, parent) { @@ -279,23 +289,23 @@ FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, InstanceWindow* i connect(ui->updateButton, &QPushButton::pressed, this, &FlameManagedPackPage::update); } -void FlameManagedPackPage::parseManagedPack() { +void FlameManagedPackPage::parseManagedPack() +{ qDebug() << "Parsing Flame pack"; // We need to tell the user to redownload the pack, since we didn't save the required info previously if (m_inst->getManagedPackID().isEmpty()) { setFailState(); - QString message = tr( - "

Hey there!

" - "

" - "It seems like your Pack ID is null. This is because of a bug in older versions of the launcher.
" - "Unfortunately, we can't do the proper API requests without this information.
" - "
" - "So, in order for this feature to work, you will need to re-download the modpack from the built-in downloader.
" - "
" - "Don't worry though, it will ask you to update this instance instead, so you'll not lose this instance!" - "

" - ); + QString message = + tr("

Hey there!

" + "

" + "It seems like your Pack ID is null. This is because of a bug in older versions of the launcher.
" + "Unfortunately, we can't do the proper API requests without this information.
" + "
" + "So, in order for this feature to work, you will need to re-download the modpack from the built-in downloader.
" + "
" + "Don't worry though, it will ask you to update this instance instead, so you'll not lose this instance!" + "

"); ui->changelogTextBrowser->setHtml(message); return; @@ -327,7 +337,7 @@ void FlameManagedPackPage::parseManagedPack() { Flame::loadIndexedPackVersions(m_pack, data); } catch (const JSONValidationError& e) { qDebug() << *response; - qWarning() << "Error while reading modrinth modpack version: " << e.cause(); + qWarning() << "Error while reading flame modpack version: " << e.cause(); setFailState(); return; @@ -365,6 +375,7 @@ void FlameManagedPackPage::parseManagedPack() { QString FlameManagedPackPage::url() const { + // FIXME: We should display the websiteUrl field, but this requires doing the API request first :( return {}; } diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h index 9ad5e34a..282a8111 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.h +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2022 flow +// +// SPDX-License-Identifier: GPL-3.0-only + #pragma once #include "BaseInstance.h" @@ -44,7 +48,7 @@ class ManagedPackPage : public QWidget, public BasePage { /** Gets the necessary information about the managed pack, such as * available versions*/ - virtual void parseManagedPack() {}; + virtual void parseManagedPack(){}; /** URL of the managed pack. * Not the version-specific one. @@ -58,7 +62,7 @@ class ManagedPackPage : public QWidget, public BasePage { */ virtual void suggestVersion(); - virtual void update() {}; + virtual void update(){}; protected slots: /** Does the necessary UI changes for when something failed. @@ -94,7 +98,9 @@ class GenericManagedPackPage final : public ManagedPackPage { Q_OBJECT public: - GenericManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr) : ManagedPackPage(inst, instance_window, parent) {} + GenericManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr) + : ManagedPackPage(inst, instance_window, parent) + {} ~GenericManagedPackPage() override = default; // TODO: We may want to show this page with some useful info at some point. -- cgit From 089018015a441a35dc1780c9b61b29740bbf8a28 Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 18 Nov 2022 15:48:16 -0300 Subject: refactor(ManagedPackPage): use smart pointers instead of raw ones Signed-off-by: flow --- launcher/ui/pages/instance/ManagedPackPage.cpp | 42 ++++++++++++-------------- launcher/ui/pages/instance/ManagedPackPage.h | 4 +++ 2 files changed, 24 insertions(+), 22 deletions(-) (limited to 'launcher/ui/pages/instance/ManagedPackPage.h') diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 10182b8b..b3816ce9 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -179,14 +179,17 @@ void ModrinthManagedPackPage::parseManagedPack() { qDebug() << "Parsing Modrinth pack"; - auto netJob = new NetJob(QString("Modrinth::PackVersions(%1)").arg(m_inst->getManagedPackName()), APPLICATION->network()); - auto response = new QByteArray(); + if (m_fetch_job && m_fetch_job->isRunning()) + m_fetch_job->abort(); + + m_fetch_job.reset(new NetJob(QString("Modrinth::PackVersions(%1)").arg(m_inst->getManagedPackName()), APPLICATION->network())); + auto response = std::make_shared(); QString id = m_inst->getManagedPackID(); - netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response)); + m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response.get())); - QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { + QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] { QJsonParseError parse_error{}; QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); if (parse_error.error != QJsonParseError::NoError) { @@ -234,16 +237,12 @@ void ModrinthManagedPackPage::parseManagedPack() m_loaded = true; }); - QObject::connect(netJob, &NetJob::failed, this, &ModrinthManagedPackPage::setFailState); - QObject::connect(netJob, &NetJob::aborted, this, &ModrinthManagedPackPage::setFailState); - QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { - netJob->deleteLater(); - delete response; - }); + QObject::connect(m_fetch_job.get(), &NetJob::failed, this, &ModrinthManagedPackPage::setFailState); + QObject::connect(m_fetch_job.get(), &NetJob::aborted, this, &ModrinthManagedPackPage::setFailState); ui->changelogTextBrowser->setText(tr("Fetching changelogs...")); - netJob->start(); + m_fetch_job->start(); } QString ModrinthManagedPackPage::url() const @@ -319,14 +318,17 @@ void FlameManagedPackPage::parseManagedPack() return; } - auto netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(m_inst->getManagedPackName()), APPLICATION->network()); - auto response = new QByteArray(); + if (m_fetch_job && m_fetch_job->isRunning()) + m_fetch_job->abort(); + + m_fetch_job.reset(new NetJob(QString("Flame::PackVersions(%1)").arg(m_inst->getManagedPackName()), APPLICATION->network())); + auto response = std::make_shared(); QString id = m_inst->getManagedPackID(); - netJob->addNetAction(Net::Download::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response)); + m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response.get())); - QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { + QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] { QJsonParseError parse_error{}; QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); if (parse_error.error != QJsonParseError::NoError) { @@ -371,14 +373,10 @@ void FlameManagedPackPage::parseManagedPack() m_loaded = true; }); - QObject::connect(netJob, &NetJob::failed, this, &FlameManagedPackPage::setFailState); - QObject::connect(netJob, &NetJob::aborted, this, &FlameManagedPackPage::setFailState); - QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { - netJob->deleteLater(); - delete response; - }); + QObject::connect(m_fetch_job.get(), &NetJob::failed, this, &FlameManagedPackPage::setFailState); + QObject::connect(m_fetch_job.get(), &NetJob::aborted, this, &FlameManagedPackPage::setFailState); - netJob->start(); + m_fetch_job->start(); } QString FlameManagedPackPage::url() const diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h index 282a8111..d29a5e88 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.h +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -123,6 +123,8 @@ class ModrinthManagedPackPage final : public ManagedPackPage { void update() override; private: + NetJob::Ptr m_fetch_job = nullptr; + Modrinth::Modpack m_pack; ModrinthAPI m_api; }; @@ -143,6 +145,8 @@ class FlameManagedPackPage final : public ManagedPackPage { void update() override; private: + NetJob::Ptr m_fetch_job = nullptr; + Flame::IndexedPack m_pack; FlameAPI m_api; }; -- cgit