From c6b3eccbdf2785b59ab33ed99fabf6f3f5d81d2a Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sat, 14 May 2022 19:46:52 +0200 Subject: refactor: rename Modrinth classes to ModrinthMod --- .../modplatform/modrinth/ModrinthModModel.cpp | 43 ++++++++++++ .../pages/modplatform/modrinth/ModrinthModModel.h | 25 +++++++ .../pages/modplatform/modrinth/ModrinthModPage.cpp | 82 ++++++++++++++++++++++ .../pages/modplatform/modrinth/ModrinthModPage.h | 61 ++++++++++++++++ .../pages/modplatform/modrinth/ModrinthModel.cpp | 43 ------------ .../ui/pages/modplatform/modrinth/ModrinthModel.h | 25 ------- .../ui/pages/modplatform/modrinth/ModrinthPage.cpp | 82 ---------------------- .../ui/pages/modplatform/modrinth/ModrinthPage.h | 61 ---------------- 8 files changed, 211 insertions(+), 211 deletions(-) create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModModel.cpp create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h delete mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp delete mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModel.h delete mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp delete mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthPage.h (limited to 'launcher/ui/pages') diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.cpp new file mode 100644 index 00000000..1d9f4d60 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.cpp @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu + * + * 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 . + */ + +#include "ModrinthModModel.h" + +#include "modplatform/modrinth/ModrinthPackIndex.h" + +namespace Modrinth { + +// NOLINTNEXTLINE(modernize-avoid-c-arrays) +const char* ListModel::sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; + +void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) +{ + Modrinth::loadIndexedPack(m, obj); +} + +void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) +{ + Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance); +} + +auto ListModel::documentToArray(QJsonDocument& obj) const -> QJsonArray +{ + return obj.object().value("hits").toArray(); +} + +} // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h new file mode 100644 index 00000000..63c23bbe --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModModel.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ModrinthModPage.h" + +namespace Modrinth { + +class ListModel : public ModPlatform::ListModel { + Q_OBJECT + + public: + ListModel(ModrinthModPage* parent) : ModPlatform::ListModel(parent){}; + ~ListModel() override = default; + + private: + void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override; + void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override; + + auto documentToArray(QJsonDocument& obj) const -> QJsonArray override; + + // NOLINTNEXTLINE(modernize-avoid-c-arrays) + static const char* sorts[5]; + inline auto getSorts() const -> const char** override { return sorts; }; +}; + +} // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp new file mode 100644 index 00000000..d3a1f859 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 Sefa Eyeoglu + * + * 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 . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ModrinthModPage.h" +#include "modplatform/modrinth/ModrinthAPI.h" +#include "ui_ModPage.h" + +#include "ModrinthModModel.h" +#include "ui/dialogs/ModDownloadDialog.h" + +ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance* instance) + : ModPage(dialog, instance, new ModrinthAPI()) +{ + listModel = new Modrinth::ListModel(this); + ui->packView->setModel(listModel); + + // index is used to set the sorting with the modrinth api + ui->sortByBox->addItem(tr("Sort by Relevance")); + ui->sortByBox->addItem(tr("Sort by Downloads")); + ui->sortByBox->addItem(tr("Sort by Follows")); + ui->sortByBox->addItem(tr("Sort by Last Updated")); + ui->sortByBox->addItem(tr("Sort by Newest")); + + // sometimes Qt just ignores virtual slots and doesn't work as intended it seems, + // so it's best not to connect them in the parent's constructor... + connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch())); + connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthModPage::onSelectionChanged); + connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthModPage::onVersionSelectionChanged); + connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthModPage::onModSelected); +} + +auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader) const -> bool +{ + auto loaderStrings = ModrinthAPI::getModLoaderStrings(loader); + + auto loaderCompatible = false; + for (auto remoteLoader : ver.loaders) + { + if (loaderStrings.contains(remoteLoader)) { + loaderCompatible = true; + break; + } + } + return ver.mcVersion.contains(mineVer) && loaderCompatible; +} + +// I don't know why, but doing this on the parent class makes it so that +// other mod providers start loading before being selected, at least with +// my Qt, so we need to implement this in every derived class... +auto ModrinthModPage::shouldDisplay() const -> bool { return true; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h new file mode 100644 index 00000000..b1e72bfe --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 Sefa Eyeoglu + * + * 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 . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "modplatform/ModAPI.h" +#include "ui/pages/modplatform/ModPage.h" + +#include "modplatform/modrinth/ModrinthAPI.h" + +class ModrinthModPage : public ModPage { + Q_OBJECT + + public: + explicit ModrinthModPage(ModDownloadDialog* dialog, BaseInstance* instance); + ~ModrinthModPage() override = default; + + inline auto displayName() const -> QString override { return "Modrinth"; } + inline auto icon() const -> QIcon override { return APPLICATION->getThemedIcon("modrinth"); } + inline auto id() const -> QString override { return "modrinth"; } + inline auto helpPage() const -> QString override { return "Mod-platform"; } + + inline auto debugName() const -> QString override { return "Modrinth"; } + inline auto metaEntryBase() const -> QString override { return "ModrinthPacks"; }; + + auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader = ModAPI::Unspecified) const -> bool override; + + auto shouldDisplay() const -> bool override; +}; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp deleted file mode 100644 index b788860a..00000000 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * PolyMC - Minecraft Launcher - * Copyright (C) 2022 Sefa Eyeoglu - * - * 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 . - */ - -#include "ModrinthModel.h" - -#include "modplatform/modrinth/ModrinthPackIndex.h" - -namespace Modrinth { - -// NOLINTNEXTLINE(modernize-avoid-c-arrays) -const char* ListModel::sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; - -void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) -{ - Modrinth::loadIndexedPack(m, obj); -} - -void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) -{ - Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance); -} - -auto ListModel::documentToArray(QJsonDocument& obj) const -> QJsonArray -{ - return obj.object().value("hits").toArray(); -} - -} // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h deleted file mode 100644 index 45a6090a..00000000 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "ModrinthPage.h" - -namespace Modrinth { - -class ListModel : public ModPlatform::ListModel { - Q_OBJECT - - public: - ListModel(ModrinthPage* parent) : ModPlatform::ListModel(parent){}; - ~ListModel() override = default; - - private: - void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override; - void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override; - - auto documentToArray(QJsonDocument& obj) const -> QJsonArray override; - - // NOLINTNEXTLINE(modernize-avoid-c-arrays) - static const char* sorts[5]; - inline auto getSorts() const -> const char** override { return sorts; }; -}; - -} // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp deleted file mode 100644 index 98bde0ae..00000000 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * PolyMC - Minecraft Launcher - * Copyright (c) 2022 Sefa Eyeoglu - * - * 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 . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ModrinthPage.h" -#include "modplatform/modrinth/ModrinthAPI.h" -#include "ui_ModPage.h" - -#include "ModrinthModel.h" -#include "ui/dialogs/ModDownloadDialog.h" - -ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) - : ModPage(dialog, instance, new ModrinthAPI()) -{ - listModel = new Modrinth::ListModel(this); - ui->packView->setModel(listModel); - - // index is used to set the sorting with the modrinth api - ui->sortByBox->addItem(tr("Sort by Relevance")); - ui->sortByBox->addItem(tr("Sort by Downloads")); - ui->sortByBox->addItem(tr("Sort by Follows")); - ui->sortByBox->addItem(tr("Sort by Last Updated")); - ui->sortByBox->addItem(tr("Sort by Newest")); - - // sometimes Qt just ignores virtual slots and doesn't work as intended it seems, - // so it's best not to connect them in the parent's constructor... - connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch())); - connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthPage::onSelectionChanged); - connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthPage::onVersionSelectionChanged); - connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthPage::onModSelected); -} - -auto ModrinthPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader) const -> bool -{ - auto loaderStrings = ModrinthAPI::getModLoaderStrings(loader); - - auto loaderCompatible = false; - for (auto remoteLoader : ver.loaders) - { - if (loaderStrings.contains(remoteLoader)) { - loaderCompatible = true; - break; - } - } - return ver.mcVersion.contains(mineVer) && loaderCompatible; -} - -// I don't know why, but doing this on the parent class makes it so that -// other mod providers start loading before being selected, at least with -// my Qt, so we need to implement this in every derived class... -auto ModrinthPage::shouldDisplay() const -> bool { return true; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h deleted file mode 100644 index e3a0e1f0..00000000 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * PolyMC - Minecraft Launcher - * Copyright (c) 2022 Sefa Eyeoglu - * - * 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 . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "modplatform/ModAPI.h" -#include "ui/pages/modplatform/ModPage.h" - -#include "modplatform/modrinth/ModrinthAPI.h" - -class ModrinthPage : public ModPage { - Q_OBJECT - - public: - explicit ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance); - ~ModrinthPage() override = default; - - inline auto displayName() const -> QString override { return "Modrinth"; } - inline auto icon() const -> QIcon override { return APPLICATION->getThemedIcon("modrinth"); } - inline auto id() const -> QString override { return "modrinth"; } - inline auto helpPage() const -> QString override { return "Mod-platform"; } - - inline auto debugName() const -> QString override { return "Modrinth"; } - inline auto metaEntryBase() const -> QString override { return "ModrinthPacks"; }; - - auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader = ModAPI::Unspecified) const -> bool override; - - auto shouldDisplay() const -> bool override; -}; -- cgit From db038463581400005f045a277a249ab07175ab2b Mon Sep 17 00:00:00 2001 From: kb1000 Date: Mon, 31 Jan 2022 15:25:36 +0100 Subject: Add support for importing Modrinth packs from files --- launcher/ui/pages/modplatform/ImportPage.cpp | 4 +- .../ui/pages/modplatform/modrinth/ModrinthPage.cpp | 55 +++++++++++++ .../ui/pages/modplatform/modrinth/ModrinthPage.h | 62 ++++++++++++++ .../ui/pages/modplatform/modrinth/ModrinthPage.ui | 94 ++++++++++++++++++++++ 4 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthPage.h create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui (limited to 'launcher/ui/pages') diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 1b53dd40..8ae38f8d 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -109,7 +109,8 @@ void ImportPage::updateState() { // FIXME: actually do some validation of what's inside here... this is fake AF QFileInfo fi(input); - if(fi.exists() && fi.suffix() == "zip") + // mrpack is a modrinth pack + if(fi.exists() && (fi.suffix() == "zip" || fi.suffix() == "mrpack")) { QFileInfo fi(url.fileName()); dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url)); @@ -143,6 +144,7 @@ void ImportPage::setUrl(const QString& url) void ImportPage::on_modpackBtn_clicked() { + // TODO: Add .mrpack filter auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString(); const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter); if (url.isValid()) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp new file mode 100644 index 00000000..93b1ca02 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2021-2022 kb1000 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ModrinthPage.h" + +#include "ui_ModrinthPage.h" + +#include + +ModrinthPage::ModrinthPage(NewInstanceDialog *dialog, QWidget *parent) : QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog) +{ + ui->setupUi(this); +} + +ModrinthPage::~ModrinthPage() +{ + delete ui; +} + +void ModrinthPage::openedImpl() +{ + BasePage::openedImpl(); + triggerSearch(); +} + +bool ModrinthPage::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { + auto *keyEvent = reinterpret_cast(event); + if (keyEvent->key() == Qt::Key_Return) { + this->triggerSearch(); + keyEvent->accept(); + return true; + } + } + return QObject::eventFilter(watched, event); +} + +void ModrinthPage::triggerSearch() { + +} diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h new file mode 100644 index 00000000..6c75b60d --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -0,0 +1,62 @@ +/* + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2021-2022 kb1000 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Application.h" +#include "ui/dialogs/NewInstanceDialog.h" +#include "ui/pages/BasePage.h" + +#include + +namespace Ui +{ + class ModrinthPage; +} + +class ModrinthPage : public QWidget, public BasePage +{ + Q_OBJECT + +public: + explicit ModrinthPage(NewInstanceDialog *dialog, QWidget *parent = nullptr); + ~ModrinthPage() override; + + QString displayName() const override + { + return tr("Modrinth"); + } + QIcon icon() const override + { + return APPLICATION->getThemedIcon("modrinth"); + } + QString id() const override + { + return "modrinth"; + } + + void openedImpl() override; + + bool eventFilter(QObject *watched, QEvent *event) override; + +private slots: + void triggerSearch(); + +private: + Ui::ModrinthPage *ui; + NewInstanceDialog *dialog; +}; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui new file mode 100644 index 00000000..7ef099d3 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui @@ -0,0 +1,94 @@ + + + ModrinthPage + + + + 0 + 0 + 837 + 685 + + + + + + + + + Search and filter ... + + + + + + + Search + + + + + + + + + + + Qt::ScrollBarAlwaysOff + + + true + + + + 48 + 48 + + + + + + + + true + + + true + + + + + + + + + + + + + + Version selected: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + searchEdit + searchButton + packView + packDescription + sortByBox + versionSelectionBox + + + + -- cgit From 31988f0529f6c316d6a9ba3e66cf981a807ed710 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sat, 14 May 2022 19:56:38 +0200 Subject: fix: adapt upstream Modrinth code to our codebase --- launcher/ui/pages/modplatform/ImportPage.cpp | 2 +- .../ui/pages/modplatform/modrinth/ModrinthPage.cpp | 45 +++++++++++++++------ .../ui/pages/modplatform/modrinth/ModrinthPage.h | 46 ++++++++++++++++------ 3 files changed, 70 insertions(+), 23 deletions(-) (limited to 'launcher/ui/pages') diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 8ae38f8d..3b65de9d 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -144,8 +144,8 @@ void ImportPage::setUrl(const QString& url) void ImportPage::on_modpackBtn_clicked() { - // TODO: Add .mrpack filter auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString(); + filter += ";;" + tr("Modrinth pack (*.mrpack)"); const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter); if (url.isValid()) { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 93b1ca02..0d65ef16 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -1,18 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-only /* - * Copyright 2013-2021 MultiMC Contributors - * Copyright 2021-2022 kb1000 + * PolyMC - Minecraft Launcher * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2021-2022 kb1000 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "ModrinthPage.h" @@ -31,6 +49,11 @@ ModrinthPage::~ModrinthPage() delete ui; } +void ModrinthPage::retranslate() +{ + ui->retranslateUi(this); +} + void ModrinthPage::openedImpl() { BasePage::openedImpl(); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 6c75b60d..562049b4 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -1,18 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-only /* - * Copyright 2013-2021 MultiMC Contributors - * Copyright 2021-2022 kb1000 + * PolyMC - Minecraft Launcher * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2021-2022 kb1000 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #pragma once @@ -49,6 +67,12 @@ public: return "modrinth"; } + virtual QString helpPage() const override + { + return "Modrinth-platform"; + } + void retranslate() override; + void openedImpl() override; bool eventFilter(QObject *watched, QEvent *event) override; -- cgit From 4fda35b466e4e3f242955cf8cb692a10e8820f0b Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 20:17:05 -0300 Subject: feat: add modrinth pack downloading Things that don't work / work poorly (there's more for sure but those are the evident ones): - Icons are broken in the import dialog - No way to search for private packs - Icons are not downloaded when downloading a mod - No support for multiple download URLs - Probably a lot more... --- .../pages/modplatform/modrinth/ModrinthModel.cpp | 274 +++++++++++++++++++++ .../ui/pages/modplatform/modrinth/ModrinthModel.h | 81 ++++++ .../ui/pages/modplatform/modrinth/ModrinthPage.cpp | 207 +++++++++++++++- .../ui/pages/modplatform/modrinth/ModrinthPage.h | 67 ++--- 4 files changed, 593 insertions(+), 36 deletions(-) create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthModel.h (limited to 'launcher/ui/pages') diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp new file mode 100644 index 00000000..2890e27d --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -0,0 +1,274 @@ +#include "ModrinthModel.h" + +#include "BuildConfig.h" +#include "Json.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" +#include "ui/dialogs/ModDownloadDialog.h" + +#include + +namespace Modrinth { + +ModpackListModel::ModpackListModel(ModrinthPage* parent) : QAbstractListModel(parent), m_parent(parent) {} + +auto ModpackListModel::debugName() const -> QString +{ + return m_parent->debugName(); +} + +/******** Make data requests ********/ + +void ModpackListModel::fetchMore(const QModelIndex& parent) +{ + if (parent.isValid()) + return; + if (nextSearchOffset == 0) { + qWarning() << "fetchMore with 0 offset is wrong..."; + return; + } + performPaginatedSearch(); +} + +auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVariant +{ + int pos = index.row(); + if (pos >= modpacks.size() || pos < 0 || !index.isValid()) { + return QString("INVALID INDEX %1").arg(pos); + } + + Modrinth::Modpack pack = modpacks.at(pos); + if (role == Qt::DisplayRole) { + return pack.name; + } else if (role == Qt::ToolTipRole) { + if (pack.description.length() > 100) { + // some magic to prevent to long tooltips and replace html linebreaks + QString edit = pack.description.left(97); + edit = edit.left(edit.lastIndexOf("
")).left(edit.lastIndexOf(" ")).append("..."); + return edit; + } + return pack.description; + } else if (role == Qt::DecorationRole) { + // FIXME: help the icons dont have the same size ;-; + if (m_logoMap.contains(pack.iconName)) { + return (m_logoMap.value(pack.iconName)); + } + QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder"); + ((ModpackListModel*)this)->requestLogo(pack.iconName, pack.iconUrl.toString()); + return icon; + } else if (role == Qt::UserRole) { + QVariant v; + v.setValue(pack); + return v; + } + + return {}; +} + +/* +void ModpackListModel::requestModVersions(ModPlatform::IndexedPack const& current) +{ + auto profile = (dynamic_cast((dynamic_cast(parent()))->m_instance))->getPackProfile(); + + m_parent->apiProvider()->getVersions(this, { current.addonId.toString(), getMineVersions(), profile->getModLoader() }); +}*/ + +void ModpackListModel::performPaginatedSearch() +{ + // TODO: Move to standalone API + NetJob* netJob = new NetJob("Modrinth::SearchModpack", APPLICATION->network()); + auto searchAllUrl = QString( + "https://staging-api.modrinth.com/v2/search?" + "query=%1&" + "facets=[[\"project_type:modpack\"]]") + .arg(currentSearchTerm); + + netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), &m_all_response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this] { + QJsonParseError parse_error_all {}; + + 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; + return; + } + + searchRequestFinished(doc_all); + }); + QObject::connect(netJob, &NetJob::failed, this, &ModpackListModel::searchRequestFailed); + + jobPtr = netJob; + jobPtr->start(); +} + +void ModpackListModel::refresh() +{ + if (jobPtr) { + jobPtr->abort(); + searchState = ResetRequested; + return; + } else { + beginResetModel(); + modpacks.clear(); + endResetModel(); + searchState = None; + } + nextSearchOffset = 0; + performPaginatedSearch(); +} + +void ModpackListModel::searchWithTerm(const QString& term, const int sort) +{ + if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) { + return; + } + + currentSearchTerm = term; + currentSort = sort; + + refresh(); +} + +void ModpackListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback) +{ + if (m_logoMap.contains(logo)) { + callback(APPLICATION->metacache() + ->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))) + ->getFullPath()); + } else { + requestLogo(logo, logoUrl); + } +} + +void ModpackListModel::requestLogo(QString logo, QString url) +{ + if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) { + return; + } + + MetaEntryPtr entry = + APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))); + auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network()); + job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); + + auto fullPath = entry->getFullPath(); + QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] { + job->deleteLater(); + emit logoLoaded(logo, QIcon(fullPath)); + if (waitingCallbacks.contains(logo)) { + waitingCallbacks.value(logo)(fullPath); + } + }); + + QObject::connect(job, &NetJob::failed, this, [this, logo, job] { + job->deleteLater(); + emit logoFailed(logo); + }); + + job->start(); + m_loadingLogos.append(logo); +} + +/******** Request callbacks ********/ + +void ModpackListModel::logoLoaded(QString logo, QIcon out) +{ + m_loadingLogos.removeAll(logo); + m_logoMap.insert(logo, out); + for (int i = 0; i < modpacks.size(); i++) { + if (modpacks[i].iconName == logo) { + emit dataChanged(createIndex(i, 0), createIndex(i, 0), { Qt::DecorationRole }); + } + } +} + +void ModpackListModel::logoFailed(QString logo) +{ + m_failedLogos.append(logo); + m_loadingLogos.removeAll(logo); +} + +void ModpackListModel::searchRequestFinished(QJsonDocument& doc_all) +{ + jobPtr.reset(); + + QList newList; + + auto packs_all = doc_all.object().value("hits").toArray(); + for (auto packRaw : packs_all) { + auto packObj = packRaw.toObject(); + + Modrinth::Modpack pack; + try { + Modrinth::loadIndexedPack(pack, packObj); + newList.append(pack); + } catch (const JSONValidationError& e) { + qWarning() << "Error while loading mod from " << m_parent->debugName() << ": " << e.cause(); + continue; + } + } + + if (packs_all.size() < 25) { + searchState = Finished; + } else { + nextSearchOffset += 25; + searchState = CanPossiblyFetchMore; + } + + beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1); + modpacks.append(newList); + endInsertRows(); +} + +void ModpackListModel::searchRequestFailed(QString reason) +{ + if (!jobPtr->first()->m_reply) { + // Network error + QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load mods.")); + } else if (jobPtr->first()->m_reply && jobPtr->first()->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409) { + // 409 Gone, notify user to update + QMessageBox::critical(nullptr, tr("Error"), + //: %1 refers to the launcher itself + QString("%1 %2") + .arg(m_parent->displayName()) + .arg(tr("API version too old!\nPlease update %1!").arg(BuildConfig.LAUNCHER_NAME))); + } + jobPtr.reset(); + + if (searchState == ResetRequested) { + beginResetModel(); + modpacks.clear(); + endResetModel(); + + nextSearchOffset = 0; + performPaginatedSearch(); + } else { + searchState = Finished; + } +} + +void ModpackListModel::versionRequestSucceeded(QJsonDocument doc, QString id) +{ + auto& current = m_parent->getCurrent(); + if (id != current.id) { + return; + } + + auto arr = doc.isObject() ? Json::ensureArray(doc.object(), "data") : doc.array(); + + try { + // loadIndexedPackVersions(current, arr); + } catch (const JSONValidationError& e) { + qDebug() << doc; + qWarning() << "Error while reading " << debugName() << " mod version: " << e.cause(); + } + + // m_parent->updateModVersions(); +} + +} // namespace Modrinth + +/******** Helpers ********/ diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h new file mode 100644 index 00000000..1fdbe278 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include "modplatform/modrinth/ModrinthPackManifest.h" +#include "ui/pages/modplatform/modrinth/ModrinthPage.h" + +class ModPage; +class Version; + +namespace Modrinth { + +using LogoMap = QMap; +using LogoCallback = std::function; + +class ModpackListModel : public QAbstractListModel { + Q_OBJECT + + public: + ModpackListModel(ModrinthPage* parent); + ~ModpackListModel() override = default; + + inline auto rowCount(const QModelIndex& parent) const -> int override { return modpacks.size(); }; + inline auto columnCount(const QModelIndex& parent) const -> int override { return 1; }; + inline auto flags(const QModelIndex& index) const -> Qt::ItemFlags override { return QAbstractListModel::flags(index); }; + + auto debugName() const -> QString; + + /* Retrieve information from the model at a given index with the given role */ + auto data(const QModelIndex& index, int role) const -> QVariant override; + + inline void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; } + + /* Ask the API for more information */ + void fetchMore(const QModelIndex& parent) override; + void refresh(); + void searchWithTerm(const QString& term, const int sort); + + void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback); + + inline auto canFetchMore(const QModelIndex& parent) const -> bool override { return searchState == CanPossiblyFetchMore; }; + + public slots: + void searchRequestFinished(QJsonDocument& doc_all); + void searchRequestFailed(QString reason); + + void versionRequestSucceeded(QJsonDocument doc, QString addonId); + + protected slots: + + void logoFailed(QString logo); + void logoLoaded(QString logo, QIcon out); + + void performPaginatedSearch(); + + protected: + void requestLogo(QString file, QString url); + + inline auto getMineVersions() const -> std::list; + + protected: + ModrinthPage* m_parent; + + QList modpacks; + + LogoMap m_logoMap; + QMap waitingCallbacks; + QStringList m_failedLogos; + QStringList m_loadingLogos; + + QString currentSearchTerm; + int currentSort = 0; + int nextSearchOffset = 0; + enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None; + + NetJob::Ptr jobPtr; + + QByteArray m_all_response; + QByteArray m_specific_response; +}; +} // namespace ModPlatform diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 0d65ef16..68805316 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -34,14 +34,41 @@ */ #include "ModrinthPage.h" - #include "ui_ModrinthPage.h" +#include "ModrinthModel.h" + +#include "InstanceImportTask.h" +#include "Json.h" + +#include + +#include #include +#include -ModrinthPage::ModrinthPage(NewInstanceDialog *dialog, QWidget *parent) : QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog) +ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog) { ui->setupUi(this); + + connect(ui->searchButton, &QPushButton::clicked, this, &ModrinthPage::triggerSearch); + ui->searchEdit->installEventFilter(this); + m_model = new Modrinth::ModpackListModel(this); + ui->packView->setModel(m_model); + + ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); + + ui->sortByBox->addItem(tr("Sort by Featured")); + ui->sortByBox->addItem(tr("Sort by Popularity")); + ui->sortByBox->addItem(tr("Sort by Last Updated")); + ui->sortByBox->addItem(tr("Sort by Name")); + ui->sortByBox->addItem(tr("Sort by Author")); + ui->sortByBox->addItem(tr("Sort by Total Downloads")); + + connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch())); + connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthPage::onSelectionChanged); + connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthPage::onVersionSelectionChanged); } ModrinthPage::~ModrinthPage() @@ -60,10 +87,10 @@ void ModrinthPage::openedImpl() triggerSearch(); } -bool ModrinthPage::eventFilter(QObject *watched, QEvent *event) +bool ModrinthPage::eventFilter(QObject* watched, QEvent* event) { if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { - auto *keyEvent = reinterpret_cast(event); + auto* keyEvent = reinterpret_cast(event); if (keyEvent->key() == Qt::Key_Return) { this->triggerSearch(); keyEvent->accept(); @@ -73,6 +100,176 @@ bool ModrinthPage::eventFilter(QObject *watched, QEvent *event) return QObject::eventFilter(watched, event); } -void ModrinthPage::triggerSearch() { +void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) +{ + ui->versionSelectionBox->clear(); + + if (!first.isValid()) { + if (isOpened) { + dialog->setSuggestedPack(); + } + return; + } + + current = m_model->data(first, Qt::UserRole).value(); + auto name = current.name; + + if (!current.extraInfoLoaded) { + qDebug() << "Loading modrinth modpack information"; + + auto netJob = new NetJob(QString("Modrinth::PackInformation(%1)").arg(current.name), APPLICATION->network()); + auto response = new QByteArray(); + + QString id = current.id; + netJob->addNetAction(Net::Download::makeByteArray(QString("https://staging-api.modrinth.com/v2/project/%1").arg(id), response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { + if (id != current.id) { + return; // wrong request? + } + + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + auto obj = Json::requireObject(doc); + + try { + Modrinth::loadIndexedInfo(current, obj); + } catch (const JSONValidationError& e) { + qDebug() << *response; + qWarning() << "Error while reading modrinth modpack version: " << e.cause(); + } + + updateUI(); + suggestCurrent(); + }); + QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + netJob->start(); + } else + updateUI(); + + if (!current.versionsLoaded) { + qDebug() << "Loading modrinth modpack versions"; + + auto netJob = new NetJob(QString("Modrinth::PackVersions(%1)").arg(current.name), APPLICATION->network()); + auto response = new QByteArray(); + + QString id = current.id; + + netJob->addNetAction( + Net::Download::makeByteArray(QString("https://staging-api.modrinth.com/v2/project/%1/version").arg(id), response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] { + if (id != current.id) { + return; // wrong request? + } + + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + try { + Modrinth::loadIndexedVersions(current, doc); + } catch (const JSONValidationError& e) { + qDebug() << *response; + qWarning() << "Error while reading modrinth modpack version: " << e.cause(); + } + + for (auto version : current.versions) { + ui->versionSelectionBox->addItem(version.version, QVariant(version.id)); + } + + updateVersionsUI(); + suggestCurrent(); + }); + QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + netJob->start(); + + } else { + for (auto version : current.versions) { + ui->versionSelectionBox->addItem(QString("%1 - %2").arg(version.name, version.version), QVariant(version.id)); + } + + suggestCurrent(); + } +} + +void ModrinthPage::updateUI() +{ + QString text = ""; + + if (current.extra.sourceUrl.isEmpty()) + text = current.name; + else + text = "" + current.name + ""; + + if (!current.authors.empty()) { + // TODO: Implement multiple authors with links + text += "
" + tr(" by ") + current.authors.at(0); + } + + text += "
"; + + HoeDown h; + text += h.process(current.extra.body.toUtf8()); + + ui->packDescription->setHtml(text + current.description); +} + +void ModrinthPage::updateVersionsUI() +{ + // idk +} + +void ModrinthPage::suggestCurrent() +{ + if (!isOpened) { + return; + } + + if (selectedVersion.isEmpty()) { + dialog->setSuggestedPack(); + return; + } + + for (auto& ver : current.versions) { + if (ver.id == selectedVersion) { + dialog->setSuggestedPack(current.name, new InstanceImportTask(ver.download_url)); + + break; + } + } +} + +void ModrinthPage::triggerSearch() +{ + m_model->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex()); +} + +void ModrinthPage::onVersionSelectionChanged(QString data) +{ + if (data.isNull() || data.isEmpty()) { + selectedVersion = ""; + return; + } + selectedVersion = ui->versionSelectionBox->currentData().toString(); + suggestCurrent(); } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 562049b4..f72a5071 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -39,48 +39,53 @@ #include "ui/dialogs/NewInstanceDialog.h" #include "ui/pages/BasePage.h" +#include "modplatform/modrinth/ModrinthPackManifest.h" + #include -namespace Ui -{ - class ModrinthPage; +namespace Ui { +class ModrinthPage; +} + +namespace Modrinth { +class ModpackListModel; } -class ModrinthPage : public QWidget, public BasePage -{ +class ModrinthPage : public QWidget, public BasePage { Q_OBJECT -public: - explicit ModrinthPage(NewInstanceDialog *dialog, QWidget *parent = nullptr); + public: + explicit ModrinthPage(NewInstanceDialog* dialog, QWidget* parent = nullptr); ~ModrinthPage() override; - QString displayName() const override - { - return tr("Modrinth"); - } - QIcon icon() const override - { - return APPLICATION->getThemedIcon("modrinth"); - } - QString id() const override - { - return "modrinth"; - } - - virtual QString helpPage() const override - { - return "Modrinth-platform"; - } - void retranslate() override; + QString displayName() const override { return tr("Modrinth"); } + QIcon icon() const override { return APPLICATION->getThemedIcon("modrinth"); } + QString id() const override { return "modrinth"; } + QString helpPage() const override { return "Modrinth-platform"; } - void openedImpl() override; + inline auto debugName() const -> QString { return "Modrinth"; } + inline auto metaEntryBase() const -> QString { return "ModrinthModpacks"; }; - bool eventFilter(QObject *watched, QEvent *event) override; + auto getCurrent() -> Modrinth::Modpack& { return current; } + void suggestCurrent(); -private slots: + void updateUI(); + void updateVersionsUI(); + + void retranslate() override; + void openedImpl() override; + bool eventFilter(QObject* watched, QEvent* event) override; + + private slots: + void onSelectionChanged(QModelIndex first, QModelIndex second); + void onVersionSelectionChanged(QString data); void triggerSearch(); -private: - Ui::ModrinthPage *ui; - NewInstanceDialog *dialog; + private: + Ui::ModrinthPage* ui; + NewInstanceDialog* dialog; + Modrinth::ModpackListModel* m_model; + + Modrinth::Modpack current; + QString selectedVersion; }; -- cgit From 9dd70ca9ae6fdab913a77467e803bf90ddd949ed Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 20:26:20 -0300 Subject: fix: download icon as well when importing modrinth modpacks --- launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 3 +++ launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui | 3 +++ 2 files changed, 6 insertions(+) (limited to 'launcher/ui/pages') diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 68805316..b21fdf4a 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -253,6 +253,9 @@ void ModrinthPage::suggestCurrent() for (auto& ver : current.versions) { if (ver.id == selectedVersion) { dialog->setSuggestedPack(current.name, new InstanceImportTask(ver.download_url)); + auto iconName = current.iconName; + m_model->getLogo(iconName, current.iconUrl.toString(), + [this, iconName](QString logo) { dialog->setSuggestedIconFromFile(logo, iconName); }); break; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui index 7ef099d3..8de53a69 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui @@ -45,6 +45,9 @@ 48 + + true + -- cgit From 5ea8cec16f6dfbaeaca56ccf7f9151039a1dd145 Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 21:29:48 -0300 Subject: fix: make all modrinth modpacks have the same icon size --- .../ui/pages/modplatform/modrinth/ModrinthModel.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'launcher/ui/pages') diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 2890e27d..121f5d4e 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -49,9 +49,10 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian } return pack.description; } else if (role == Qt::DecorationRole) { - // FIXME: help the icons dont have the same size ;-; if (m_logoMap.contains(pack.iconName)) { - return (m_logoMap.value(pack.iconName)); + return (m_logoMap.value(pack.iconName) + .pixmap(48, 48) + .scaled(48, 48, Qt::IgnoreAspectRatio, Qt::TransformationMode::SmoothTransformation)); } QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder"); ((ModpackListModel*)this)->requestLogo(pack.iconName, pack.iconUrl.toString()); @@ -65,14 +66,6 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian return {}; } -/* -void ModpackListModel::requestModVersions(ModPlatform::IndexedPack const& current) -{ - auto profile = (dynamic_cast((dynamic_cast(parent()))->m_instance))->getPackProfile(); - - m_parent->apiProvider()->getVersions(this, { current.addonId.toString(), getMineVersions(), profile->getModLoader() }); -}*/ - void ModpackListModel::performPaginatedSearch() { // TODO: Move to standalone API @@ -86,7 +79,7 @@ void ModpackListModel::performPaginatedSearch() netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), &m_all_response)); QObject::connect(netJob, &NetJob::succeeded, this, [this] { - QJsonParseError parse_error_all {}; + QJsonParseError parse_error_all{}; QJsonDocument doc_all = QJsonDocument::fromJson(m_all_response, &parse_error_all); if (parse_error_all.error != QJsonParseError::NoError) { @@ -210,7 +203,7 @@ void ModpackListModel::searchRequestFinished(QJsonDocument& doc_all) continue; } } - + if (packs_all.size() < 25) { searchState = Finished; } else { -- cgit From 9899a0e098e5cfb76a754fa9da2f73be46cc880a Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 21:47:35 -0300 Subject: fix: Have the URL be the project URL itself (I think, doesn't seem to work for the waffle though, probably because of the staging API :/) --- launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'launcher/ui/pages') diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index b21fdf4a..cf519b8c 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -219,7 +219,7 @@ void ModrinthPage::updateUI() if (current.extra.sourceUrl.isEmpty()) text = current.name; else - text = "" + current.name + ""; + text = "" + current.name + ""; if (!current.authors.empty()) { // TODO: Implement multiple authors with links -- cgit From 365cc198ba1e4e8129c95291e60e2c3c7ffbbf7a Mon Sep 17 00:00:00 2001 From: flow Date: Sat, 14 May 2022 21:50:54 -0300 Subject: refactor: some random improvements --- launcher/ui/pages/modplatform/ImportPage.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'launcher/ui/pages') diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 3b65de9d..c86d02ca 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -110,7 +110,10 @@ void ImportPage::updateState() //