Merge remote-tracking branch 'upstream/develop' into data-packs

Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
TheKodeToad 2025-03-24 21:11:46 +00:00
commit 6ab4fef0c5
No known key found for this signature in database
GPG key ID: 5E39D70B4C93C38E
686 changed files with 15261 additions and 9719 deletions

View file

@ -17,7 +17,6 @@ namespace ResourceDownload {
DataPackResourcePage::DataPackResourcePage(DataPackDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance)
{
connect(m_ui->searchButton, &QPushButton::clicked, this, &DataPackResourcePage::triggerSearch);
connect(m_ui->packView, &QListView::doubleClicked, this, &DataPackResourcePage::onResourceSelected);
}
@ -32,7 +31,7 @@ void DataPackResourcePage::triggerSearch()
updateSelectionButton();
static_cast<DataPackResourceModel*>(m_model)->searchWithTerm(getSearchTerm(), m_ui->sortByBox->currentData().toUInt());
m_fetch_progress.watch(m_model->activeSearchJob().get());
m_fetchProgress.watch(m_model->activeSearchJob().get());
}
QMap<QString, QString> DataPackResourcePage::urlHandlers() const

View file

@ -39,7 +39,9 @@ ResourceAPI::SearchArgs ModModel::createSearchArguments()
auto sort = getCurrentSortingMethodByIndex();
return { ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, loaders, versions, side, categories };
return {
ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, loaders, versions, side, categories, m_filter->openSource
};
}
ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& entry)
@ -104,18 +106,6 @@ bool checkSide(QString filter, QString value)
return filter.isEmpty() || value.isEmpty() || filter == "both" || value == "both" || filter == value;
}
bool checkMcVersions(std::list<Version> filter, QStringList value)
{
bool valid = false;
for (auto mcVersion : filter) {
if (value.contains(mcVersion.toString())) {
valid = true;
break;
}
}
return filter.empty() || valid;
}
bool ModModel::checkFilters(ModPlatform::IndexedPack::Ptr pack)
{
if (!m_filter)
@ -135,7 +125,7 @@ bool ModModel::checkVersionFilters(const ModPlatform::IndexedVersion& v)
checkSide(m_filter->side, v.side) && // side
(m_filter->releases.empty() || // releases
std::find(m_filter->releases.cbegin(), m_filter->releases.cend(), v.version_type) != m_filter->releases.cend()) &&
checkMcVersions(m_filter->versions, v.mcVersion)); // mcVersions
m_filter->checkMcVersions(v.mcVersion)); // mcVersions
}
} // namespace ResourceDownload

View file

@ -99,7 +99,7 @@ void ModPage::triggerSearch()
updateSelectionButton();
static_cast<ModModel*>(m_model)->searchWithTerm(getSearchTerm(), m_ui->sortByBox->currentData().toUInt(), changed);
m_fetch_progress.watch(m_model->activeSearchJob().get());
m_fetchProgress.watch(m_model->activeSearchJob().get());
}
QMap<QString, QString> ModPage::urlHandlers() const

View file

@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "ui/pages/BasePage.h"
class ModpackProviderBasePage : public BasePage {
public:
/** Programatically set the term in the search bar. */
virtual void setSearchTerm(QString) = 0;
/** Get the current term in the search bar. */
[[nodiscard]] virtual QString getSerachTerm() const = 0;
};

View file

@ -43,6 +43,9 @@ OptionalModDialog::OptionalModDialog(QWidget* parent, const QStringList& mods) :
else
item->setCheckState(Qt::Checked);
});
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
}
OptionalModDialog::~OptionalModDialog()

View file

