From 4a13dbe3bb22ba47cf1ea5dfe0e9ffc9688b048a Mon Sep 17 00:00:00 2001 From: flow Date: Thu, 14 Jul 2022 22:23:41 -0300 Subject: feat: create delegate for project item views This allows us to define custom painting for list view items. In particular, this is applied to the mod downloader, in order to allow displaying both the mod name and mod description, and settings their effects (like bold or underline) independent of each other. Signed-off-by: flow --- launcher/ui/pages/modplatform/ModModel.cpp | 23 +++++++++++------------ launcher/ui/pages/modplatform/ModModel.h | 1 - launcher/ui/pages/modplatform/ModPage.cpp | 3 +++ 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 94b1f099..5861fcc6 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -6,6 +6,8 @@ #include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" +#include "ui/widgets/ProjectItem.h" + #include namespace ModPlatform { @@ -39,9 +41,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 +63,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; } diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index dd22407c..de864df5 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -2,7 +2,6 @@ #include -#include "modplatform/ModAPI.h" #include "modplatform/ModIndex.h" #include "net/NetJob.h" diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 200fe59e..b7fe0ffa 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -43,6 +43,7 @@ #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" +#include "ui/widgets/ProjectItem.h" ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api) : QWidget(dialog) @@ -71,6 +72,8 @@ ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api) connect(&filter_widget, &ModFilterWidget::filterUnchanged, this, [&]{ ui->searchButton->setStyleSheet("text-decoration: none"); }); + + ui->packView->setItemDelegate(new ProjectItemDelegate(this)); } ModPage::~ModPage() -- cgit From 6e9a27f40faa00719f7cfd680edc5e16c86a9da7 Mon Sep 17 00:00:00 2001 From: flow Date: Thu, 16 Jun 2022 20:46:47 -0300 Subject: feat: display the 'body' of a MR mod on the mod downloader Signed-off-by: flow --- launcher/ui/pages/modplatform/ModPage.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index b7fe0ffa..a9a37b4b 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -40,6 +40,8 @@ #include #include +#include + #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" @@ -288,5 +290,6 @@ void ModPage::updateUi() text += "
"; - ui->packDescription->setHtml(text + current.description); + HoeDown h; + ui->packDescription->setHtml(text + (current.extraData.body.isEmpty() ? current.description : h.process(current.extraData.body.toUtf8()))); } -- cgit From a8bcd85c93ad1e5af277652862f773413c255c47 Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 15 Jul 2022 09:34:11 -0300 Subject: feat+refactor: add shortcuts to mod downloader and clean up Signed-off-by: flow --- launcher/ui/pages/modplatform/ModModel.cpp | 1 + launcher/ui/pages/modplatform/ModPage.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 5861fcc6..84f6f4c4 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -2,6 +2,7 @@ #include "BuildConfig.h" #include "Json.h" +#include "ModPage.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index a9a37b4b..c355f069 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -76,6 +76,7 @@ ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api) }); ui->packView->setItemDelegate(new ProjectItemDelegate(this)); + ui->packView->installEventFilter(this); } ModPage::~ModPage() @@ -98,6 +99,18 @@ auto ModPage::eventFilter(QObject* watched, QEvent* event) -> bool auto* keyEvent = dynamic_cast(event); if (keyEvent->key() == Qt::Key_Return) { triggerSearch(); + keyEvent->accept(); + return true; + } + } else if (watched == ui->packView && event->type() == QEvent::KeyPress) { + auto* keyEvent = dynamic_cast(event); + if (keyEvent->key() == Qt::Key_Return) { + onModSelected(); + + // To have the 'select mod' button outlined instead of the 'review and confirm' one + ui->modSelectionButton->setFocus(Qt::FocusReason::ShortcutFocusReason); + ui->packView->setFocus(Qt::FocusReason::NoFocusReason); + keyEvent->accept(); return true; } @@ -172,6 +185,9 @@ void ModPage::onVersionSelectionChanged(QString data) void ModPage::onModSelected() { + if (selectedVersion < 0) + return; + auto& version = current.versions[selectedVersion]; if (dialog->isModSelected(current.name, version.fileName)) { dialog->removeSelectedMod(current.name); -- cgit From 5936c7b65ceef28fb569e966f2bcbe3aed3fa999 Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 15 Jul 2022 11:20:08 -0300 Subject: change: preserve search term across different mod providers Signed-off-by: flow --- launcher/ui/pages/modplatform/ModPage.cpp | 11 ++++++++++- launcher/ui/pages/modplatform/ModPage.h | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index c355f069..e052b655 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -138,7 +138,16 @@ void ModPage::triggerSearch() updateSelectionButton(); } - listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex(), changed); + listModel->searchWithTerm(getSearchTerm(), ui->sortByBox->currentIndex(), changed); +} + +QString ModPage::getSearchTerm() const +{ + return ui->searchEdit->text(); +} +void ModPage::setSearchTerm(QString term) +{ + ui->searchEdit->setText(term); } void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second) diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index cf00e16e..4990c1c0 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -45,6 +45,11 @@ class ModPage : public QWidget, public BasePage { auto getFilter() const -> const std::shared_ptr { return m_filter; } auto getDialog() const -> const ModDownloadDialog* { return dialog; } + /** Get the current term in the search bar. */ + auto getSearchTerm() const -> QString; + /** Programatically set the term in the search bar. */ + void setSearchTerm(QString); + auto getCurrent() -> ModPlatform::IndexedPack& { return current; } void updateModVersions(int prev_count = -1); -- cgit From c3f647dc962a0da6e96e54f472ee764370ed4f66 Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 15 Jul 2022 11:57:27 -0300 Subject: feat: add (semi) instant searching in mod downloader It has a delay of 350ms from the last typed character to search, in order to cache small changes while typing. Signed-off-by: flow --- launcher/ui/pages/modplatform/ModPage.cpp | 12 ++++++++++++ launcher/ui/pages/modplatform/ModPage.h | 3 +++ 2 files changed, 15 insertions(+) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index e052b655..4fad037e 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -56,8 +56,15 @@ ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api) , api(api) { ui->setupUi(this); + connect(ui->searchButton, &QPushButton::clicked, this, &ModPage::triggerSearch); connect(ui->modFilterButton, &QPushButton::clicked, this, &ModPage::filterMods); + + m_search_timer.setTimerType(Qt::TimerType::CoarseTimer); + m_search_timer.setSingleShot(true); + + connect(&m_search_timer, &QTimer::timeout, this, &ModPage::triggerSearch); + ui->searchEdit->installEventFilter(this); ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -101,6 +108,11 @@ auto ModPage::eventFilter(QObject* watched, QEvent* event) -> bool triggerSearch(); keyEvent->accept(); return true; + } else { + if (m_search_timer.isActive()) + m_search_timer.stop(); + + m_search_timer.start(350); } } else if (watched == ui->packView && event->type() == QEvent::KeyPress) { auto* keyEvent = dynamic_cast(event); diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index 4990c1c0..c58a7cbb 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -81,4 +81,7 @@ class ModPage : public QWidget, public BasePage { std::unique_ptr api; int selectedVersion = -1; + + // Used to do instant searching with a delay to cache quick changes + QTimer m_search_timer; }; -- cgit From 158b7fd166f6be76b4e6c0e3f7cf14d6a4b43a17 Mon Sep 17 00:00:00 2001 From: flow Date: Fri, 15 Jul 2022 13:18:12 -0300 Subject: feat+refactor: clean up ProgressWidget and add progress indicatior to mod downloader Signed-off-by: flow --- launcher/ui/pages/modplatform/ModModel.h | 1 + launcher/ui/pages/modplatform/ModPage.cpp | 9 ++++++++- launcher/ui/pages/modplatform/ModPage.h | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index de864df5..96747fbd 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -30,6 +30,7 @@ class ListModel : public QAbstractListModel { auto data(const QModelIndex& index, int role) const -> QVariant override; inline void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; } + inline NetJob* activeJob() { return jobPtr.get(); } /* Ask the API for more information */ void fetchMore(const QModelIndex& parent) override; diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 4fad037e..176f8fde 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -53,6 +53,7 @@ ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api) , ui(new Ui::ModPage) , dialog(dialog) , filter_widget(static_cast(instance)->getPackProfile()->getComponentVersion("net.minecraft"), this) + , m_fetch_progress(this, false) , api(api) { ui->setupUi(this); @@ -70,7 +71,12 @@ ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api) ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); - ui->gridLayout_3->addWidget(&filter_widget, 0, 0, 1, ui->gridLayout_3->columnCount()); + m_fetch_progress.hideIfInactive(true); + m_fetch_progress.setFixedHeight(24); + m_fetch_progress.progressFormat(""); + + ui->gridLayout_3->addWidget(&m_fetch_progress, 0, 0, 1, ui->gridLayout_3->columnCount()); + ui->gridLayout_3->addWidget(&filter_widget, 1, 0, 1, ui->gridLayout_3->columnCount()); filter_widget.setInstance(static_cast(m_instance)); m_filter = filter_widget.getFilter(); @@ -151,6 +157,7 @@ void ModPage::triggerSearch() } listModel->searchWithTerm(getSearchTerm(), ui->sortByBox->currentIndex(), changed); + m_fetch_progress.watch(listModel->activeJob()); } QString ModPage::getSearchTerm() const diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index c58a7cbb..09c38d8b 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -8,6 +8,7 @@ #include "ui/pages/BasePage.h" #include "ui/pages/modplatform/ModModel.h" #include "ui/widgets/ModFilterWidget.h" +#include "ui/widgets/ProgressWidget.h" class ModDownloadDialog; @@ -75,6 +76,8 @@ class ModPage : public QWidget, public BasePage { ModFilterWidget filter_widget; std::shared_ptr m_filter; + ProgressWidget m_fetch_progress; + ModPlatform::ListModel* listModel = nullptr; ModPlatform::IndexedPack current; -- cgit From 74c6c5cfbc9f588052d8423c03c30f2c547bd5c9 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 18 Jul 2022 19:15:02 -0300 Subject: refactor: use function cb instead of class cb in getModInfo I've discovered functional programming :^) This makes this route more fit for general use. Signed-off-by: flow --- launcher/ui/pages/modplatform/ModModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 84f6f4c4..77ecd056 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -102,7 +102,8 @@ void ListModel::performPaginatedSearch() void ListModel::requestModInfo(ModPlatform::IndexedPack& current) { - m_parent->apiProvider()->getModInfo(this, current); + m_parent->apiProvider()->getModInfo( + current, [this](QJsonDocument& doc, ModPlatform::IndexedPack& pack) { infoRequestFinished(doc, pack); }); } void ListModel::refresh() -- cgit From 5bc67d3f6b03bae6ff861d6641d22bbddefe2202 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 18 Jul 2022 19:17:44 -0300 Subject: feat: cache extra mod info (like links and body) Signed-off-by: flow --- launcher/ui/pages/modplatform/ModModel.cpp | 27 ++++++++++++++++++++++++--- launcher/ui/pages/modplatform/ModModel.h | 5 +++-- launcher/ui/pages/modplatform/ModPage.cpp | 9 +++++---- 3 files changed, 32 insertions(+), 9 deletions(-) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 77ecd056..13cfc9cb 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -85,6 +85,17 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant return {}; } +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(); + + return true; +} + void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) { auto profile = (dynamic_cast((dynamic_cast(parent()))->m_instance))->getPackProfile(); @@ -100,10 +111,10 @@ 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( - current, [this](QJsonDocument& doc, ModPlatform::IndexedPack& pack) { infoRequestFinished(doc, pack); }); + current, [this, index](QJsonDocument& doc, ModPlatform::IndexedPack& pack) { infoRequestFinished(doc, pack, index); }); } void ListModel::refresh() @@ -256,7 +267,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,6 +279,16 @@ 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().addonId) { + // Cache info :^) + QVariant new_pack; + new_pack.setValue(pack); + if (!setData(index, new_pack, Qt::UserRole)) { + qWarning() << "Failed to cache mod info!"; + } + } + m_parent->updateUi(); } diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index 96747fbd..33b327d0 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -28,6 +28,7 @@ class ListModel : public QAbstractListModel { /* Retrieve information from the model at a given index with the given role */ auto data(const QModelIndex& index, int role) const -> QVariant override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; inline void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; } inline NetJob* activeJob() { return jobPtr.get(); } @@ -36,7 +37,7 @@ class ListModel : public QAbstractListModel { void fetchMore(const QModelIndex& parent) override; void refresh(); void searchWithTerm(const QString& term, const int sort, const bool filter_changed); - void requestModInfo(ModPlatform::IndexedPack& current); + void requestModInfo(ModPlatform::IndexedPack& current, QModelIndex index); void requestModVersions(const ModPlatform::IndexedPack& current); virtual void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) = 0; @@ -51,7 +52,7 @@ class ListModel : public QAbstractListModel { void searchRequestFinished(QJsonDocument& doc); void searchRequestFailed(QString reason); - void infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack); + void infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index); void versionRequestSucceeded(QJsonDocument doc, QString addonId); diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 176f8fde..59831dd9 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -169,13 +169,13 @@ void ModPage::setSearchTerm(QString term) ui->searchEdit->setText(term); } -void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second) +void ModPage::onSelectionChanged(QModelIndex curr, QModelIndex prev) { ui->versionSelectionBox->clear(); - if (!first.isValid()) { return; } + if (!curr.isValid()) { return; } - current = listModel->data(first, Qt::UserRole).value(); + current = listModel->data(curr, Qt::UserRole).value(); if (!current.versionsLoaded) { qDebug() << QString("Loading %1 mod versions").arg(debugName()); @@ -195,7 +195,8 @@ void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second) if(!current.extraDataLoaded){ qDebug() << QString("Loading %1 mod info").arg(debugName()); - listModel->requestModInfo(current); + + listModel->requestModInfo(current, curr); } updateUi(); -- cgit From 6f052baa94f6f758cb18b81e2cf5e28cdc5bd367 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 18 Jul 2022 19:22:31 -0300 Subject: refactor: use function cb instead of class cb in getVersions I've discovered even more functional programming! :^) Signed-off-by: flow --- launcher/ui/pages/modplatform/ModModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 13cfc9cb..f3e1e6ae 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -100,7 +100,8 @@ void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) { auto profile = (dynamic_cast((dynamic_cast(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](QJsonDocument& doc, QString addonId) { versionRequestSucceeded(doc, addonId); }); } void ListModel::performPaginatedSearch() -- cgit From 0808a10b7b9b9cde808a62b7d617b5c7010c24cf Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 18 Jul 2022 19:28:46 -0300 Subject: feat: cache mod versions Signed-off-by: flow --- launcher/ui/pages/modplatform/ModModel.cpp | 14 +++++++++++--- launcher/ui/pages/modplatform/ModModel.h | 4 ++-- launcher/ui/pages/modplatform/ModPage.cpp | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index f3e1e6ae..9d7a9970 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -96,12 +96,12 @@ bool ListModel::setData(const QModelIndex &index, const QVariant &value, int rol return true; } -void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) +void ListModel::requestModVersions(ModPlatform::IndexedPack const& current, QModelIndex index) { auto profile = (dynamic_cast((dynamic_cast(parent()))->m_instance))->getPackProfile(); m_parent->apiProvider()->getVersions({ current.addonId.toString(), getMineVersions(), profile->getModLoaders() }, - [this, current](QJsonDocument& doc, QString addonId) { versionRequestSucceeded(doc, addonId); }); + [this, current, index](QJsonDocument& doc, QString addonId) { versionRequestSucceeded(doc, addonId, index); }); } void ListModel::performPaginatedSearch() @@ -293,7 +293,7 @@ void ListModel::infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack m_parent->updateUi(); } -void ListModel::versionRequestSucceeded(QJsonDocument doc, QString addonId) +void ListModel::versionRequestSucceeded(QJsonDocument doc, QString addonId, const QModelIndex& index) { auto& current = m_parent->getCurrent(); if (addonId != current.addonId) { @@ -309,6 +309,14 @@ void ListModel::versionRequestSucceeded(QJsonDocument doc, QString addonId) qWarning() << "Error while reading " << debugName() << " mod version: " << e.cause(); } + // Cache info :^) + QVariant new_pack; + new_pack.setValue(current); + if (!setData(index, new_pack, Qt::UserRole)) { + qWarning() << "Failed to cache mod versions!"; + } + + m_parent->updateModVersions(); } diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index 33b327d0..d338b8c0 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -38,7 +38,7 @@ class ListModel : public QAbstractListModel { void refresh(); void searchWithTerm(const QString& term, const int sort, const bool filter_changed); void requestModInfo(ModPlatform::IndexedPack& current, QModelIndex index); - void requestModVersions(const ModPlatform::IndexedPack& current); + void requestModVersions(const ModPlatform::IndexedPack& current, QModelIndex index); virtual void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) = 0; virtual void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) {}; @@ -54,7 +54,7 @@ class ListModel : public QAbstractListModel { void infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index); - void versionRequestSucceeded(QJsonDocument doc, QString addonId); + void versionRequestSucceeded(QJsonDocument doc, QString addonId, const QModelIndex& index); protected slots: diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 59831dd9..014ba5af 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -183,7 +183,7 @@ void ModPage::onSelectionChanged(QModelIndex curr, QModelIndex prev) ui->modSelectionButton->setText(tr("Loading versions...")); ui->modSelectionButton->setEnabled(false); - listModel->requestModVersions(current); + listModel->requestModVersions(current, curr); } else { for (int i = 0; i < current.versions.size(); i++) { ui->versionSelectionBox->addItem(current.versions[i].version, QVariant(i)); -- cgit From 6aaf1f4f213bb258bc565d4085da13158abf4520 Mon Sep 17 00:00:00 2001 From: flow Date: Tue, 19 Jul 2022 12:29:31 -0300 Subject: feat: lazy-load CF mod descriptions Signed-off-by: flow --- launcher/ui/pages/modplatform/flame/FlameModModel.cpp | 6 ++++++ launcher/ui/pages/modplatform/flame/FlameModModel.h | 1 + 2 files changed, 7 insertions(+) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index 8de2e545..bc2c686c 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -12,6 +12,12 @@ void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) FlameMod::loadIndexedPack(m, obj); } +// We already deal with the URLs when initializing the pack, due to the API response's structure +void ListModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) +{ + FlameMod::loadBody(m, obj); +} + void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) { FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance); diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.h b/launcher/ui/pages/modplatform/flame/FlameModModel.h index 707c1bb1..6a6aef2e 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.h +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.h @@ -13,6 +13,7 @@ class ListModel : public ModPlatform::ListModel { private: void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override; + void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) override; void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override; auto documentToArray(QJsonDocument& obj) const -> QJsonArray override; -- cgit From cee41b87f728e79d7e1ec0e67c24dc23a5dde9d0 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 31 Jul 2022 16:01:47 -0300 Subject: fix(ui): force redraw of mod list when (de)selecting a mod Signed-off-by: flow --- launcher/ui/pages/modplatform/ModPage.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 014ba5af..a34a74db 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -226,6 +226,9 @@ void ModPage::onModSelected() } updateSelectionButton(); + + /* Force redraw on the mods list when the selection changes */ + ui->packView->adjustSize(); } -- cgit From 4a8abc948ef15664dbde196ba77daccdf3d623ad Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 1 Aug 2022 18:34:15 -0300 Subject: fix: prevent segfault due to callbacks into deleted objects Since network requests are, for the most part, asynchronous, there's a chance a request only comes through after the request sender has already been deleted. This adds a global (read static) hash table relating models for the mod downloader to their status (true = alive, false = destroyed). It is a bit of a hack, but I couldn't come up with a better way of doing this. To reproduce the issue before this commit: scroll really quickly through CF mods, to trigger network requests for their versions and description. Then, in the middle of it close the mod downloader. Sometimes this will create a crash. Signed-off-by: flow --- launcher/ui/pages/modplatform/ModModel.cpp | 24 ++++++++++++++++++++---- launcher/ui/pages/modplatform/ModModel.h | 2 +- 2 files changed, 21 insertions(+), 5 deletions(-) (limited to 'launcher/ui/pages/modplatform') diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 9d7a9970..9cf9ec29 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -13,7 +13,16 @@ 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 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 { @@ -101,7 +110,11 @@ void ListModel::requestModVersions(ModPlatform::IndexedPack const& current, QMod auto profile = (dynamic_cast((dynamic_cast(parent()))->m_instance))->getPackProfile(); m_parent->apiProvider()->getVersions({ current.addonId.toString(), getMineVersions(), profile->getModLoaders() }, - [this, current, index](QJsonDocument& doc, QString addonId) { versionRequestSucceeded(doc, addonId, index); }); + [this, current, index](QJsonDocument& doc, QString addonId) { + if (!s_running.constFind(this).value()) + return; + versionRequestSucceeded(doc, addonId, index); + }); } void ListModel::performPaginatedSearch() @@ -114,8 +127,11 @@ void ListModel::performPaginatedSearch() void ListModel::requestModInfo(ModPlatform::IndexedPack& current, QModelIndex index) { - m_parent->apiProvider()->getModInfo( - current, [this, index](QJsonDocument& doc, ModPlatform::IndexedPack& pack) { infoRequestFinished(doc, pack, index); }); + 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() diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index d338b8c0..a58c7c55 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -18,7 +18,7 @@ class ListModel : public QAbstractListModel { public: ListModel(ModPage* parent); - ~ListModel() override = default; + ~ListModel() override; inline auto rowCount(const QModelIndex& parent) const -> int override { return modpacks.size(); }; inline auto columnCount(const QModelIndex& parent) const -> int override { return 1; }; -- cgit