mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-06-12 21:27:44 +02:00
Merge remote-tracking branch 'upstream/develop' into resource-meta
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
@ -51,7 +51,6 @@
|
||||
#include <icons/IconList.h>
|
||||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
#include <QSaveFile>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStack>
|
||||
#include <functional>
|
||||
|
@ -78,7 +78,7 @@ int MSALoginDialog::exec()
|
||||
connect(m_authflow_task.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed);
|
||||
connect(m_authflow_task.get(), &Task::succeeded, this, &QDialog::accept);
|
||||
connect(m_authflow_task.get(), &Task::aborted, this, &MSALoginDialog::reject);
|
||||
connect(m_authflow_task.get(), &Task::status, this, &MSALoginDialog::onTaskStatus);
|
||||
connect(m_authflow_task.get(), &Task::status, this, &MSALoginDialog::onAuthFlowStatus);
|
||||
connect(m_authflow_task.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser);
|
||||
connect(m_authflow_task.get(), &AuthFlow::authorizeWithBrowserWithExtra, this, &MSALoginDialog::authorizeWithBrowserWithExtra);
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, m_authflow_task.get(), &Task::abort);
|
||||
@ -87,7 +87,7 @@ int MSALoginDialog::exec()
|
||||
connect(m_devicecode_task.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed);
|
||||
connect(m_devicecode_task.get(), &Task::succeeded, this, &QDialog::accept);
|
||||
connect(m_devicecode_task.get(), &Task::aborted, this, &MSALoginDialog::reject);
|
||||
connect(m_devicecode_task.get(), &Task::status, this, &MSALoginDialog::onTaskStatus);
|
||||
connect(m_devicecode_task.get(), &Task::status, this, &MSALoginDialog::onDeviceFlowStatus);
|
||||
connect(m_devicecode_task.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser);
|
||||
connect(m_devicecode_task.get(), &AuthFlow::authorizeWithBrowserWithExtra, this, &MSALoginDialog::authorizeWithBrowserWithExtra);
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, m_devicecode_task.get(), &Task::abort);
|
||||
@ -132,7 +132,7 @@ void MSALoginDialog::onTaskFailed(QString reason)
|
||||
|
||||
void MSALoginDialog::authorizeWithBrowser(const QUrl& url)
|
||||
{
|
||||
ui->stackedWidget->setCurrentIndex(1);
|
||||
ui->stackedWidget2->setCurrentIndex(1);
|
||||
ui->loginButton->setToolTip(QString("<div style='width: 200px;'>%1</div>").arg(url.toString()));
|
||||
m_url = url;
|
||||
}
|
||||
@ -152,12 +152,18 @@ void MSALoginDialog::authorizeWithBrowserWithExtra(QString url, QString code, in
|
||||
}
|
||||
}
|
||||
|
||||
void MSALoginDialog::onTaskStatus(QString status)
|
||||
void MSALoginDialog::onDeviceFlowStatus(QString status)
|
||||
{
|
||||
ui->stackedWidget->setCurrentIndex(0);
|
||||
ui->status->setText(status);
|
||||
}
|
||||
|
||||
void MSALoginDialog::onAuthFlowStatus(QString status)
|
||||
{
|
||||
ui->stackedWidget2->setCurrentIndex(0);
|
||||
ui->status2->setText(status);
|
||||
}
|
||||
|
||||
// Public interface
|
||||
MinecraftAccountPtr MSALoginDialog::newAccount(QWidget* parent)
|
||||
{
|
||||
|
@ -40,7 +40,8 @@ class MSALoginDialog : public QDialog {
|
||||
|
||||
protected slots:
|
||||
void onTaskFailed(QString reason);
|
||||
void onTaskStatus(QString status);
|
||||
void onDeviceFlowStatus(QString status);
|
||||
void onAuthFlowStatus(QString status);
|
||||
void authorizeWithBrowser(const QUrl& url);
|
||||
void authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>440</width>
|
||||
<height>430</height>
|
||||
<height>447</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
@ -20,6 +20,171 @@
|
||||
<string>Add Microsoft Account</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget2">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="loadingPage2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_31">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="loadingLabel2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Please wait...</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="status2">
|
||||
<property name="text">
|
||||
<string>Status</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_31">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="mpPage1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_21" stretch="0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="loginButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sign in with Microsoft</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="orLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Or</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="currentIndex">
|
||||
@ -28,7 +193,7 @@
|
||||
<widget class="QWidget" name="loadingPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<spacer name="verticalSpacer_41">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
@ -89,98 +254,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="mpPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0,0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="loginButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sign in with Microsoft</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="orLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Or</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
|
@ -90,6 +90,9 @@ void ProgressDialog::on_skipButton_clicked(bool checked)
|
||||
|
||||
ProgressDialog::~ProgressDialog()
|
||||
{
|
||||
for (auto conn : this->m_taskConnections) {
|
||||
disconnect(conn);
|
||||
}
|
||||
delete ui;
|
||||
}
|
||||
|
||||
@ -140,15 +143,15 @@ int ProgressDialog::execWithTask(Task* task)
|
||||
}
|
||||
|
||||
// Connect signals.
|
||||
connect(task, &Task::started, this, &ProgressDialog::onTaskStarted);
|
||||
connect(task, &Task::failed, this, &ProgressDialog::onTaskFailed);
|
||||
connect(task, &Task::succeeded, this, &ProgressDialog::onTaskSucceeded);
|
||||
connect(task, &Task::status, this, &ProgressDialog::changeStatus);
|
||||
connect(task, &Task::details, this, &ProgressDialog::changeStatus);
|
||||
connect(task, &Task::stepProgress, this, &ProgressDialog::changeStepProgress);
|
||||
connect(task, &Task::progress, this, &ProgressDialog::changeProgress);
|
||||
connect(task, &Task::aborted, this, &ProgressDialog::hide);
|
||||
connect(task, &Task::abortStatusChanged, ui->skipButton, &QPushButton::setEnabled);
|
||||
this->m_taskConnections.push_back(connect(task, &Task::started, this, &ProgressDialog::onTaskStarted));
|
||||
this->m_taskConnections.push_back(connect(task, &Task::failed, this, &ProgressDialog::onTaskFailed));
|
||||
this->m_taskConnections.push_back(connect(task, &Task::succeeded, this, &ProgressDialog::onTaskSucceeded));
|
||||
this->m_taskConnections.push_back(connect(task, &Task::status, this, &ProgressDialog::changeStatus));
|
||||
this->m_taskConnections.push_back(connect(task, &Task::details, this, &ProgressDialog::changeStatus));
|
||||
this->m_taskConnections.push_back(connect(task, &Task::stepProgress, this, &ProgressDialog::changeStepProgress));
|
||||
this->m_taskConnections.push_back(connect(task, &Task::progress, this, &ProgressDialog::changeProgress));
|
||||
this->m_taskConnections.push_back(connect(task, &Task::aborted, this, &ProgressDialog::hide));
|
||||
this->m_taskConnections.push_back(connect(task, &Task::abortStatusChanged, ui->skipButton, &QPushButton::setEnabled));
|
||||
|
||||
m_is_multi_step = task->isMultiStep();
|
||||
ui->taskProgressScrollArea->setHidden(!m_is_multi_step);
|
||||
|
@ -93,6 +93,8 @@ class ProgressDialog : public QDialog {
|
||||
Ui::ProgressDialog* ui;
|
||||
|
||||
Task* m_task;
|
||||
|
||||
QList<QMetaObject::Connection> m_taskConnections;
|
||||
|
||||
bool m_is_multi_step = false;
|
||||
QHash<QUuid, SubTaskProgressBar*> taskProgress;
|
||||
|
@ -139,6 +139,9 @@ void SkinManageDialog::on_fileBtn_clicked()
|
||||
{
|
||||
auto filter = QMimeDatabase().mimeTypeForName("image/png").filterString();
|
||||
QString raw_path = QFileDialog::getOpenFileName(this, tr("Select Skin Texture"), QString(), filter);
|
||||
if (raw_path.isNull()) {
|
||||
return;
|
||||
}
|
||||
auto message = m_list.installSkin(raw_path, {});
|
||||
if (!message.isEmpty()) {
|
||||
CustomMessageBox::selectable(this, tr("Selected file is not a valid skin"), message, QMessageBox::Critical)->show();
|
||||
|
@ -104,18 +104,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 +123,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
|
||||
|
@ -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);
|
||||
|
@ -255,7 +255,10 @@ void ResourcePage::updateSelectionButton()
|
||||
|
||||
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_selected_version_index))
|
||||
m_ui->resourceSelectionButton->setText(tr("Select %1 for download").arg(resourceString()));
|
||||
else
|
||||
m_ui->resourceSelectionButton->setText(tr("Deselect %1 for download").arg(resourceString()));
|
||||
|
@ -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 });
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
@ -308,3 +338,25 @@ 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();
|
||||
}
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <modplatform/flame/FlamePackIndex.h>
|
||||
#include <QTimer>
|
||||
#include "ui/pages/modplatform/ModpackProviderBasePage.h"
|
||||
#include "ui/widgets/ModFilterWidget.h"
|
||||
#include "ui/widgets/ProgressWidget.h"
|
||||
|
||||
namespace Ui {
|
||||
@ -84,6 +85,7 @@ class FlamePage : public QWidget, public ModpackProviderBasePage {
|
||||
void triggerSearch();
|
||||
void onSelectionChanged(QModelIndex first, QModelIndex second);
|
||||
void onVersionSelectionChanged(int index);
|
||||
void createFilterWidget();
|
||||
|
||||
private:
|
||||
Ui::FlamePage* ui = nullptr;
|
||||
@ -97,4 +99,7 @@ class FlamePage : public QWidget, public ModpackProviderBasePage {
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
@ -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="QLineEdit" name="searchEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search and filter...</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="QPushButton" name="filterButton">
|
||||
<property name="text">
|
||||
<string>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>
|
||||
|
@ -215,11 +215,11 @@ unique_qobject_ptr<ModFilterWidget> FlameModPage::createFilterWidget()
|
||||
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
|
||||
|
@ -100,6 +100,9 @@ class FlameModPage : public ModPage {
|
||||
|
||||
protected:
|
||||
virtual void prepareProviderCategories() override;
|
||||
|
||||
private:
|
||||
Task::Ptr m_categoriesTask;
|
||||
};
|
||||
|
||||
class FlameResourcePackPage : public ResourcePackResourcePage {
|
||||
|
@ -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 });
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@ -361,3 +388,25 @@ 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();
|
||||
}
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "modplatform/modrinth/ModrinthPackManifest.h"
|
||||
#include "ui/pages/modplatform/ModpackProviderBasePage.h"
|
||||
#include "ui/widgets/ModFilterWidget.h"
|
||||
#include "ui/widgets/ProgressWidget.h"
|
||||
|
||||
#include <QTimer>
|
||||
@ -87,6 +88,7 @@ class ModrinthPage : public QWidget, public ModpackProviderBasePage {
|
||||
void onSelectionChanged(QModelIndex first, QModelIndex second);
|
||||
void onVersionSelectionChanged(int index);
|
||||
void triggerSearch();
|
||||
void createFilterWidget();
|
||||
|
||||
private:
|
||||
Ui::ModrinthPage* ui;
|
||||
@ -100,4 +102,7 @@ class ModrinthPage : public QWidget, public ModpackProviderBasePage {
|
||||
|
||||
// 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="QLineEdit" name="searchEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search and filter...</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="QPushButton" name="filterButton">
|
||||
<property name="text">
|
||||
<string>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>
|
||||
|
@ -38,19 +38,6 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelPostExitCmd">
|
||||
<property name="text">
|
||||
<string>P&ost-exit command:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>postExitCmdTextBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="preLaunchCmdTextBox"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelPreLaunchCmd">
|
||||
<property name="text">
|
||||
@ -61,8 +48,8 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="postExitCmdTextBox"/>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="preLaunchCmdTextBox"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelWrapperCmd">
|
||||
@ -77,6 +64,19 @@
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="wrapperCmdTextBox"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelPostExitCmd">
|
||||
<property name="text">
|
||||
<string>P&ost-exit command:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>postExitCmdTextBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="postExitCmdTextBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -64,10 +64,49 @@ class VersionBasicModel : public QIdentityProxyModel {
|
||||
{
|
||||
if (role == Qt::DisplayRole)
|
||||
return QIdentityProxyModel::data(index, BaseVersionList::VersionIdRole);
|
||||
if (role == Qt::UserRole)
|
||||
return QIdentityProxyModel::data(index, BaseVersionList::VersionIdRole);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
class AllVersionProxyModel : public QSortFilterProxyModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AllVersionProxyModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) {}
|
||||
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override { return QSortFilterProxyModel::rowCount(parent) + 1; }
|
||||
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.row() == 0) {
|
||||
if (role == Qt::DisplayRole) {
|
||||
return tr("All Versions");
|
||||
}
|
||||
if (role == Qt::UserRole) {
|
||||
return "all";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QModelIndex newIndex = QSortFilterProxyModel::index(index.row() - 1, index.column());
|
||||
return QSortFilterProxyModel::data(newIndex, role);
|
||||
}
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override
|
||||
{
|
||||
if (index.row() == 0) {
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
}
|
||||
return QSortFilterProxyModel::flags(index);
|
||||
}
|
||||
};
|
||||
|
||||
ModFilterWidget::ModFilterWidget(MinecraftInstance* instance, bool extended, QWidget* parent)
|
||||
: QTabWidget(parent), ui(new Ui::ModFilterWidget), m_instance(instance), m_filter(new Filter())
|
||||
{
|
||||
@ -76,14 +115,21 @@ ModFilterWidget::ModFilterWidget(MinecraftInstance* instance, bool extended, QWi
|
||||
m_versions_proxy = new VersionProxyModel(this);
|
||||
m_versions_proxy->setFilter(BaseVersionList::TypeRole, new ExactFilter("release"));
|
||||
|
||||
auto proxy = new VersionBasicModel(this);
|
||||
QAbstractProxyModel* proxy = new VersionBasicModel(this);
|
||||
proxy->setSourceModel(m_versions_proxy);
|
||||
|
||||
if (extended) {
|
||||
if (!m_instance) {
|
||||
ui->environmentGroup->hide();
|
||||
}
|
||||
ui->versions->setSourceModel(proxy);
|
||||
ui->versions->setSeparator(", ");
|
||||
ui->versions->setDefaultText(tr("All Versions"));
|
||||
ui->version->hide();
|
||||
} else {
|
||||
auto allVersions = new AllVersionProxyModel(this);
|
||||
allVersions->setSourceModel(proxy);
|
||||
proxy = allVersions;
|
||||
ui->version->setModel(proxy);
|
||||
ui->versions->hide();
|
||||
ui->showAllVersions->hide();
|
||||
@ -162,18 +208,22 @@ void ModFilterWidget::loadVersionList()
|
||||
|
||||
void ModFilterWidget::prepareBasicFilter()
|
||||
{
|
||||
m_filter->hideInstalled = false;
|
||||
m_filter->side = ""; // or "both"
|
||||
auto loaders = m_instance->getPackProfile()->getSupportedModLoaders().value();
|
||||
ui->neoForge->setChecked(loaders & ModPlatform::NeoForge);
|
||||
ui->forge->setChecked(loaders & ModPlatform::Forge);
|
||||
ui->fabric->setChecked(loaders & ModPlatform::Fabric);
|
||||
ui->quilt->setChecked(loaders & ModPlatform::Quilt);
|
||||
m_filter->loaders = loaders;
|
||||
auto def = m_instance->getPackProfile()->getComponentVersion("net.minecraft");
|
||||
m_filter->versions.emplace_front(def);
|
||||
ui->versions->setCheckedItems({ def });
|
||||
ui->version->setCurrentIndex(ui->version->findText(def));
|
||||
if (m_instance) {
|
||||
m_filter->hideInstalled = false;
|
||||
m_filter->side = ""; // or "both"
|
||||
auto loaders = m_instance->getPackProfile()->getSupportedModLoaders().value();
|
||||
ui->neoForge->setChecked(loaders & ModPlatform::NeoForge);
|
||||
ui->forge->setChecked(loaders & ModPlatform::Forge);
|
||||
ui->fabric->setChecked(loaders & ModPlatform::Fabric);
|
||||
ui->quilt->setChecked(loaders & ModPlatform::Quilt);
|
||||
m_filter->loaders = loaders;
|
||||
auto def = m_instance->getPackProfile()->getComponentVersion("net.minecraft");
|
||||
m_filter->versions.emplace_front(def);
|
||||
ui->versions->setCheckedItems({ def });
|
||||
ui->version->setCurrentIndex(ui->version->findText(def));
|
||||
} else {
|
||||
ui->hideInstalled->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void ModFilterWidget::onShowAllVersionsChanged()
|
||||
@ -249,7 +299,9 @@ void ModFilterWidget::onHideInstalledFilterChanged()
|
||||
void ModFilterWidget::onVersionFilterTextChanged(const QString& version)
|
||||
{
|
||||
m_filter->versions.clear();
|
||||
m_filter->versions.emplace_back(version);
|
||||
if (ui->version->currentData(Qt::UserRole) != "all") {
|
||||
m_filter->versions.emplace_back(version);
|
||||
}
|
||||
m_filter_changed = true;
|
||||
emit filterChanged();
|
||||
}
|
||||
|
@ -71,6 +71,15 @@ class ModFilterWidget : public QTabWidget {
|
||||
releases == other.releases && categoryIds == other.categoryIds;
|
||||
}
|
||||
bool operator!=(const Filter& other) const { return !(*this == other); }
|
||||
|
||||
bool checkMcVersions(QStringList value)
|
||||
{
|
||||
for (auto mcVersion : versions)
|
||||
if (value.contains(mcVersion.toString()))
|
||||
return true;
|
||||
|
||||
return versions.empty();
|
||||
}
|
||||
};
|
||||
|
||||
static unique_qobject_ptr<ModFilterWidget> create(MinecraftInstance* instance, bool extended, QWidget* parent = nullptr);
|
||||
|
Reference in New Issue
Block a user