@ -31,9 +31,9 @@ QHash<ResourceModel*, bool> ResourceModel::s_running_models;
ResourceModel::ResourceModel(ResourceAPI* api) : QAbstractListModel(), m_api(api)
{
s_running_models.insert(this, true);
#ifndef LAUNCHER_TEST
m_current_info_job.setMaxConcurrent(APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
#endif
if (APPLICATION_DYN) {
m_current_info_job.setMaxConcurrent(APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
}
}
ResourceModel::~ResourceModel()
@ -60,11 +60,15 @@ auto ResourceModel::data(const QModelIndex& index, int role) const -> QVariant
return pack->description;
}
case Qt::DecorationRole: {
if (auto icon_or_none = const_cast<ResourceModel*>(this)->getIcon(const_cast<QModelIndex&>(index), pack->logoUrl);
icon_or_none.has_value())
return icon_or_none.value();
if (APPLICATION_DYN) {
if (auto icon_or_none = const_cast<ResourceModel*>(this)->getIcon(const_cast<QModelIndex&>(index), pack->logoUrl);
icon_or_none.has_value())
return icon_or_none.value();
return APPLICATION->getThemedIcon("screenshot-placeholder");
return APPLICATION->getThemedIcon("screenshot-placeholder");
} else {
return {};
}
}
case Qt::SizeHintRole:
return QSize(0, 58);
@ -333,7 +337,7 @@ std::optional<QIcon> ResourceModel::getIcon(QModelIndex& index, const QUrl& url)
auto icon_fetch_action = Net::ApiDownload::makeCached(url, cache_entry);
auto full_file_path = cache_entry->getFullPath();
connect(icon_fetch_action.get(), &Task::succeeded, this, [=] {
connect(icon_fetch_action.get(), &Task::succeeded, this, [this, url, full_file_path, index] {
auto icon = QIcon(full_file_path);
QPixmapCache::insert(url.toString(), icon.pixmap(icon.actualSize({ 64, 64 })));
@ -341,7 +345,7 @@ std::optional<QIcon> ResourceModel::getIcon(QModelIndex& index, const QUrl& url)
emit dataChanged(index, index, { Qt::DecorationRole });
});
connect(icon_fetch_action.get(), &Task::failed, this, [=] {
connect(icon_fetch_action.get(), &Task::failed, this, [this, url] {
m_currently_running_icon_actions.remove(url);
m_failed_icon_actions.insert(url);
});

View file

@ -30,7 +30,7 @@ void ResourcePackResourcePage::triggerSearch()
updateSelectionButton();
static_cast<ResourcePackResourceModel*>(m_model)->searchWithTerm(getSearchTerm(), m_ui->sortByBox->currentData().toUInt());
m_fetch_progress.watch(m_model->activeSearchJob().get());
m_fetchProgress.watch(m_model->activeSearchJob().get());
}
QMap<QString, QString> ResourcePackResourcePage::urlHandlers() const

View file

@ -39,14 +39,16 @@
#include "ResourcePage.h"
#include "modplatform/ModIndex.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui_ResourcePage.h"
#include <StringUtils.h>
#include <QDesktopServices>
#include <QKeyEvent>
#include "Markdown.h"
#include "StringUtils.h"
#include "Application.h"
#include "ui/dialogs/ResourceDownloadDialog.h"
#include "ui/pages/modplatform/ResourceModel.h"
#include "ui/widgets/ProjectItem.h"
@ -54,7 +56,7 @@
namespace ResourceDownload {
ResourcePage::ResourcePage(ResourceDownloadDialog* parent, BaseInstance& base_instance)
: QWidget(parent), m_base_instance(base_instance), m_ui(new Ui::ResourcePage), m_parent_dialog(parent), m_fetch_progress(this, false)
: QWidget(parent), m_baseInstance(base_instance), m_ui(new Ui::ResourcePage), m_parentDialog(parent), m_fetchProgress(this, false)
{
m_ui->setupUi(this);
@ -63,18 +65,18 @@ ResourcePage::ResourcePage(ResourceDownloadDialog* parent, BaseInstance& base_in
m_ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300);
m_search_timer.setTimerType(Qt::TimerType::CoarseTimer);
m_search_timer.setSingleShot(true);
m_searchTimer.setTimerType(Qt::TimerType::CoarseTimer);
m_searchTimer.setSingleShot(true);
connect(&m_search_timer, &QTimer::timeout, this, &ResourcePage::triggerSearch);
connect(&m_searchTimer, &QTimer::timeout, this, &ResourcePage::triggerSearch);
// hide progress bar to prevent weird artifact
m_fetch_progress.hide();
m_fetch_progress.hideIfInactive(true);
m_fetch_progress.setFixedHeight(24);
m_fetch_progress.progressFormat("");
m_fetchProgress.hide();
m_fetchProgress.hideIfInactive(true);
m_fetchProgress.setFixedHeight(24);
m_fetchProgress.progressFormat("");
m_ui->verticalLayout->insertWidget(1, &m_fetch_progress);
m_ui->verticalLayout->insertWidget(1, &m_fetchProgress);
m_ui->packView->setItemDelegate(new ProjectItemDelegate(this));
m_ui->packView->installEventFilter(this);
@ -120,10 +122,10 @@ auto ResourcePage::eventFilter(QObject* watched, QEvent* event) -> bool
keyEvent->accept();
return true;
} else {
if (m_search_timer.isActive())
m_search_timer.stop();
if (m_searchTimer.isActive())
m_searchTimer.stop();
m_search_timer.start(350);
m_searchTimer.start(350);
}
} else if (watched == m_ui->packView) {
if (keyEvent->key() == Qt::Key_Return) {
@ -247,14 +249,17 @@ void ResourcePage::updateUi()
void ResourcePage::updateSelectionButton()
{
if (!isOpened || m_selected_version_index < 0) {
if (!isOpened || m_selectedVersionIndex < 0) {
m_ui->resourceSelectionButton->setEnabled(false);
return;
}
m_ui->resourceSelectionButton->setEnabled(true);
if (auto current_pack = getCurrentPack(); current_pack) {
if (!current_pack->isVersionSelected(m_selected_version_index))
if (current_pack->versionsLoaded && current_pack->versions.empty()) {
m_ui->resourceSelectionButton->setEnabled(false);
qWarning() << tr("No version available for the selected pack");
} else if (!current_pack->isVersionSelected(m_selectedVersionIndex))
m_ui->resourceSelectionButton->setText(tr("Select %1 for download").arg(resourceString()));
else
m_ui->resourceSelectionButton->setText(tr("Deselect %1 for download").arg(resourceString()));
@ -279,11 +284,15 @@ void ResourcePage::updateVersionList()
if (!m_model->checkVersionFilters(version))
continue;
auto release_type = current_pack->versions[i].version_type.isValid()
? QString(" [%1]").arg(current_pack->versions[i].version_type.toString())
: "";
auto versionText = version.version;
if (version.version_type.isValid()) {
versionText += QString(" [%1]").arg(version.version_type.toString());
}
if (version.fileId == installedVersion) {
versionText += tr(" [installed]", "Mod version select");
}
m_ui->versionSelectionBox->addItem(QString("%1%2").arg(version.version, release_type), QVariant(i));
m_ui->versionSelectionBox->addItem(versionText, QVariant(i));
}
}
if (m_ui->versionSelectionBox->count() == 0) {
@ -323,25 +332,26 @@ void ResourcePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
void ResourcePage::onVersionSelectionChanged(int index)
{
m_selected_version_index = index;
m_selectedVersionIndex = m_ui->versionSelectionBox->itemData(index).toInt();
updateSelectionButton();
}
void ResourcePage::addResourceToDialog(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& version)
{
m_parent_dialog->addResource(pack, version);
m_parentDialog->addResource(pack, version);
}
void ResourcePage::removeResourceFromDialog(const QString& pack_name)
{
m_parent_dialog->removeResource(pack_name);
m_parentDialog->removeResource(pack_name);
}
void ResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
ModPlatform::IndexedVersion& ver,
const std::shared_ptr<ResourceFolderModel> base_model)
{
m_model->addPack(pack, ver, base_model);
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
m_model->addPack(pack, ver, base_model, is_indexed);
}
void ResourcePage::removeResourceFromPage(const QString& name)
@ -351,14 +361,15 @@ void ResourcePage::removeResourceFromPage(const QString& name)
void ResourcePage::onResourceSelected()
{
if (m_selected_version_index < 0)
if (m_selectedVersionIndex < 0)
return;
auto current_pack = getCurrentPack();
if (!current_pack || !current_pack->versionsLoaded)
if (!current_pack || !current_pack->versionsLoaded || current_pack->versions.size() < m_selectedVersionIndex)
return;
auto& version = current_pack->versions[m_selected_version_index];
auto& version = current_pack->versions[m_selectedVersionIndex];
Q_ASSERT(!version.downloadUrl.isNull());
if (version.is_currently_selected)
removeResourceFromDialog(current_pack->name);
else
@ -397,14 +408,14 @@ void ResourcePage::openUrl(const QUrl& url)
}
}
if (!page.isNull() && !m_do_not_jump_to_mod) {
if (!page.isNull() && !m_doNotJumpToMod) {
const QString slug = match.captured(1);
// ensure the user isn't opening the same mod
if (auto current_pack = getCurrentPack(); current_pack && slug != current_pack->slug) {
m_parent_dialog->selectPage(page);
m_parentDialog->selectPage(page);
auto newPage = m_parent_dialog->selectedPage();
auto newPage = m_parentDialog->selectedPage();
QLineEdit* searchEdit = newPage->m_ui->searchEdit;
auto model = newPage->m_model;
@ -448,7 +459,7 @@ void ResourcePage::openProject(QVariant projectID)
m_ui->resourceFilterButton->hide();
m_ui->packView->hide();
m_ui->resourceSelectionButton->hide();
m_do_not_jump_to_mod = true;
m_doNotJumpToMod = true;
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
@ -462,20 +473,23 @@ void ResourcePage::openProject(QVariant projectID)
auto cancelBtn = buttonBox->button(QDialogButtonBox::Cancel);
cancelBtn->setDefault(false);
cancelBtn->setAutoDefault(false);
cancelBtn->setText(tr("Cancel"));
connect(okBtn, &QPushButton::clicked, this, [this] {
onResourceSelected();
m_parent_dialog->accept();
m_parentDialog->accept();
});
connect(cancelBtn, &QPushButton::clicked, m_parent_dialog, &ResourceDownloadDialog::reject);
connect(cancelBtn, &QPushButton::clicked, m_parentDialog, &ResourceDownloadDialog::reject);
m_ui->gridLayout_4->addWidget(buttonBox, 1, 2);
auto jump = [this, okBtn] {
connect(m_ui->versionSelectionBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
[this, okBtn](int index) { okBtn->setEnabled(m_ui->versionSelectionBox->itemData(index).toInt() >= 0); });
auto jump = [this] {
for (int row = 0; row < m_model->rowCount({}); row++) {
const QModelIndex index = m_model->index(row);
m_ui->packView->setCurrentIndex(index);
okBtn->setEnabled(true);
return;
}
m_ui->packDescription->setText(tr("The resource was not found"));

View file

@ -62,7 +62,7 @@ class ResourcePage : public QWidget, public BasePage {
[[nodiscard]] bool setCurrentPack(ModPlatform::IndexedPack::Ptr);
[[nodiscard]] auto getCurrentPack() const -> ModPlatform::IndexedPack::Ptr;
[[nodiscard]] auto getDialog() const -> const ResourceDownloadDialog* { return m_parent_dialog; }
[[nodiscard]] auto getDialog() const -> const ResourceDownloadDialog* { return m_parentDialog; }
[[nodiscard]] auto getModel() const -> ResourceModel* { return m_model; }
protected:
@ -99,22 +99,22 @@ class ResourcePage : public QWidget, public BasePage {
virtual void openUrl(const QUrl&);
public:
BaseInstance& m_base_instance;
BaseInstance& m_baseInstance;
protected:
Ui::ResourcePage* m_ui;
ResourceDownloadDialog* m_parent_dialog = nullptr;
ResourceDownloadDialog* m_parentDialog = nullptr;
ResourceModel* m_model = nullptr;
int m_selected_version_index = -1;
int m_selectedVersionIndex = -1;
ProgressWidget m_fetch_progress;
ProgressWidget m_fetchProgress;
// Used to do instant searching with a delay to cache quick changes
QTimer m_search_timer;
QTimer m_searchTimer;
bool m_do_not_jump_to_mod = false;
bool m_doNotJumpToMod = false;
};
} // namespace ResourceDownload

View file

@ -8,6 +8,7 @@
#include "ShaderPackModel.h"
#include "Application.h"
#include "ui/dialogs/ResourceDownloadDialog.h"
#include <QRegularExpression>
@ -31,7 +32,7 @@ void ShaderPackResourcePage::triggerSearch()
updateSelectionButton();
static_cast<ShaderPackResourceModel*>(m_model)->searchWithTerm(getSearchTerm(), m_ui->sortByBox->currentData().toUInt());
m_fetch_progress.watch(m_model->activeSearchJob().get());
m_fetchProgress.watch(m_model->activeSearchJob().get());
}
QMap<QString, QString> ShaderPackResourcePage::urlHandlers() const
@ -48,10 +49,11 @@ void ShaderPackResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pac
ModPlatform::IndexedVersion& version,
const std::shared_ptr<ResourceFolderModel> base_model)
{
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
QString custom_target_folder;
if (version.loaders & ModPlatform::Cauldron)
custom_target_folder = QStringLiteral("resourcepacks");
m_model->addPack(pack, version, base_model, false, custom_target_folder);
m_model->addPack(pack, version, base_model, is_indexed, custom_target_folder);
}
} // namespace ResourceDownload

View file

@ -164,3 +164,13 @@ void AtlPage::onVersionSelectionChanged(QString version)
selectedVersion = version;
suggestCurrent();
}
void AtlPage::setSearchTerm(QString term)
{
ui->searchEdit->setText(term);
}
QString AtlPage::getSerachTerm() const
{
return ui->searchEdit->text();
}

View file

@ -42,8 +42,7 @@
#include <QWidget>
#include "Application.h"
#include "tasks/Task.h"
#include "ui/pages/BasePage.h"
#include "ui/pages/modplatform/ModpackProviderBasePage.h"
namespace Ui {
class AtlPage;
@ -51,7 +50,7 @@ class AtlPage;
class NewInstanceDialog;
class AtlPage : public QWidget, public BasePage {
class AtlPage : public QWidget, public ModpackProviderBasePage {
Q_OBJECT
public:
@ -66,6 +65,11 @@ class AtlPage : public QWidget, public BasePage {
void openedImpl() 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:
void suggestCurrent();

View file

@ -1,6 +1,7 @@
#include "FlameModel.h"
#include <Json.h>
#include "Application.h"
#include "modplatform/ModIndex.h"
#include "modplatform/ResourceAPI.h"
#include "modplatform/flame/FlameAPI.h"
#include "ui/widgets/ProjectItem.h"
@ -183,34 +184,28 @@ void ListModel::performPaginatedSearch()
return;
}
}
auto netJob = makeShared<NetJob>("Flame::Search", APPLICATION->network());
auto searchUrl = QString(
"https://api.curseforge.com/v1/mods/search?"
"gameId=432&"
"classId=4471&"
"index=%1&"
"pageSize=25&"
"searchFilter=%2&"
"sortField=%3&"
"sortOrder=desc")
.arg(nextSearchOffset)
.arg(currentSearchTerm)
.arg(currentSort + 1);
ResourceAPI::SortingMethod sort{};
sort.index = currentSort + 1;
netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchUrl), response));
auto netJob = makeShared<NetJob>("Flame::Search", APPLICATION->network());
auto searchUrl = FlameAPI().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(searchUrl.value()), response));
jobPtr = netJob;
jobPtr->start();
QObject::connect(netJob.get(), &NetJob::succeeded, this, &ListModel::searchRequestFinished);
QObject::connect(netJob.get(), &NetJob::failed, this, &ListModel::searchRequestFailed);
}
void ListModel::searchWithTerm(const QString& term, int sort)
void ListModel::searchWithTerm(const QString& term, int sort, std::shared_ptr<ModFilterWidget::Filter> filter, bool filterChanged)
{
if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) {
if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort && !filterChanged) {
return;
}
currentSearchTerm = term;
currentSort = sort;
m_filter = filter;
if (hasActiveSearchJob()) {
jobPtr->abort();
searchState = ResetRequested;

View file

@ -14,6 +14,7 @@
#include <net/NetJob.h>
#include <functional>
#include "ui/widgets/ModFilterWidget.h"
#include <modplatform/flame/FlamePackIndex.h>
@ -38,7 +39,7 @@ class ListModel : public QAbstractListModel {
void fetchMore(const QModelIndex& parent) override;
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
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; }
@ -65,6 +66,7 @@ class ListModel : public QAbstractListModel {
QString currentSearchTerm;
int currentSort = 0;
std::shared_ptr<ModFilterWidget::Filter> m_filter;
int nextSearchOffset = 0;
enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None;
Task::Ptr jobPtr;

View file

@ -34,10 +34,14 @@
*/
#include "FlamePage.h"
#include "Version.h"
#include "modplatform/flame/FlamePackIndex.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/widgets/ModFilterWidget.h"
#include "ui_FlamePage.h"
#include <QKeyEvent>
#include <memory>
#include "Application.h"
#include "FlameModel.h"
@ -88,6 +92,7 @@ FlamePage::FlamePage(NewInstanceDialog* dialog, QWidget* parent)
ui->packView->setItemDelegate(new ProjectItemDelegate(this));
ui->packDescription->setMetaEntry("FlamePacks");
createFilterWidget();
}
FlamePage::~FlamePage()
@ -131,10 +136,25 @@ void FlamePage::openedImpl()
void FlamePage::triggerSearch()
{
listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex());
ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect);
ui->packView->clearSelection();
ui->packDescription->clear();
ui->versionSelectionBox->clear();
listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex(), m_filterWidget->getFilter(),
m_filterWidget->changed());
m_fetch_progress.watch(listModel->activeSearchJob().get());
}
bool checkVersionFilters(const Flame::IndexedVersion& 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.mcVersion })); // mcVersions}
}
void FlamePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelIndex prev)
{
ui->versionSelectionBox->clear();
@ -148,7 +168,7 @@ void FlamePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelInde
current = listModel->data(curr, Qt::UserRole).value<Flame::IndexedPack>();
if (current.versionsLoaded == false) {
if (!current.versionsLoaded || m_filterWidget->changed()) {
qDebug() << "Loading flame modpack versions";
auto netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(current.name), APPLICATION->network());
auto response = std::make_shared<QByteArray>();
@ -176,6 +196,16 @@ void FlamePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelInde
qWarning() << "Error while reading flame modpack version: " << e.cause();
}
auto pred = [this](const Flame::IndexedVersion& 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.mcVersion.isEmpty() && !version.version.contains(version.mcVersion)
@ -243,7 +273,7 @@ void FlamePage::suggestCurrent()
void FlamePage::onVersionSelectionChanged(int index)
{
bool is_blocked = false;
ui->versionSelectionBox->currentData().toInt(&is_blocked);
ui->versionSelectionBox->itemData(index).toInt(&is_blocked);
if (index == -1 || is_blocked) {
m_selected_version_index = -1;
@ -299,3 +329,34 @@ void FlamePage::updateUi()
ui->packDescription->setHtml(StringUtils::htmlListPatch(text + current.description));
ui->packDescription->flush();
}
QString FlamePage::getSerachTerm() const
{
return ui->searchEdit->text();
}
void FlamePage::setSearchTerm(QString term)
{
ui->searchEdit->setText(term);
}
void FlamePage::createFilterWidget()
{
auto widget = ModFilterWidget::create(nullptr, false, 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, &FlamePage::triggerSearch);
auto response = std::make_shared<QByteArray>();
m_categoriesTask = FlameAPI::getCategories(response, ModPlatform::ResourceType::MODPACK);
QObject::connect(m_categoriesTask.get(), &Task::succeeded, [this, response]() {
auto categories = FlameAPI::loadModCategories(response);
m_filterWidget->setCategories(categories);
});
m_categoriesTask->start();
}

View file

@ -40,7 +40,8 @@
#include <Application.h>
#include <modplatform/flame/FlamePackIndex.h>
#include <QTimer>
#include "ui/pages/BasePage.h"
#include "ui/pages/modplatform/ModpackProviderBasePage.h"
#include "ui/widgets/ModFilterWidget.h"
#include "ui/widgets/ProgressWidget.h"
namespace Ui {
@ -53,7 +54,7 @@ namespace Flame {
class ListModel;
}
class FlamePage : public QWidget, public BasePage {
class FlamePage : public QWidget, public ModpackProviderBasePage {
Q_OBJECT
public:
@ -72,6 +73,11 @@ class FlamePage : public QWidget, public BasePage {
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:
void suggestCurrent();
@ -79,6 +85,7 @@ class FlamePage : public QWidget, public BasePage {
void triggerSearch();
void onSelectionChanged(QModelIndex first, QModelIndex second);
void onVersionSelectionChanged(int index);
void createFilterWidget();
private:
Ui::FlamePage* ui = nullptr;
@ -92,4 +99,7 @@ class FlamePage : 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;
};

View file

@ -30,42 +30,59 @@
</widget>
</item>
<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>

View file

@ -32,7 +32,7 @@ void FlameModModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject&
void FlameModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
FlameMod::loadIndexedPackVersions(m, arr);
}
auto FlameModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
@ -65,7 +65,7 @@ void FlameResourcePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJso
void FlameResourcePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
FlameMod::loadIndexedPackVersions(m, arr);
}
bool FlameResourcePackModel::optedOut(const ModPlatform::IndexedVersion& ver) const
@ -93,7 +93,7 @@ void FlameTexturePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJson
void FlameTexturePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
FlameMod::loadIndexedPackVersions(m, arr);
QVector<ModPlatform::IndexedVersion> filtered_versions(m.versions.size());
@ -157,7 +157,7 @@ void FlameShaderPackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonO
void FlameShaderPackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
FlameMod::loadIndexedPackVersions(m, arr);
}
bool FlameShaderPackModel::optedOut(const ModPlatform::IndexedVersion& ver) const

View file

@ -209,17 +209,17 @@ auto FlameShaderPackPage::shouldDisplay() const -> bool
unique_qobject_ptr<ModFilterWidget> FlameModPage::createFilterWidget()
{
return ModFilterWidget::create(&static_cast<MinecraftInstance&>(m_base_instance), false, this);
return ModFilterWidget::create(&static_cast<MinecraftInstance&>(m_baseInstance), false, this);
}
void FlameModPage::prepareProviderCategories()
{
auto response = std::make_shared<QByteArray>();
auto task = FlameAPI::getModCategories(response);
QObject::connect(task.get(), &Task::succeeded, [this, response]() {
m_categoriesTask = FlameAPI::getModCategories(response);
QObject::connect(m_categoriesTask.get(), &Task::succeeded, [this, response]() {
auto categories = FlameAPI::loadModCategories(response);
m_filter_widget->setCategories(categories);
});
task->start();
m_categoriesTask->start();
};
} // namespace ResourceDownload

View file

@ -100,6 +100,9 @@ class FlameModPage : public ModPage {
protected:
virtual void prepareProviderCategories() override;
private:
Task::Ptr m_categoriesTask;
};
class FlameResourcePackPage : public ResourcePackResourcePage {

View file

@ -135,4 +135,13 @@ void ImportFTBPage::triggerSearch()
currentModel->setSearchTerm(ui->searchEdit->text());
}
void ImportFTBPage::setSearchTerm(QString term)
{
ui->searchEdit->setText(term);
}
QString ImportFTBPage::getSerachTerm() const
{
return ui->searchEdit->text();
}
} // namespace FTBImportAPP

View file

@ -25,7 +25,7 @@
#include <Application.h>
#include "modplatform/import_ftb/PackHelpers.h"
#include "ui/pages/BasePage.h"
#include "ui/pages/modplatform/ModpackProviderBasePage.h"
#include "ui/pages/modplatform/import_ftb/ListModel.h"
class NewInstanceDialog;
@ -35,7 +35,7 @@ namespace Ui {
class ImportFTBPage;
}
class ImportFTBPage : public QWidget, public BasePage {
class ImportFTBPage : public QWidget, public ModpackProviderBasePage {
Q_OBJECT
public:
@ -49,6 +49,11 @@ class ImportFTBPage : public QWidget, public BasePage {
void openedImpl() override;
void retranslate() 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:
void suggestCurrent();
void onPackSelectionChanged(Modpack* pack = nullptr);

View file

@ -13,6 +13,11 @@
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Note: If your FTB instances are not in the default location, select it using the button next to search.</string>
</property>

View file

@ -369,4 +369,13 @@ void Page::triggerSearch()
currentModel->setSearchTerm(ui->searchEdit->text());
}
void Page::setSearchTerm(QString term)
{
ui->searchEdit->setText(term);
}
QString Page::getSerachTerm() const
{
return ui->searchEdit->text();
}
} // namespace LegacyFTB

View file

@ -43,7 +43,7 @@
#include "QObjectPtr.h"
#include "modplatform/legacy_ftb/PackFetchTask.h"
#include "modplatform/legacy_ftb/PackHelpers.h"
#include "ui/pages/BasePage.h"
#include "ui/pages/modplatform/ModpackProviderBasePage.h"
class NewInstanceDialog;
@ -57,7 +57,7 @@ class ListModel;
class FilterModel;
class PrivatePackManager;
class Page : public QWidget, public BasePage {
class Page : public QWidget, public ModpackProviderBasePage {
Q_OBJECT
public:
@ -71,6 +71,11 @@ class Page : public QWidget, public BasePage {
void openedImpl() override;
void retranslate() 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:
void suggestCurrent();
void onPackSelectionChanged(Modpack* pack = nullptr);

View file

@ -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();
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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;
};

View file

@ -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>

View file

@ -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

View file

@ -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()

View file

@ -154,6 +154,10 @@ void Technic::ListModel::performSearch()
QString("%1search?build=%2&q=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD, currentSearchTerm);
searchMode = List;
}
auto clientId = APPLICATION->settings()->get("TechnicClientID").toString();
if (!clientId.isEmpty()) {
searchUrl += "?cid=" + clientId;
}
netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchUrl), response));
jobPtr = netJob;
jobPtr->start();

View file

@ -342,3 +342,13 @@ void TechnicPage::onVersionSelectionChanged(QString version)
selectedVersion = version;
selectVersion();
}
void TechnicPage::setSearchTerm(QString term)
{
ui->searchEdit->setText(term);
}
QString TechnicPage::getSerachTerm() const
{
return ui->searchEdit->text();
}

View file

@ -41,7 +41,7 @@
#include <Application.h>
#include "TechnicData.h"
#include "net/NetJob.h"
#include "ui/pages/BasePage.h"
#include "ui/pages/modplatform/ModpackProviderBasePage.h"
#include "ui/widgets/ProgressWidget.h"
namespace Ui {
@ -54,7 +54,7 @@ namespace Technic {
class ListModel;
}
class TechnicPage : public QWidget, public BasePage {
class TechnicPage : public QWidget, public ModpackProviderBasePage {
Q_OBJECT
public:
@ -71,6 +71,11 @@ class TechnicPage : public QWidget, public BasePage {
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:
void suggestCurrent();
void metadataLoaded();