aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
authorflow <flowlnlnln@gmail.com>2022-09-07 08:27:11 -0300
committerGitHub <noreply@github.com>2022-09-07 08:27:11 -0300
commit1b0ca476824ad3d704de70720184d2f1e194d2f5 (patch)
tree6d5574a10b1fd34af511f9126c51e62b5a994516 /launcher
parent8e3f5c33057175b83ef276914d81ed4d5616d6e5 (diff)
parent4a8abc948ef15664dbde196ba77daccdf3d623ad (diff)
downloadPrismLauncher-1b0ca476824ad3d704de70720184d2f1e194d2f5.tar.gz
PrismLauncher-1b0ca476824ad3d704de70720184d2f1e194d2f5.tar.bz2
PrismLauncher-1b0ca476824ad3d704de70720184d2f1e194d2f5.zip
Merge pull request #939 from flowln/mod_downloader_improve
Some more UI / UX improvements to the mod downloader!
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp2
-rw-r--r--launcher/CMakeLists.txt2
-rw-r--r--launcher/modplatform/ModAPI.h4
-rw-r--r--launcher/modplatform/ModIndex.h2
-rw-r--r--launcher/modplatform/flame/FlameAPI.cpp37
-rw-r--r--launcher/modplatform/flame/FlameAPI.h1
-rw-r--r--launcher/modplatform/flame/FlameModIndex.cpp19
-rw-r--r--launcher/modplatform/flame/FlameModIndex.h3
-rw-r--r--launcher/modplatform/helpers/NetworkModAPI.cpp20
-rw-r--r--launcher/modplatform/helpers/NetworkModAPI.h4
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackIndex.cpp2
-rw-r--r--launcher/ui/dialogs/ModDownloadDialog.cpp71
-rw-r--r--launcher/ui/dialogs/ModDownloadDialog.h25
-rw-r--r--launcher/ui/dialogs/ReviewMessageBox.cpp5
-rw-r--r--launcher/ui/pages/modplatform/ModModel.cpp85
-rw-r--r--launcher/ui/pages/modplatform/ModModel.h13
-rw-r--r--launcher/ui/pages/modplatform/ModPage.cpp70
-rw-r--r--launcher/ui/pages/modplatform/ModPage.h11
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModModel.cpp6
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModModel.h1
-rw-r--r--launcher/ui/widgets/Common.cpp22
-rw-r--r--launcher/ui/widgets/Common.h9
-rw-r--r--launcher/ui/widgets/PageContainer.cpp9
-rw-r--r--launcher/ui/widgets/PageContainer.h4
-rw-r--r--launcher/ui/widgets/ProgressWidget.cpp94
-rw-r--r--launcher/ui/widgets/ProgressWidget.h48
-rw-r--r--launcher/ui/widgets/ProjectItem.cpp78
-rw-r--r--launcher/ui/widgets/ProjectItem.h25
28 files changed, 530 insertions, 142 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index 0c9f0487..aa937964 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -685,6 +685,8 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("UpdateDialogGeometry", "");
+ m_settings->registerSetting("ModDownloadGeometry", "");
+
// HACK: This code feels so stupid is there a less stupid way of doing this?
{
m_settings->registerSetting("PastebinURL", "");
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 490202cf..dfd56d26 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -896,6 +896,8 @@ SET(LAUNCHER_SOURCES
ui/widgets/PageContainer.cpp
ui/widgets/PageContainer.h
ui/widgets/PageContainer_p.h
+ ui/widgets/ProjectItem.h
+ ui/widgets/ProjectItem.cpp
ui/widgets/VersionListView.cpp
ui/widgets/VersionListView.h
ui/widgets/VersionSelectWidget.cpp
diff --git a/launcher/modplatform/ModAPI.h b/launcher/modplatform/ModAPI.h
index 4114d83c..c7408835 100644
--- a/launcher/modplatform/ModAPI.h
+++ b/launcher/modplatform/ModAPI.h
@@ -73,7 +73,7 @@ class ModAPI {
};
virtual void searchMods(CallerType* caller, SearchArgs&& args) const = 0;
- virtual void getModInfo(CallerType* caller, ModPlatform::IndexedPack& pack) = 0;
+ virtual void getModInfo(ModPlatform::IndexedPack& pack, std::function<void(QJsonDocument&, ModPlatform::IndexedPack&)> callback) = 0;
virtual auto getProject(QString addonId, QByteArray* response) const -> NetJob* = 0;
virtual auto getProjects(QStringList addonIds, QByteArray* response) const -> NetJob* = 0;
@@ -85,7 +85,7 @@ class ModAPI {
ModLoaderTypes loaders;
};
- virtual void getVersions(CallerType* caller, VersionSearchArgs&& args) const = 0;
+ virtual void getVersions(VersionSearchArgs&& args, std::function<void(QJsonDocument&, QString)> callback) const = 0;
static auto getModLoaderString(ModLoaderType type) -> const QString {
switch (type) {
diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h
index 89fe1c5c..518fed7c 100644
--- a/launcher/modplatform/ModIndex.h
+++ b/launcher/modplatform/ModIndex.h
@@ -75,6 +75,8 @@ struct ExtraPackData {
QString sourceUrl;
QString wikiUrl;
QString discordUrl;
+
+ QString body;
};
struct IndexedPack {
diff --git a/launcher/modplatform/flame/FlameAPI.cpp b/launcher/modplatform/flame/FlameAPI.cpp
index 0ff04f72..9c74918b 100644
--- a/launcher/modplatform/flame/FlameAPI.cpp
+++ b/launcher/modplatform/flame/FlameAPI.cpp
@@ -67,6 +67,43 @@ auto FlameAPI::getModFileChangelog(int modId, int fileId) -> QString
return changelog;
}
+auto FlameAPI::getModDescription(int modId) -> QString
+{
+ QEventLoop lock;
+ QString description;
+
+ auto* netJob = new NetJob(QString("Flame::ModDescription"), APPLICATION->network());
+ auto* response = new QByteArray();
+ netJob->addNetAction(Net::Download::makeByteArray(
+ QString("https://api.curseforge.com/v1/mods/%1/description")
+ .arg(QString::number(modId)), response));
+
+ QObject::connect(netJob, &NetJob::succeeded, [netJob, response, &description] {
+ QJsonParseError parse_error{};
+ QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
+ if (parse_error.error != QJsonParseError::NoError) {
+ qWarning() << "Error while parsing JSON response from Flame::ModDescription at " << parse_error.offset
+ << " reason: " << parse_error.errorString();
+ qWarning() << *response;
+
+ netJob->failed(parse_error.errorString());
+ return;
+ }
+
+ description = Json::ensureString(doc.object(), "data");
+ });
+
+ QObject::connect(netJob, &NetJob::finished, [response, &lock] {
+ delete response;
+ lock.quit();
+ });
+
+ netJob->start();
+ lock.exec();
+
+ return description;
+}
+
auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion
{
QEventLoop loop;
diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h
index 336df387..4eac0664 100644
--- a/launcher/modplatform/flame/FlameAPI.h
+++ b/launcher/modplatform/flame/FlameAPI.h
@@ -7,6 +7,7 @@ class FlameAPI : public NetworkModAPI {
public:
auto matchFingerprints(const QList<uint>& fingerprints, QByteArray* response) -> NetJob::Ptr;
auto getModFileChangelog(int modId, int fileId) -> QString;
+ auto getModDescription(int modId) -> QString;
auto getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion;
diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp
index 746018e2..32aa4bdb 100644
--- a/launcher/modplatform/flame/FlameModIndex.cpp
+++ b/launcher/modplatform/flame/FlameModIndex.cpp
@@ -4,10 +4,9 @@
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "modplatform/flame/FlameAPI.h"
-#include "net/NetJob.h"
-static ModPlatform::ProviderCapabilities ProviderCaps;
static FlameAPI api;
+static ModPlatform::ProviderCapabilities ProviderCaps;
void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
{
@@ -31,10 +30,11 @@ void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
pack.authors.append(packAuthor);
}
- loadExtraPackData(pack, obj);
+ pack.extraDataLoaded = false;
+ loadURLs(pack, obj);
}
-void FlameMod::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& obj)
+void FlameMod::loadURLs(ModPlatform::IndexedPack& pack, QJsonObject& obj)
{
auto links_obj = Json::ensureObject(obj, "links");
@@ -50,7 +50,16 @@ void FlameMod::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& ob
if(pack.extraData.wikiUrl.endsWith('/'))
pack.extraData.wikiUrl.chop(1);
- pack.extraDataLoaded = true;
+ if (!pack.extraData.body.isEmpty())
+ pack.extraDataLoaded = true;
+}
+
+void FlameMod::loadBody(ModPlatform::IndexedPack& pack, QJsonObject& obj)
+{
+ pack.extraData.body = api.getModDescription(pack.addonId.toInt());
+
+ if (!pack.extraData.issuesUrl.isEmpty() || !pack.extraData.sourceUrl.isEmpty() || !pack.extraData.wikiUrl.isEmpty())
+ pack.extraDataLoaded = true;
}
static QString enumToString(int hash_algorithm)
diff --git a/launcher/modplatform/flame/FlameModIndex.h b/launcher/modplatform/flame/FlameModIndex.h
index a839dd83..db63cdbb 100644
--- a/launcher/modplatform/flame/FlameModIndex.h
+++ b/launcher/modplatform/flame/FlameModIndex.h
@@ -12,7 +12,8 @@
namespace FlameMod {
void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj);
-void loadExtraPackData(ModPlatform::IndexedPack& m, QJsonObject& obj);
+void loadURLs(ModPlatform::IndexedPack& m, QJsonObject& obj);
+void loadBody(ModPlatform::IndexedPack& m, QJsonObject& obj);
void loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
QJsonArray& arr,
const shared_qobject_ptr<QNetworkAccessManager>& network,
diff --git a/launcher/modplatform/helpers/NetworkModAPI.cpp b/launcher/modplatform/helpers/NetworkModAPI.cpp
index 90edfe31..866e7540 100644
--- a/launcher/modplatform/helpers/NetworkModAPI.cpp
+++ b/launcher/modplatform/helpers/NetworkModAPI.cpp
@@ -31,48 +31,48 @@ void NetworkModAPI::searchMods(CallerType* caller, SearchArgs&& args) const
netJob->start();
}
-void NetworkModAPI::getModInfo(CallerType* caller, ModPlatform::IndexedPack& pack)
+void NetworkModAPI::getModInfo(ModPlatform::IndexedPack& pack, std::function<void(QJsonDocument&, ModPlatform::IndexedPack&)> callback)
{
auto response = new QByteArray();
auto job = getProject(pack.addonId.toString(), response);
- QObject::connect(job, &NetJob::succeeded, caller, [caller, &pack, response] {
+ QObject::connect(job, &NetJob::succeeded, [callback, &pack, response] {
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
- qWarning() << "Error while parsing JSON response from " << caller->debugName() << " at " << parse_error.offset
+ qWarning() << "Error while parsing JSON response for mod info at " << parse_error.offset
<< " reason: " << parse_error.errorString();
qWarning() << *response;
return;
}
- caller->infoRequestFinished(doc, pack);
+ callback(doc, pack);
});
job->start();
}
-void NetworkModAPI::getVersions(CallerType* caller, VersionSearchArgs&& args) const
+void NetworkModAPI::getVersions(VersionSearchArgs&& args, std::function<void(QJsonDocument&, QString)> callback) const
{
- auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(caller->debugName()).arg(args.addonId), APPLICATION->network());
+ auto netJob = new NetJob(QString("ModVersions(%2)").arg(args.addonId), APPLICATION->network());
auto response = new QByteArray();
netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(args), response));
- QObject::connect(netJob, &NetJob::succeeded, caller, [response, caller, args] {
+ QObject::connect(netJob, &NetJob::succeeded, [response, callback, args] {
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
- qWarning() << "Error while parsing JSON response from " << caller->debugName() << " at " << parse_error.offset
+ qWarning() << "Error while parsing JSON response for getting versions at " << parse_error.offset
<< " reason: " << parse_error.errorString();
qWarning() << *response;
return;
}
- caller->versionRequestSucceeded(doc, args.addonId);
+ callback(doc, args.addonId);
});
- QObject::connect(netJob, &NetJob::finished, caller, [response, netJob] {
+ QObject::connect(netJob, &NetJob::finished, [response, netJob] {
netJob->deleteLater();
delete response;
});
diff --git a/launcher/modplatform/helpers/NetworkModAPI.h b/launcher/modplatform/helpers/NetworkModAPI.h
index 989bcec4..b8af22c7 100644
--- a/launcher/modplatform/helpers/NetworkModAPI.h
+++ b/launcher/modplatform/helpers/NetworkModAPI.h
@@ -5,8 +5,8 @@
class NetworkModAPI : public ModAPI {
public:
void searchMods(CallerType* caller, SearchArgs&& args) const override;
- void getModInfo(CallerType* caller, ModPlatform::IndexedPack& pack) override;
- void getVersions(CallerType* caller, VersionSearchArgs&& args) const override;
+ void getModInfo(ModPlatform::IndexedPack& pack, std::function<void(QJsonDocument&, ModPlatform::IndexedPack&)> callback) override;
+ void getVersions(VersionSearchArgs&& args, std::function<void(QJsonDocument&, QString)> callback) const override;
auto getProject(QString addonId, QByteArray* response) const -> NetJob* override;
diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
index e50dd96d..3e53becb 100644
--- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
+++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
@@ -87,6 +87,8 @@ void Modrinth::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& ob
pack.extraData.donate.append(donate);
}
+ pack.extraData.body = Json::ensureString(obj, "body");
+
pack.extraDataLoaded = true;
}
diff --git a/launcher/ui/dialogs/ModDownloadDialog.cpp b/launcher/ui/dialogs/ModDownloadDialog.cpp
index bc5e5206..7382d1cf 100644
--- a/launcher/ui/dialogs/ModDownloadDialog.cpp
+++ b/launcher/ui/dialogs/ModDownloadDialog.cpp
@@ -19,36 +19,33 @@
#include "ModDownloadDialog.h"
#include <BaseVersion.h>
-#include <icons/IconList.h>
#include <InstanceList.h>
+#include <icons/IconList.h>
#include "Application.h"
-#include "ProgressDialog.h"
#include "ReviewMessageBox.h"
+#include <QDialogButtonBox>
#include <QLayout>
#include <QPushButton>
#include <QValidator>
-#include <QDialogButtonBox>
-#include "ui/widgets/PageContainer.h"
-#include "ui/pages/modplatform/modrinth/ModrinthModPage.h"
#include "ModDownloadTask.h"
+#include "ui/pages/modplatform/flame/FlameModPage.h"
+#include "ui/pages/modplatform/modrinth/ModrinthModPage.h"
+#include "ui/widgets/PageContainer.h"
-
-ModDownloadDialog::ModDownloadDialog(const std::shared_ptr<ModFolderModel> &mods, QWidget *parent,
- BaseInstance *instance)
- : QDialog(parent), mods(mods), m_instance(instance)
+ModDownloadDialog::ModDownloadDialog(const std::shared_ptr<ModFolderModel>& mods, QWidget* parent, BaseInstance* instance)
+ : QDialog(parent), mods(mods), m_verticalLayout(new QVBoxLayout(this)), m_instance(instance)
{
setObjectName(QStringLiteral("ModDownloadDialog"));
-
- resize(std::max(0.5*parent->width(), 400.0), std::max(0.75*parent->height(), 400.0));
-
- m_verticalLayout = new QVBoxLayout(this);
m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
+ resize(std::max(0.5 * parent->width(), 400.0), std::max(0.75 * parent->height(), 400.0));
+
setWindowIcon(APPLICATION->getThemedIcon("new"));
- // NOTE: m_buttons must be initialized before PageContainer, because it indirectly accesses m_buttons through setSuggestedPack! Do not move this below.
+ // NOTE: m_buttons must be initialized before PageContainer, because it indirectly accesses m_buttons through setSuggestedPack! Do not
+ // move this below.
m_buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
m_container = new PageContainer(this);
@@ -58,12 +55,17 @@ ModDownloadDialog::ModDownloadDialog(const std::shared_ptr<ModFolderModel> &mods
m_container->addButtons(m_buttons);
+ connect(m_container, &PageContainer::selectedPageChanged, this, &ModDownloadDialog::selectedPageChanged);
+
// Bonk Qt over its stupid head and make sure it understands which button is the default one...
// See: https://stackoverflow.com/questions/24556831/qbuttonbox-set-default-button
auto OkButton = m_buttons->button(QDialogButtonBox::Ok);
OkButton->setEnabled(false);
OkButton->setDefault(true);
OkButton->setAutoDefault(true);
+ OkButton->setText(tr("Review and confirm"));
+ OkButton->setShortcut(tr("Ctrl+Return"));
+ OkButton->setToolTip(tr("Opens a new popup to review your selected mods and confirm your selection. Shortcut: Ctrl+Return"));
connect(OkButton, &QPushButton::clicked, this, &ModDownloadDialog::confirm);
auto CancelButton = m_buttons->button(QDialogButtonBox::Cancel);
@@ -78,7 +80,9 @@ ModDownloadDialog::ModDownloadDialog(const std::shared_ptr<ModFolderModel> &mods
QMetaObject::connectSlotsByName(this);
setWindowModality(Qt::WindowModal);
- setWindowTitle("Download mods");
+ setWindowTitle(dialogTitle());
+
+ restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("ModDownloadGeometry").toByteArray()));
}
QString ModDownloadDialog::dialogTitle()
@@ -88,6 +92,7 @@ QString ModDownloadDialog::dialogTitle()
void ModDownloadDialog::reject()
{
+ APPLICATION->settings()->set("ModDownloadGeometry", saveGeometry().toBase64());
QDialog::reject();
}
@@ -114,12 +119,13 @@ void ModDownloadDialog::confirm()
void ModDownloadDialog::accept()
{
+ APPLICATION->settings()->set("ModDownloadGeometry", saveGeometry().toBase64());
QDialog::accept();
}
-QList<BasePage *> ModDownloadDialog::getPages()
+QList<BasePage*> ModDownloadDialog::getPages()
{
- QList<BasePage *> pages;
+ QList<BasePage*> pages;
pages.append(new ModrinthModPage(this, m_instance));
if (APPLICATION->capabilities() & Application::SupportsFlame)
@@ -128,7 +134,7 @@ QList<BasePage *> ModDownloadDialog::getPages()
return pages;
}
-void ModDownloadDialog::addSelectedMod(const QString& name, ModDownloadTask* task)
+void ModDownloadDialog::addSelectedMod(QString name, ModDownloadTask* task)
{
removeSelectedMod(name);
modTask.insert(name, task);
@@ -136,16 +142,16 @@ void ModDownloadDialog::addSelectedMod(const QString& name, ModDownloadTask* tas
m_buttons->button(QDialogButtonBox::Ok)->setEnabled(!modTask.isEmpty());
}
-void ModDownloadDialog::removeSelectedMod(const QString &name)
+void ModDownloadDialog::removeSelectedMod(QString name)
{
- if(modTask.contains(name))
+ if (modTask.contains(name))
delete modTask.find(name).value();
modTask.remove(name);
m_buttons->button(QDialogButtonBox::Ok)->setEnabled(!modTask.isEmpty());
}
-bool ModDownloadDialog::isModSelected(const QString &name, const QString& filename) const
+bool ModDownloadDialog::isModSelected(QString name, QString filename) const
{
// FIXME: Is there a way to check for versions without checking the filename
// as a heuristic, other than adding such info to ModDownloadTask itself?
@@ -153,16 +159,31 @@ bool ModDownloadDialog::isModSelected(const QString &name, const QString& filena
return iter != modTask.end() && (iter.value()->getFilename() == filename);
}
-bool ModDownloadDialog::isModSelected(const QString &name) const
+bool ModDownloadDialog::isModSelected(QString name) const
{
auto iter = modTask.find(name);
return iter != modTask.end();
}
-ModDownloadDialog::~ModDownloadDialog()
+const QList<ModDownloadTask*> ModDownloadDialog::getTasks()
{
+ return modTask.values();
}
-const QList<ModDownloadTask*> ModDownloadDialog::getTasks() {
- return modTask.values();
+void ModDownloadDialog::selectedPageChanged(BasePage* previous, BasePage* selected)
+{
+ auto* prev_page = dynamic_cast<ModPage*>(previous);
+ if (!prev_page) {
+ qCritical() << "Page '" << previous->displayName() << "' in ModDownloadDialog is not a ModPage!";
+ return;
+ }
+
+ auto* selected_page = dynamic_cast<ModPage*>(selected);
+ if (!selected_page) {
+ qCritical() << "Page '" << selected->displayName() << "' in ModDownloadDialog is not a ModPage!";
+ return;
+ }
+
+ // Same effect as having a global search bar
+ selected_page->setSearchTerm(prev_page->getSearchTerm());
}
diff --git a/launcher/ui/dialogs/ModDownloadDialog.h b/launcher/ui/dialogs/ModDownloadDialog.h
index 1fa1f058..18a5f0f3 100644
--- a/launcher/ui/dialogs/ModDownloadDialog.h
+++ b/launcher/ui/dialogs/ModDownloadDialog.h
@@ -21,11 +21,9 @@
#include <QDialog>
#include <QVBoxLayout>
-#include "BaseVersion.h"
-#include "ui/pages/BasePageProvider.h"
-#include "minecraft/mod/ModFolderModel.h"
#include "ModDownloadTask.h"
-#include "ui/pages/modplatform/flame/FlameModPage.h"
+#include "minecraft/mod/ModFolderModel.h"
+#include "ui/pages/BasePageProvider.h"
namespace Ui
{
@@ -36,21 +34,21 @@ class PageContainer;
class QDialogButtonBox;
class ModrinthModPage;
-class ModDownloadDialog : public QDialog, public BasePageProvider
+class ModDownloadDialog final : public QDialog, public BasePageProvider
{
Q_OBJECT
public:
- explicit ModDownloadDialog(const std::shared_ptr<ModFolderModel> &mods, QWidget *parent, BaseInstance *instance);
- ~ModDownloadDialog();
+ explicit ModDownloadDialog(const std::shared_ptr<ModFolderModel>& mods, QWidget* parent, BaseInstance* instance);
+ ~ModDownloadDialog() override = default;
QString dialogTitle() override;
- QList<BasePage *> getPages() override;
+ QList<BasePage*> getPages() override;
- void addSelectedMod(const QString & name = QString(), ModDownloadTask * task = nullptr);
- void removeSelectedMod(const QString & name = QString());
- bool isModSelected(const QString & name, const QString & filename) const;
- bool isModSelected(const QString & name) const;
+ void addSelectedMod(QString name = QString(), ModDownloadTask* task = nullptr);
+ void removeSelectedMod(QString name = QString());
+ bool isModSelected(QString name, QString filename) const;
+ bool isModSelected(QString name) const;
const QList<ModDownloadTask*> getTasks();
const std::shared_ptr<ModFolderModel> &mods;
@@ -60,6 +58,9 @@ public slots:
void accept() override;
void reject() override;
+private slots:
+ void selectedPageChanged(BasePage* previous, BasePage* selected);
+
private:
Ui::ModDownloadDialog *ui = nullptr;
PageContainer * m_container = nullptr;
diff --git a/launcher/ui/dialogs/ReviewMessageBox.cpp b/launcher/ui/dialogs/ReviewMessageBox.cpp
index e664e566..7c25c91c 100644
--- a/launcher/ui/dialogs/ReviewMessageBox.cpp
+++ b/launcher/ui/dialogs/ReviewMessageBox.cpp
@@ -1,11 +1,16 @@
#include "ReviewMessageBox.h"
#include "ui_ReviewMessageBox.h"
+#include <QPushButton>
+
ReviewMessageBox::ReviewMessageBox(QWidget* parent, QString const& title, QString const& icon)
: QDialog(parent), ui(new Ui::ReviewMessageBox)
{
ui->setupUi(this);
+ auto back_button = ui->buttonBox->button(QDialogButtonBox::Cancel);
+ back_button->setText(tr("Back"));
+
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &ReviewMessageBox::accept);
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &ReviewMessageBox::reject);
}
diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp
index 06a6f6b8..029e2be0 100644
--- a/launcher/ui/pages/modplatform/ModModel.cpp
+++ b/launcher/ui/pages/modplatform/ModModel.cpp
@@ -2,15 +2,27 @@
#include "BuildConfig.h"
#include "Json.h"
+#include "ModPage.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "ui/dialogs/ModDownloadDialog.h"
+#include "ui/widgets/ProjectItem.h"
+
#include <QMessageBox>
namespace ModPlatform {
-ListModel::ListModel(ModPage* parent) : QAbstractListModel(parent), m_parent(parent) {}
+// HACK: We need this to prevent callbacks from calling the ListModel after it has already been deleted.
+// This leaks a tiny bit of memory per time the user has opened the mod dialog. How to make this better?
+static QHash<ListModel*, bool> s_running;
+
+ListModel::ListModel(ModPage* parent) : QAbstractListModel(parent), m_parent(parent) { s_running.insert(this, true); }
+
+ListModel::~ListModel()
+{
+ s_running.find(this).value() = false;
+}
auto ListModel::debugName() const -> QString
{
@@ -39,9 +51,6 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant
ModPlatform::IndexedPack pack = modpacks.at(pos);
switch (role) {
- case Qt::DisplayRole: {
- return pack.name;
- }
case Qt::ToolTipRole: {
if (pack.description.length() > 100) {
// some magic to prevent to long tooltips and replace html linebreaks
@@ -64,20 +73,20 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant
((ListModel*)this)->requestLogo(pack.logoName, pack.logoUrl);
return icon;
}
+ case Qt::SizeHintRole:
+ return QSize(0, 58);
case Qt::UserRole: {
QVariant v;
v.setValue(pack);
return v;
}
- case Qt::FontRole: {
- QFont font;
- if (m_parent->getDialog()->isModSelected(pack.name)) {
- font.setBold(true);
- font.setUnderline(true);
- }
-
- return font;
- }
+ // Custom data
+ case UserDataTypes::TITLE:
+ return pack.name;
+ case UserDataTypes::DESCRIPTION:
+ return pack.description;
+ case UserDataTypes::SELECTED:
+ return m_parent->getDialog()->isModSelected(pack.name);
default:
break;
}
@@ -85,11 +94,27 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant
return {};
}
-void ListModel::requestModVersions(ModPlatform::IndexedPack const& current)
+bool ListModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ int pos = index.row();
+ if (pos >= modpacks.size() || pos < 0 || !index.isValid())
+ return false;
+
+ modpacks[pos] = value.value<ModPlatform::IndexedPack>();
+
+ return true;
+}
+
+void ListModel::requestModVersions(ModPlatform::IndexedPack const& current, QModelIndex index)
{
auto profile = (dynamic_cast<MinecraftInstance*>((dynamic_cast<ModPage*>(parent()))->m_instance))->getPackProfile();
- m_parent->apiProvider()->getVersions(this, { current.addonId.toString(), getMineVersions(), profile->getModLoaders() });
+ m_parent->apiProvider()->getVersions({ current.addonId.toString(), getMineVersions(), profile->getModLoaders() },
+ [this, current, index](QJsonDocument& doc, QString addonId) {
+ if (!s_running.constFind(this).value())
+ return;
+ versionRequestSucceeded(doc, addonId, index);
+ });
}
void ListModel::performPaginatedSearch()
@@ -100,9 +125,13 @@ void ListModel::performPaginatedSearch()
this, { nextSearchOffset, currentSearchTerm, getSorts()[currentSort], profile->getModLoaders(), getMineVersions() });
}
-void ListModel::requestModInfo(ModPlatform::IndexedPack& current)
+void ListModel::requestModInfo(ModPlatform::IndexedPack& current, QModelIndex index)
{
- m_parent->apiProvider()->getModInfo(this, current);
+ m_parent->apiProvider()->getModInfo(current, [this, index](QJsonDocument& doc, ModPlatform::IndexedPack& pack) {
+ if (!s_running.constFind(this).value())
+ return;
+ infoRequestFinished(doc, pack, index);
+ });
}
void ListModel::refresh()
@@ -256,7 +285,7 @@ void ListModel::searchRequestFailed(QString reason)
}
}
-void ListModel::infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack)
+void ListModel::infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index)
{
qDebug() << "Loading mod info";
@@ -268,10 +297,20 @@ void ListModel::infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack
qWarning() << "Error while reading " << debugName() << " mod info: " << e.cause();
}
+ // Check if the index is still valid for this mod or not
+ if (pack.addonId == data(index, Qt::UserRole).value<ModPlatform::IndexedPack>().addonId) {
+ // Cache info :^)
+ QVariant new_pack;
+ new_pack.setValue(pack);
+ if (!setData(index, new_pack, Qt::UserRole)) {