diff options
| author | flow <flowlnlnln@gmail.com> | 2022-09-07 08:27:11 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-07 08:27:11 -0300 |
| commit | 1b0ca476824ad3d704de70720184d2f1e194d2f5 (patch) | |
| tree | 6d5574a10b1fd34af511f9126c51e62b5a994516 /launcher | |
| parent | 8e3f5c33057175b83ef276914d81ed4d5616d6e5 (diff) | |
| parent | 4a8abc948ef15664dbde196ba77daccdf3d623ad (diff) | |
| download | PrismLauncher-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')
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)) { |
