Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into change_version

This commit is contained in:
Trial97
2024-05-18 15:27:02 +03:00
257 changed files with 3168 additions and 3863 deletions

View File

@ -55,7 +55,6 @@ CustomPage::CustomPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget(par
connect(ui->alphaFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->betaFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->snapshotFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->oldSnapshotFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->releaseFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->experimentsFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->refreshBtn, &QPushButton::clicked, this, &CustomPage::refresh);
@ -96,13 +95,11 @@ void CustomPage::filterChanged()
{
QStringList out;
if (ui->alphaFilter->isChecked())
out << "(old_alpha)";
out << "(alpha)";
if (ui->betaFilter->isChecked())
out << "(old_beta)";
out << "(beta)";
if (ui->snapshotFilter->isChecked())
out << "(snapshot)";
if (ui->oldSnapshotFilter->isChecked())
out << "(old_snapshot)";
if (ui->releaseFilter->isChecked())
out << "(release)";
if (ui->experimentsFilter->isChecked())

View File

@ -93,16 +93,6 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="oldSnapshotFilter">
<property name="text">
<string>Old Snapshots</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="betaFilter">
<property name="text">
@ -286,7 +276,6 @@
<tabstop>tabWidget</tabstop>
<tabstop>releaseFilter</tabstop>
<tabstop>snapshotFilter</tabstop>
<tabstop>oldSnapshotFilter</tabstop>
<tabstop>betaFilter</tabstop>
<tabstop>alphaFilter</tabstop>
<tabstop>experimentsFilter</tabstop>

View File

@ -123,6 +123,10 @@ void ImportPage::updateState()
// need to find the download link for the modpack
// format of url curseforge://install?addonId=IDHERE&fileId=IDHERE
QUrlQuery query(url);
if (query.allQueryItemValues("addonId").isEmpty() || query.allQueryItemValues("fileId").isEmpty()) {
qDebug() << "Invalid curseforge link:" << url;
return;
}
auto addonId = query.allQueryItemValues("addonId")[0];
auto fileId = query.allQueryItemValues("fileId")[0];
auto array = std::make_shared<QByteArray>();
@ -200,7 +204,9 @@ void ImportPage::setExtraInfo(const QMap<QString, QString>& extra_info)
void ImportPage::on_modpackBtn_clicked()
{
auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString();
const QMimeType zip = QMimeDatabase().mimeTypeForName("application/zip");
auto filter = tr("Supported files") + QString(" (%1 *.mrpack)").arg(zip.globPatterns().join(" "));
filter += ";;" + zip.filterString();
//: Option for filtering for *.mrpack files when importing
filter += ";;" + tr("Modrinth pack") + " (*.mrpack)";
const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter);

View File

@ -90,6 +90,7 @@ void ModPage::filterMods()
void ModPage::triggerSearch()
{
m_filter = m_filter_widget->getFilter();
m_ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect);
m_ui->packView->clearSelection();
m_ui->packDescription->clear();
m_ui->versionSelectionBox->clear();

View File

@ -207,6 +207,11 @@ void ResourceModel::loadEntry(QModelIndex& entry)
return;
versionRequestSucceeded(doc, pack, entry);
};
if (!callbacks.on_fail)
callbacks.on_fail = [](QString reason, int) {
QMessageBox::critical(nullptr, tr("Error"),
tr("A network error occurred. Could not load project versions: %1").arg(reason));
};
if (auto job = m_api->getProjectVersions(std::move(args), std::move(callbacks)); job)
runInfoJob(job);
@ -228,7 +233,13 @@ void ResourceModel::loadEntry(QModelIndex& entry)
callbacks.on_fail = [this](QString reason) {
if (!s_running_models.constFind(this).value())
return;
QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project info:%1").arg(reason));
QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project info: %1").arg(reason));
};
if (!callbacks.on_abort)
callbacks.on_abort = [this] {
if (!s_running_models.constFind(this).value())
return;
qCritical() << tr("The request was aborted for an unknown reason");
};
if (auto job = m_api->getProjectInfo(std::move(args), std::move(callbacks)); job)
@ -320,7 +331,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(), &NetAction::succeeded, this, [=] {
connect(icon_fetch_action.get(), &Task::succeeded, this, [=] {
auto icon = QIcon(full_file_path);
QPixmapCache::insert(url.toString(), icon.pixmap(icon.actualSize({ 64, 64 })));
@ -328,7 +339,7 @@ std::optional<QIcon> ResourceModel::getIcon(QModelIndex& index, const QUrl& url)
emit dataChanged(index, index, { Qt::DecorationRole });
});
connect(icon_fetch_action.get(), &NetAction::failed, this, [=] {
connect(icon_fetch_action.get(), &Task::failed, this, [=] {
m_currently_running_icon_actions.remove(url);
m_failed_icon_actions.insert(url);
});

View File

@ -23,6 +23,7 @@ ResourcePackResourcePage::ResourcePackResourcePage(ResourceDownloadDialog* dialo
void ResourcePackResourcePage::triggerSearch()
{
m_ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect);
m_ui->packView->clearSelection();
m_ui->packDescription->clear();
m_ui->versionSelectionBox->clear();

View File

@ -200,6 +200,11 @@ void ResourcePage::updateUi()
}
if (current_pack->extraDataLoaded) {
if (current_pack->extraData.status == "archived") {
text += "<br><br>" + tr("<b>This project has been archived. It will not receive any further updates unless the author decides "
"to unarchive the project.</b>");
}
if (!current_pack->extraData.donate.isEmpty()) {
text += "<br><br>" + tr("Donate information: ");
auto donateToStr = [](ModPlatform::DonationData& donate) -> QString {
@ -407,9 +412,9 @@ void ResourcePage::openUrl(const QUrl& url)
auto jump = [url, slug, model, view] {
for (int row = 0; row < model->rowCount({}); row++) {
const QModelIndex index = model->index(row);
const auto pack = model->data(index, Qt::UserRole).value<ModPlatform::IndexedPack>();
const auto pack = model->data(index, Qt::UserRole).value<ModPlatform::IndexedPack::Ptr>();
if (pack.slug == slug) {
if (pack->slug == slug) {
view->setCurrentIndex(index);
return;
}

View File

@ -24,6 +24,7 @@ ShaderPackResourcePage::ShaderPackResourcePage(ShaderPackDownloadDialog* dialog,
void ShaderPackResourcePage::triggerSearch()
{
m_ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect);
m_ui->packView->clearSelection();
m_ui->packDescription->clear();
m_ui->versionSelectionBox->clear();

View File

@ -170,6 +170,10 @@ void ListModel::performPaginatedSearch()
callbacks.on_fail = [this](QString reason) { searchRequestFailed(reason); };
callbacks.on_succeed = [this](auto& doc, auto& pack) { searchRequestForOneSucceeded(doc); };
callbacks.on_abort = [this] {
qCritical() << "Search task aborted by an unknown reason!";
searchRequestFailed("Abborted");
};
static const FlameAPI api;
if (auto job = api.getProjectInfo({ projectId }, std::move(callbacks)); job) {
jobPtr = job;

View File

@ -34,6 +34,7 @@
*/
#include "FlamePage.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui_FlamePage.h"
#include <QKeyEvent>
@ -193,6 +194,8 @@ void FlamePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelInde
suggestCurrent();
});
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); });
connect(netJob, &NetJob::failed,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
netJob->start();
} else {
for (auto version : current.versions) {

View File

@ -20,6 +20,7 @@
#include "ui/widgets/ProjectItem.h"
#include "ui_ImportFTBPage.h"
#include <QFileDialog>
#include <QWidget>
#include "FileSystem.h"
#include "ListModel.h"
@ -56,6 +57,13 @@ ImportFTBPage::ImportFTBPage(NewInstanceDialog* dialog, QWidget* parent) : QWidg
connect(ui->searchEdit, &QLineEdit::textChanged, this, &ImportFTBPage::triggerSearch);
connect(ui->browseButton, &QPushButton::clicked, this, [this] {
auto path = listModel->getPath();
QString dir = QFileDialog::getExistingDirectory(this, tr("Select FTBApp instances directory"), path, QFileDialog::ShowDirsOnly);
if (!dir.isEmpty())
listModel->setPath(dir);
});
ui->modpackList->setItemDelegate(new ProjectItemDelegate(this));
ui->modpackList->selectionModel()->reset();
}

View File

@ -11,7 +11,7 @@
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<item row="2" column="1">
<widget class="QTreeView" name="modpackList">
<property name="maximumSize">
<size>
@ -21,28 +21,7 @@
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="searchEdit">
<property name="placeholderText">
<string>Search and filter...</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Search</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="sortByBox">
@ -69,6 +48,54 @@
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="searchEdit">
<property name="placeholderText">
<string>Search and filter...</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Search</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="browseButton">
<property name="toolTip">
<string>Select FTBApp instances directory</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="viewfolder">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label">
<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>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@ -17,11 +17,13 @@
*/
#include "ListModel.h"
#include <qfileinfo.h>
#include <QDir>
#include <QDirIterator>
#include <QFileInfo>
#include <QIcon>
#include <QProcessEnvironment>
#include "Application.h"
#include "FileSystem.h"
#include "StringUtils.h"
#include "modplatform/import_ftb/PackHelpers.h"
@ -29,7 +31,7 @@
namespace FTBImportAPP {
QString getPath()
QString getStaticPath()
{
QString partialPath;
#if defined(Q_OS_OSX)
@ -42,14 +44,14 @@ QString getPath()
return FS::PathCombine(partialPath, ".ftba");
}
const QString ListModel::FTB_APP_PATH = getPath();
static const QString FTB_APP_PATH = FS::PathCombine(getStaticPath(), "instances");
void ListModel::update()
{
beginResetModel();
modpacks.clear();
QString instancesPath = FS::PathCombine(FTB_APP_PATH, "instances");
QString instancesPath = getPath();
if (auto instancesInfo = QFileInfo(instancesPath); instancesInfo.exists() && instancesInfo.isDir()) {
QDirIterator directoryIterator(instancesPath, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable | QDir::Hidden,
QDirIterator::FollowSymlinks);
@ -168,4 +170,17 @@ FilterModel::Sorting FilterModel::getCurrentSorting()
{
return currentSorting;
}
void ListModel::setPath(QString path)
{
APPLICATION->settings()->set("FTBAppInstancesPath", path);
update();
}
QString ListModel::getPath()
{
auto path = APPLICATION->settings()->get("FTBAppInstancesPath").toString();
if (path.isEmpty() || !QFileInfo(path).exists())
path = FTB_APP_PATH;
return path;
}
} // namespace FTBImportAPP

View File

@ -60,7 +60,8 @@ class ListModel : public QAbstractListModel {
void update();
static const QString FTB_APP_PATH;
QString getPath();
void setPath(QString path);
private:
ModpackList modpacks;

View File

@ -140,6 +140,10 @@ void ModpackListModel::performPaginatedSearch()
callbacks.on_fail = [this](QString reason) { searchRequestFailed(reason); };
callbacks.on_succeed = [this](auto& doc, auto& pack) { searchRequestForOneSucceeded(doc); };
callbacks.on_abort = [this] {
qCritical() << "Search task aborted by an unknown reason!";
searchRequestFailed("Aborted");
};
static const ModrinthAPI api;
if (auto job = api.getProjectInfo({ projectId }, std::move(callbacks)); job) {
jobPtr = job;
@ -348,10 +352,10 @@ void ModpackListModel::searchRequestForOneSucceeded(QJsonDocument& doc)
void ModpackListModel::searchRequestFailed(QString reason)
{
auto failed_action = dynamic_cast<NetJob*>(jobPtr.get())->getFailedActions().at(0);
if (!failed_action->m_reply) {
if (failed_action->replyStatusCode() == -1) {
// Network error
QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load modpacks."));
} else if (failed_action->m_reply && failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409) {
} else if (failed_action->replyStatusCode() == 409) {
// 409 Gone, notify user to update
QMessageBox::critical(nullptr, tr("Error"),
//: %1 refers to the launcher itself

View File

@ -35,6 +35,7 @@
*/
#include "ModrinthPage.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui_ModrinthPage.h"
#include "ModrinthModel.h"
@ -103,6 +104,7 @@ void ModrinthPage::retranslate()
void ModrinthPage::openedImpl()
{
BasePage::openedImpl();
suggestCurrent();
triggerSearch();
}
@ -182,6 +184,8 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
suggestCurrent();
});
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); });
connect(netJob, &NetJob::failed,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
netJob->start();
} else
updateUI();
@ -235,6 +239,8 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
suggestCurrent();
});
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); });
connect(netJob, &NetJob::failed,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
netJob->start();
} else {
@ -262,6 +268,11 @@ void ModrinthPage::updateUI()
text += "<br>" + tr(" by ") + QString("<a href=%1>%2</a>").arg(std::get<1>(current.author).toString(), std::get<0>(current.author));
if (current.extraInfoLoaded) {
if (current.extra.status == "archived") {
text += "<br><br>" + tr("<b>This project has been archived. It will not receive any further updates unless the author decides "
"to unarchive the project.</b>");
}
if (!current.extra.donate.isEmpty()) {
text += "<br><br>" + tr("Donate information: ");
auto donateToStr = [](Modrinth::DonationData& donate) -> QString {

View File

@ -11,43 +11,7 @@
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Note: Modrinth modpacks are still in alpha phase. Some things may be rough on the edges, or not working at all! Use it with caution.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout">
<item>
<widget class="QLineEdit" name="searchEdit">
<property name="placeholderText">
<string>Search and filter ...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="searchButton">
<property name="text">
<string>Search</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<item row="2" column="0">
<layout class="QHBoxLayout">
<item>
<widget class="QListView" name="packView">
@ -77,7 +41,7 @@
</item>
</layout>
</item>
<item row="4" column="0">
<item row="3" column="0">
<layout class="QHBoxLayout">
<item>
<widget class="QComboBox" name="sortByBox"/>
@ -97,6 +61,24 @@
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout">
<item>
<widget class="QLineEdit" name="searchEdit">
<property name="placeholderText">
<string>Search and filter ...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="searchButton">
<property name="text">
<string>Search</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>

View File

@ -34,6 +34,7 @@
*/
#include "TechnicPage.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/widgets/ProjectItem.h"
#include "ui_TechnicPage.h"
@ -208,6 +209,8 @@ void TechnicPage::suggestCurrent()
metadataLoaded();
});
connect(jobPtr.get(), &NetJob::failed,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
jobPtr = netJob;
jobPtr->start();
@ -258,6 +261,8 @@ void TechnicPage::metadataLoaded()
netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(url), response));
QObject::connect(netJob.get(), &NetJob::succeeded, this, &TechnicPage::onSolderLoaded);
connect(jobPtr.get(), &NetJob::failed,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
jobPtr = netJob;
jobPtr->start();