mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-06-12 21:27:44 +02:00
Merge remote-tracking branch 'upstream/develop' into data-packs
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
@ -152,33 +152,26 @@ void ModpackListModel::performPaginatedSearch()
|
||||
return;
|
||||
}
|
||||
} // TODO: Move to standalone API
|
||||
auto netJob = makeShared<NetJob>("Modrinth::SearchModpack", APPLICATION->network());
|
||||
auto searchAllUrl = QString(BuildConfig.MODRINTH_PROD_URL +
|
||||
"/search?"
|
||||
"offset=%1&"
|
||||
"limit=%2&"
|
||||
"query=%3&"
|
||||
"index=%4&"
|
||||
"facets=[[\"project_type:modpack\"]]")
|
||||
.arg(nextSearchOffset)
|
||||
.arg(m_modpacks_per_page)
|
||||
.arg(currentSearchTerm)
|
||||
.arg(currentSort);
|
||||
ResourceAPI::SortingMethod sort{};
|
||||
sort.name = currentSort;
|
||||
auto searchUrl = ModrinthAPI().getSearchURL({ ModPlatform::ResourceType::MODPACK, nextSearchOffset, currentSearchTerm, sort,
|
||||
m_filter->loaders, m_filter->versions, "", m_filter->categoryIds, m_filter->openSource });
|
||||
|
||||
netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchAllUrl), m_all_response));
|
||||
auto netJob = makeShared<NetJob>("Modrinth::SearchModpack", APPLICATION->network());
|
||||
netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchUrl.value()), m_allResponse));
|
||||
|
||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, [this] {
|
||||
QJsonParseError parse_error_all{};
|
||||
QJsonParseError parseError{};
|
||||
|
||||
QJsonDocument doc_all = QJsonDocument::fromJson(*m_all_response, &parse_error_all);
|
||||
if (parse_error_all.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from " << debugName() << " at " << parse_error_all.offset
|
||||
<< " reason: " << parse_error_all.errorString();
|
||||
qWarning() << *m_all_response;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*m_allResponse, &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from " << debugName() << " at " << parseError.offset
|
||||
<< " reason: " << parseError.errorString();
|
||||
qWarning() << *m_allResponse;
|
||||
return;
|
||||
}
|
||||
|
||||
searchRequestFinished(doc_all);
|
||||
searchRequestFinished(doc);
|
||||
});
|
||||
QObject::connect(netJob.get(), &NetJob::failed, this, &ModpackListModel::searchRequestFailed);
|
||||
|
||||
@ -220,19 +213,23 @@ static auto sortFromIndex(int index) -> QString
|
||||
}
|
||||
}
|
||||
|
||||
void ModpackListModel::searchWithTerm(const QString& term, const int sort)
|
||||
void ModpackListModel::searchWithTerm(const QString& term,
|
||||
const int sort,
|
||||
std::shared_ptr<ModFilterWidget::Filter> filter,
|
||||
bool filterChanged)
|
||||
{
|
||||
if (sort > 5 || sort < 0)
|
||||
return;
|
||||
|
||||
auto sort_str = sortFromIndex(sort);
|
||||
|
||||
if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort_str) {
|
||||
if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort_str && !filterChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentSearchTerm = term;
|
||||
currentSort = sort_str;
|
||||
m_filter = filter;
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ class ModpackListModel : public QAbstractListModel {
|
||||
/* Ask the API for more information */
|
||||
void fetchMore(const QModelIndex& parent) override;
|
||||
void refresh();
|
||||
void searchWithTerm(const QString& term, int sort);
|
||||
void searchWithTerm(const QString& term, int sort, std::shared_ptr<ModFilterWidget::Filter> filter, bool filterChanged);
|
||||
|
||||
[[nodiscard]] bool hasActiveSearchJob() const { return jobPtr && jobPtr->isRunning(); }
|
||||
[[nodiscard]] Task::Ptr activeSearchJob() { return hasActiveSearchJob() ? jobPtr : nullptr; }
|
||||
@ -112,12 +112,13 @@ class ModpackListModel : public QAbstractListModel {
|
||||
|
||||
QString currentSearchTerm;
|
||||
QString currentSort;
|
||||
std::shared_ptr<ModFilterWidget::Filter> m_filter;
|
||||
int nextSearchOffset = 0;
|
||||
enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None;
|
||||
|
||||
Task::Ptr jobPtr;
|
||||
|
||||
std::shared_ptr<QByteArray> m_all_response = std::make_shared<QByteArray>();
|
||||
std::shared_ptr<QByteArray> m_allResponse = std::make_shared<QByteArray>();
|
||||
QByteArray m_specific_response;
|
||||
|
||||
int m_modpacks_per_page = 20;
|
||||
|
@ -35,6 +35,8 @@
|
||||
*/
|
||||
|
||||
#include "ModrinthPage.h"
|
||||
#include "Version.h"
|
||||
#include "modplatform/modrinth/ModrinthAPI.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui_ModrinthPage.h"
|
||||
|
||||
@ -58,6 +60,7 @@ ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent)
|
||||
: QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog), m_fetch_progress(this, false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
createFilterWidget();
|
||||
|
||||
ui->searchEdit->installEventFilter(this);
|
||||
m_model = new Modrinth::ModpackListModel(this);
|
||||
@ -126,6 +129,16 @@ bool ModrinthPage::eventFilter(QObject* watched, QEvent* event)
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
bool checkVersionFilters(const Modrinth::ModpackVersion& v, std::shared_ptr<ModFilterWidget::Filter> filter)
|
||||
{
|
||||
if (!filter)
|
||||
return true;
|
||||
return ((!filter->loaders || !v.loaders || filter->loaders & v.loaders) && // loaders
|
||||
(filter->releases.empty() || // releases
|
||||
std::find(filter->releases.cbegin(), filter->releases.cend(), v.version_type) != filter->releases.cend()) &&
|
||||
filter->checkMcVersions({ v.gameVersion })); // gameVersion}
|
||||
}
|
||||
|
||||
void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelIndex prev)
|
||||
{
|
||||
ui->versionSelectionBox->clear();
|
||||
@ -190,7 +203,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
|
||||
} else
|
||||
updateUI();
|
||||
|
||||
if (!current.versionsLoaded) {
|
||||
if (!current.versionsLoaded || m_filterWidget->changed()) {
|
||||
qDebug() << "Loading modrinth modpack versions";
|
||||
|
||||
auto netJob = new NetJob(QString("Modrinth::PackVersions(%1)").arg(current.name), APPLICATION->network());
|
||||
@ -221,6 +234,16 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
|
||||
qDebug() << *response;
|
||||
qWarning() << "Error while reading modrinth modpack version: " << e.cause();
|
||||
}
|
||||
auto pred = [this](const Modrinth::ModpackVersion& v) { return !checkVersionFilters(v, m_filterWidget->getFilter()); };
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
|
||||
current.versions.removeIf(pred);
|
||||
#else
|
||||
for (auto it = current.versions.begin(); it != current.versions.end();)
|
||||
if (pred(*it))
|
||||
it = current.versions.erase(it);
|
||||
else
|
||||
++it;
|
||||
#endif
|
||||
for (auto version : current.versions) {
|
||||
auto release_type = version.version_type.isValid() ? QString(" [%1]").arg(version.version_type.toString()) : "";
|
||||
auto mcVersion = !version.gameVersion.isEmpty() && !version.name.contains(version.gameVersion)
|
||||
@ -338,7 +361,11 @@ void ModrinthPage::suggestCurrent()
|
||||
|
||||
void ModrinthPage::triggerSearch()
|
||||
{
|
||||
m_model->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex());
|
||||
ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect);
|
||||
ui->packView->clearSelection();
|
||||
ui->packDescription->clear();
|
||||
ui->versionSelectionBox->clear();
|
||||
m_model->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex(), m_filterWidget->getFilter(), m_filterWidget->changed());
|
||||
m_fetch_progress.watch(m_model->activeSearchJob().get());
|
||||
}
|
||||
|
||||
@ -348,6 +375,38 @@ void ModrinthPage::onVersionSelectionChanged(int index)
|
||||
selectedVersion = "";
|
||||
return;
|
||||
}
|
||||
selectedVersion = ui->versionSelectionBox->currentData().toString();
|
||||
selectedVersion = ui->versionSelectionBox->itemData(index).toString();
|
||||
suggestCurrent();
|
||||
}
|
||||
|
||||
void ModrinthPage::setSearchTerm(QString term)
|
||||
{
|
||||
ui->searchEdit->setText(term);
|
||||
}
|
||||
|
||||
QString ModrinthPage::getSerachTerm() const
|
||||
{
|
||||
return ui->searchEdit->text();
|
||||
}
|
||||
|
||||
void ModrinthPage::createFilterWidget()
|
||||
{
|
||||
auto widget = ModFilterWidget::create(nullptr, true, this);
|
||||
m_filterWidget.swap(widget);
|
||||
auto old = ui->splitter->replaceWidget(0, m_filterWidget.get());
|
||||
// because we replaced the widget we also need to delete it
|
||||
if (old) {
|
||||
delete old;
|
||||
}
|
||||
|
||||
connect(ui->filterButton, &QPushButton::clicked, this, [this] { m_filterWidget->setHidden(!m_filterWidget->isHidden()); });
|
||||
|
||||
connect(m_filterWidget.get(), &ModFilterWidget::filterChanged, this, &ModrinthPage::triggerSearch);
|
||||
auto response = std::make_shared<QByteArray>();
|
||||
m_categoriesTask = ModrinthAPI::getModCategories(response);
|
||||
QObject::connect(m_categoriesTask.get(), &Task::succeeded, [this, response]() {
|
||||
auto categories = ModrinthAPI::loadCategories(response, "modpack");
|
||||
m_filterWidget->setCategories(categories);
|
||||
});
|
||||
m_categoriesTask->start();
|
||||
}
|
@ -38,9 +38,10 @@
|
||||
|
||||
#include "Application.h"
|
||||
#include "ui/dialogs/NewInstanceDialog.h"
|
||||
#include "ui/pages/BasePage.h"
|
||||
|
||||
#include "modplatform/modrinth/ModrinthPackManifest.h"
|
||||
#include "ui/pages/modplatform/ModpackProviderBasePage.h"
|
||||
#include "ui/widgets/ModFilterWidget.h"
|
||||
#include "ui/widgets/ProgressWidget.h"
|
||||
|
||||
#include <QTimer>
|
||||
@ -54,7 +55,7 @@ namespace Modrinth {
|
||||
class ModpackListModel;
|
||||
}
|
||||
|
||||
class ModrinthPage : public QWidget, public BasePage {
|
||||
class ModrinthPage : public QWidget, public ModpackProviderBasePage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@ -78,10 +79,16 @@ class ModrinthPage : public QWidget, public BasePage {
|
||||
void openedImpl() override;
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
/** Programatically set the term in the search bar. */
|
||||
virtual void setSearchTerm(QString) override;
|
||||
/** Get the current term in the search bar. */
|
||||
[[nodiscard]] virtual QString getSerachTerm() const override;
|
||||
|
||||
private slots:
|
||||
void onSelectionChanged(QModelIndex first, QModelIndex second);
|
||||
void onVersionSelectionChanged(int index);
|
||||
void triggerSearch();
|
||||
void createFilterWidget();
|
||||
|
||||
private:
|
||||
Ui::ModrinthPage* ui;
|
||||
@ -95,4 +102,7 @@ class ModrinthPage : public QWidget, public BasePage {
|
||||
|
||||
// Used to do instant searching with a delay to cache quick changes
|
||||
QTimer m_search_timer;
|
||||
|
||||
unique_qobject_ptr<ModFilterWidget> m_filterWidget;
|
||||
Task::Ptr m_categoriesTask;
|
||||
};
|
||||
|
@ -12,42 +12,59 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="searchEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search and filter ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QListView" name="packView">
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
<widget class="QPushButton" name="filterButton">
|
||||
<property name="text">
|
||||
<string>Filter options</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ProjectDescriptionPage" name="packDescription">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>true</bool>
|
||||
<widget class="QLineEdit" name="searchEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search and filter...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="widget" native="true"/>
|
||||
<widget class="QListView" name="packView">
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="ProjectDescriptionPage" name="packDescription">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
|
@ -39,7 +39,7 @@ void ModrinthModModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObjec
|
||||
|
||||
void ModrinthModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
|
||||
{
|
||||
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
|
||||
::Modrinth::loadIndexedPackVersions(m, arr);
|
||||
}
|
||||
|
||||
auto ModrinthModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
|
||||
@ -66,7 +66,7 @@ void ModrinthResourcePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, Q
|
||||
|
||||
void ModrinthResourcePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
|
||||
{
|
||||
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
|
||||
::Modrinth::loadIndexedPackVersions(m, arr);
|
||||
}
|
||||
|
||||
auto ModrinthResourcePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
@ -88,7 +88,7 @@ void ModrinthTexturePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJ
|
||||
|
||||
void ModrinthTexturePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
|
||||
{
|
||||
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
|
||||
::Modrinth::loadIndexedPackVersions(m, arr);
|
||||
}
|
||||
|
||||
auto ModrinthTexturePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
@ -110,7 +110,7 @@ void ModrinthShaderPackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJs
|
||||
|
||||
void ModrinthShaderPackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
|
||||
{
|
||||
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
|
||||
::Modrinth::loadIndexedPackVersions(m, arr);
|
||||
}
|
||||
|
||||
auto ModrinthShaderPackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
@ -132,7 +132,7 @@ void ModrinthDataPackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJson
|
||||
|
||||
void ModrinthDataPackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
|
||||
{
|
||||
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
|
||||
::Modrinth::loadIndexedPackVersions(m, arr);
|
||||
}
|
||||
|
||||
auto ModrinthDataPackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
|
@ -134,7 +134,8 @@ ModrinthDataPackPage::ModrinthDataPackPage(DataPackDownloadDialog* dialog, BaseI
|
||||
// so it's best not to connect them in the parent's constructor...
|
||||
connect(m_ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch()));
|
||||
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthDataPackPage::onSelectionChanged);
|
||||
connect(m_ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthDataPackPage::onVersionSelectionChanged);
|
||||
connect(m_ui->versionSelectionBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&ModrinthDataPackPage::onVersionSelectionChanged);
|
||||
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &ModrinthDataPackPage::onResourceSelected);
|
||||
|
||||
m_ui->packDescription->setMetaEntry(metaEntryBase());
|
||||
@ -166,7 +167,7 @@ auto ModrinthDataPackPage::shouldDisplay() const -> bool
|
||||
|
||||
unique_qobject_ptr<ModFilterWidget> ModrinthModPage::createFilterWidget()
|
||||
{
|
||||
return ModFilterWidget::create(&static_cast<MinecraftInstance&>(m_base_instance), true, this);
|
||||
return ModFilterWidget::create(&static_cast<MinecraftInstance&>(m_baseInstance), true, this);
|
||||
}
|
||||
|
||||
void ModrinthModPage::prepareProviderCategories()
|
||||
|
Reference in New Issue
Block a user