aboutsummaryrefslogtreecommitdiff
path: root/launcher/ui
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/ui')
-rw-r--r--launcher/ui/MainWindow.cpp18
-rw-r--r--launcher/ui/MainWindow.h2
-rw-r--r--launcher/ui/dialogs/ModDownloadDialog.cpp53
-rw-r--r--launcher/ui/dialogs/ModDownloadDialog.h9
-rw-r--r--launcher/ui/dialogs/ReviewMessageBox.cpp31
-rw-r--r--launcher/ui/dialogs/ReviewMessageBox.h23
-rw-r--r--launcher/ui/dialogs/ReviewMessageBox.ui98
-rw-r--r--launcher/ui/pages/global/LauncherPage.cpp16
-rw-r--r--launcher/ui/pages/global/LauncherPage.ui12
-rw-r--r--launcher/ui/pages/instance/LegacyUpgradePage.cpp51
-rw-r--r--launcher/ui/pages/instance/LegacyUpgradePage.h64
-rw-r--r--launcher/ui/pages/instance/LegacyUpgradePage.ui54
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.cpp15
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.ui2
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModModel.cpp4
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModPage.cpp345
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModPage.h3
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModPage.ui179
-rw-r--r--launcher/ui/pages/modplatform/flame/FlamePage.cpp16
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp319
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthPage.h3
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui179
-rw-r--r--launcher/ui/widgets/PageContainer.cpp3
23 files changed, 811 insertions, 688 deletions
diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp
index a3da64e4..7b758e05 100644
--- a/launcher/ui/MainWindow.cpp
+++ b/launcher/ui/MainWindow.cpp
@@ -233,6 +233,7 @@ public:
TranslatedToolButton helpMenuButton;
TranslatedAction actionReportBug;
TranslatedAction actionDISCORD;
+ TranslatedAction actionMATRIX;
TranslatedAction actionREDDIT;
TranslatedAction actionAbout;
@@ -341,13 +342,23 @@ public:
all_actions.append(&actionReportBug);
helpMenu->addAction(actionReportBug);
}
+
+ if(!BuildConfig.MATRIX_URL.isEmpty()) {
+ actionMATRIX = TranslatedAction(MainWindow);
+ actionMATRIX->setObjectName(QStringLiteral("actionMATRIX"));
+ actionMATRIX->setIcon(APPLICATION->getThemedIcon("matrix"));
+ actionMATRIX.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Matrix"));
+ actionMATRIX.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open %1 Matrix space"));
+ all_actions.append(&actionMATRIX);
+ helpMenu->addAction(actionMATRIX);
+ }
if (!BuildConfig.DISCORD_URL.isEmpty()) {
actionDISCORD = TranslatedAction(MainWindow);
actionDISCORD->setObjectName(QStringLiteral("actionDISCORD"));
actionDISCORD->setIcon(APPLICATION->getThemedIcon("discord"));
actionDISCORD.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Discord"));
- actionDISCORD.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open %1 discord voice chat."));
+ actionDISCORD.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open %1 Discord guild."));
all_actions.append(&actionDISCORD);
helpMenu->addAction(actionDISCORD);
}
@@ -1469,6 +1480,11 @@ void MainWindow::on_actionDISCORD_triggered()
DesktopServices::openUrl(QUrl(BuildConfig.DISCORD_URL));
}
+void MainWindow::on_actionMATRIX_triggered()
+{
+ DesktopServices::openUrl(QUrl(BuildConfig.MATRIX_URL));
+}
+
void MainWindow::on_actionChangeInstIcon_triggered()
{
if (!m_selectedInstance)
diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h
index fd65620e..f2852d78 100644
--- a/launcher/ui/MainWindow.h
+++ b/launcher/ui/MainWindow.h
@@ -72,6 +72,8 @@ private slots:
void on_actionREDDIT_triggered();
+ void on_actionMATRIX_triggered();
+
void on_actionDISCORD_triggered();
void on_actionCopyInstance_triggered();
diff --git a/launcher/ui/dialogs/ModDownloadDialog.cpp b/launcher/ui/dialogs/ModDownloadDialog.cpp
index 6b807b8c..a53f93e8 100644
--- a/launcher/ui/dialogs/ModDownloadDialog.cpp
+++ b/launcher/ui/dialogs/ModDownloadDialog.cpp
@@ -5,6 +5,7 @@
#include <InstanceList.h>
#include "ProgressDialog.h"
+#include "ReviewMessageBox.h"
#include <QLayout>
#include <QPushButton>
@@ -39,9 +40,10 @@ ModDownloadDialog::ModDownloadDialog(const std::shared_ptr<ModFolderModel> &mods
// Bonk Qt over its stupid head and make sure it understands which button is the default one...
// See: https://stackoverflow.com/questions/24556831/qbuttonbox-set-default-button
auto OkButton = m_buttons->button(QDialogButtonBox::Ok);
+ OkButton->setEnabled(false);
OkButton->setDefault(true);
OkButton->setAutoDefault(true);
- connect(OkButton, &QPushButton::clicked, this, &ModDownloadDialog::accept);
+ connect(OkButton, &QPushButton::clicked, this, &ModDownloadDialog::confirm);
auto CancelButton = m_buttons->button(QDialogButtonBox::Cancel);
CancelButton->setDefault(false);
@@ -52,6 +54,7 @@ ModDownloadDialog::ModDownloadDialog(const std::shared_ptr<ModFolderModel> &mods
HelpButton->setDefault(false);
HelpButton->setAutoDefault(false);
connect(HelpButton, &QPushButton::clicked, m_container, &PageContainer::help);
+
QMetaObject::connectSlotsByName(this);
setWindowModality(Qt::WindowModal);
setWindowTitle("Download mods");
@@ -67,6 +70,25 @@ void ModDownloadDialog::reject()
QDialog::reject();
}
+void ModDownloadDialog::confirm()
+{
+ auto keys = modTask.keys();
+ keys.sort(Qt::CaseInsensitive);
+
+ auto confirm_dialog = ReviewMessageBox::create(
+ this,
+ tr("Confirm mods to download")
+ );
+
+ for(auto task : keys){
+ confirm_dialog->appendMod(task, modTask.find(task).value()->getFilename());
+ }
+
+ connect(confirm_dialog, &QDialog::accepted, this, &ModDownloadDialog::accept);
+
+ confirm_dialog->open();
+}
+
void ModDownloadDialog::accept()
{
QDialog::accept();
@@ -83,16 +105,35 @@ QList<BasePage *> ModDownloadDialog::getPages()
};
}
-void ModDownloadDialog::setSuggestedMod(const QString& name, ModDownloadTask* task)
+void ModDownloadDialog::addSelectedMod(const QString& name, ModDownloadTask* task)
+{
+ removeSelectedMod(name);
+ modTask.insert(name, task);
+
+ m_buttons->button(QDialogButtonBox::Ok)->setEnabled(!modTask.isEmpty());
+}
+
+void ModDownloadDialog::removeSelectedMod(const QString &name)
+{
+ if(modTask.contains(name))
+ delete modTask.find(name).value();
+ modTask.remove(name);
+
+ m_buttons->button(QDialogButtonBox::Ok)->setEnabled(!modTask.isEmpty());
+}
+
+bool ModDownloadDialog::isModSelected(const QString &name, const QString& filename) const
{
- modTask.reset(task);
- m_buttons->button(QDialogButtonBox::Ok)->setEnabled(task);
+ // FIXME: Is there a way to check for versions without checking the filename
+ // as a heuristic, other than adding such info to ModDownloadTask itself?
+ auto iter = modTask.find(name);
+ return iter != modTask.end() && (iter.value()->getFilename() == filename);
}
ModDownloadDialog::~ModDownloadDialog()
{
}
-ModDownloadTask *ModDownloadDialog::getTask() {
- return modTask.release();
+const QList<ModDownloadTask*> ModDownloadDialog::getTasks() {
+ return modTask.values();
}
diff --git a/launcher/ui/dialogs/ModDownloadDialog.h b/launcher/ui/dialogs/ModDownloadDialog.h
index ece8e328..309d89d0 100644
--- a/launcher/ui/dialogs/ModDownloadDialog.h
+++ b/launcher/ui/dialogs/ModDownloadDialog.h
@@ -29,12 +29,15 @@ public:
QString dialogTitle() override;
QList<BasePage *> getPages() override;
- void setSuggestedMod(const QString & name = QString(), ModDownloadTask * task = nullptr);
+ void addSelectedMod(const QString & name = QString(), ModDownloadTask * task = nullptr);
+ void removeSelectedMod(const QString & name = QString());
+ bool isModSelected(const QString & name, const QString & filename) const;
- ModDownloadTask * getTask();
+ const QList<ModDownloadTask*> getTasks();
const std::shared_ptr<ModFolderModel> &mods;
public slots:
+ void confirm();
void accept() override;
void reject() override;
@@ -49,6 +52,6 @@ private:
ModrinthPage *modrinthPage = nullptr;
FlameModPage *flameModPage = nullptr;
- std::unique_ptr<ModDownloadTask> modTask;
+ QHash<QString, ModDownloadTask*> modTask;
BaseInstance *m_instance;
};
diff --git a/launcher/ui/dialogs/ReviewMessageBox.cpp b/launcher/ui/dialogs/ReviewMessageBox.cpp
new file mode 100644
index 00000000..2bfd02e0
--- /dev/null
+++ b/launcher/ui/dialogs/ReviewMessageBox.cpp
@@ -0,0 +1,31 @@
+#include "ReviewMessageBox.h"
+#include "ui_ReviewMessageBox.h"
+
+ReviewMessageBox::ReviewMessageBox(QWidget* parent, QString const& title, QString const& icon)
+ : QDialog(parent), ui(new Ui::ReviewMessageBox)
+{
+ ui->setupUi(this);
+}
+
+ReviewMessageBox::~ReviewMessageBox()
+{
+ delete ui;
+}
+
+auto ReviewMessageBox::create(QWidget* parent, QString&& title, QString&& icon) -> ReviewMessageBox*
+{
+ return new ReviewMessageBox(parent, title, icon);
+}
+
+void ReviewMessageBox::appendMod(const QString& name, const QString& filename)
+{
+ auto itemTop = new QTreeWidgetItem(ui->modTreeWidget);
+ itemTop->setText(0, name);
+
+ auto filenameItem = new QTreeWidgetItem(itemTop);
+ filenameItem->setText(0, tr("Filename: %1").arg(filename));
+
+ itemTop->insertChildren(0, { filenameItem });
+
+ ui->modTreeWidget->addTopLevelItem(itemTop);
+}
diff --git a/launcher/ui/dialogs/ReviewMessageBox.h b/launcher/ui/dialogs/ReviewMessageBox.h
new file mode 100644
index 00000000..48742cd9
--- /dev/null
+++ b/launcher/ui/dialogs/ReviewMessageBox.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <QDialog>
+
+namespace Ui {
+class ReviewMessageBox;
+}
+
+class ReviewMessageBox final : public QDialog {
+ Q_OBJECT
+
+ public:
+ static auto create(QWidget* parent, QString&& title, QString&& icon = "") -> ReviewMessageBox*;
+
+ void appendMod(const QString& name, const QString& filename);
+
+ ~ReviewMessageBox();
+
+ private:
+ ReviewMessageBox(QWidget* parent, const QString& title, const QString& icon);
+
+ Ui::ReviewMessageBox* ui;
+};
diff --git a/launcher/ui/dialogs/ReviewMessageBox.ui b/launcher/ui/dialogs/ReviewMessageBox.ui
new file mode 100644
index 00000000..d04f3b3f
--- /dev/null
+++ b/launcher/ui/dialogs/ReviewMessageBox.ui
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ReviewMessageBox</class>
+ <widget class="QDialog" name="ReviewMessageBox">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Confirm mod selection</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>You're about to download the following mods:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QTreeWidget" name="modTreeWidget">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectItems</enum>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string/>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ReviewMessageBox</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>200</x>
+ <y>265</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>149</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ReviewMessageBox</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>200</x>
+ <y>265</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>149</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp
index 9e1d761b..ee68cd08 100644
--- a/launcher/ui/pages/global/LauncherPage.cpp
+++ b/launcher/ui/pages/global/LauncherPage.cpp
@@ -242,16 +242,16 @@ void LauncherPage::applySettings()
switch (ui->themeComboBox->currentIndex())
{
case 0:
- s->set("IconTheme", "pe_dark");
+ s->set("IconTheme", "pe_colored");
break;
case 1:
s->set("IconTheme", "pe_light");
break;
case 2:
- s->set("IconTheme", "pe_blue");
+ s->set("IconTheme", "pe_dark");
break;
case 3:
- s->set("IconTheme", "pe_colored");
+ s->set("IconTheme", "pe_blue");
break;
case 4:
s->set("IconTheme", "OSX");
@@ -263,10 +263,10 @@ void LauncherPage::applySettings()
s->set("IconTheme", "flat");
break;
case 7:
- s->set("IconTheme", "custom");
+ s->set("IconTheme", "multimc");
break;
case 8:
- s->set("IconTheme", "multimc");
+ s->set("IconTheme", "custom");
break;
}
@@ -319,7 +319,7 @@ void LauncherPage::loadSettings()
m_currentUpdateChannel = s->get("UpdateChannel").toString();
//FIXME: make generic
auto theme = s->get("IconTheme").toString();
- if (theme == "pe_dark")
+ if (theme == "pe_colored")
{
ui->themeComboBox->setCurrentIndex(0);
}
@@ -327,11 +327,11 @@ void LauncherPage::loadSettings()
{
ui->themeComboBox->setCurrentIndex(1);
}
- else if (theme == "pe_blue")
+ else if (theme == "pe_dark")
{
ui->themeComboBox->setCurrentIndex(2);
}
- else if (theme == "pe_colored")
+ else if (theme == "pe_blue")
{
ui->themeComboBox->setCurrentIndex(3);
}
diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui
index 6f68d0dd..c110dd09 100644
--- a/launcher/ui/pages/global/LauncherPage.ui
+++ b/launcher/ui/pages/global/LauncherPage.ui
@@ -245,7 +245,7 @@
</property>
<item>
<property name="text">
- <string>Simple (Dark Icons)</string>
+ <string>Simple (Colored Icons)</string>
</property>
</item>
<item>
@@ -255,12 +255,12 @@
</item>
<item>
<property name="text">
- <string>Simple (Blue Icons)</string>
+ <string>Simple (Dark Icons)</string>
</property>
</item>
<item>
<property name="text">
- <string>Simple (Colored Icons)</string>
+ <string>Simple (Blue Icons)</string>
</property>
</item>
<item>
@@ -275,17 +275,17 @@
</item>
<item>
<property name="text">
- <string notr="true">Flat</string>
+ <string>Flat</string>
</property>
</item>
<item>
<property name="text">
- <string>Custom</string>
+ <string>Legacy</string>
</property>
</item>
<item>
<property name="text">
- <string>MultiMC</string>
+ <string>Custom</string>
</property>
</item>
</widget>
diff --git a/launcher/ui/pages/instance/LegacyUpgradePage.cpp b/launcher/ui/pages/instance/LegacyUpgradePage.cpp
deleted file mode 100644
index cb78af02..00000000
--- a/launcher/ui/pages/instance/LegacyUpgradePage.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "LegacyUpgradePage.h"
-#include "ui_LegacyUpgradePage.h"
-
-#include "InstanceList.h"
-#include "minecraft/legacy/LegacyInstance.h"
-#include "minecraft/legacy/LegacyUpgradeTask.h"
-#include "Application.h"
-
-#include "ui/dialogs/CustomMessageBox.h"
-#include "ui/dialogs/ProgressDialog.h"
-
-LegacyUpgradePage::LegacyUpgradePage(InstancePtr inst, QWidget *parent)
- : QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst)
-{
- ui->setupUi(this);
-}
-
-LegacyUpgradePage::~LegacyUpgradePage()
-{
- delete ui;
-}
-
-void LegacyUpgradePage::runModalTask(Task *task)
-{
- connect(task, &Task::failed, [this](QString reason)
- {
- CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Warning)->show();
- });
- ProgressDialog loadDialog(this);
- loadDialog.setSkipButton(true, tr("Abort"));
- if(loadDialog.execWithTask(task) == QDialog::Accepted)
- {
- m_container->requestClose();
- }
-}
-
-void LegacyUpgradePage::on_upgradeButton_clicked()
-{
- QString newName = tr("%1 (Migrated)").arg(m_inst->name());
- auto upgradeTask = new LegacyUpgradeTask(m_inst);
- upgradeTask->setName(newName);
- upgradeTask->setGroup(APPLICATION->instances()->getInstanceGroup(m_inst->id()));
- upgradeTask->setIcon(m_inst->iconKey());
- unique_qobject_ptr<Task> task(APPLICATION->instances()->wrapInstanceTask(upgradeTask));
- runModalTask(task.get());
-}
-
-bool LegacyUpgradePage::shouldDisplay() const
-{
- return !m_inst->isRunning();
-}
diff --git a/launcher/ui/pages/instance/LegacyUpgradePage.h b/launcher/ui/pages/instance/LegacyUpgradePage.h
deleted file mode 100644
index 7c51956b..00000000
--- a/launcher/ui/pages/instance/LegacyUpgradePage.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* 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 <QWidget>
-
-#include "minecraft/legacy/LegacyInstance.h"
-#include "ui/pages/BasePage.h"
-#include <Application.h>
-#include "tasks/Task.h"
-
-namespace Ui
-{
-class LegacyUpgradePage;
-}
-
-class LegacyUpgradePage : public QWidget, public BasePage
-{
- Q_OBJECT
-
-public:
- explicit LegacyUpgradePage(InstancePtr inst, QWidget *parent = 0);
- virtual ~LegacyUpgradePage();
- virtual QString displayName() const override
- {
- return tr("Upgrade");
- }
- virtual QIcon icon() const override
- {
- return APPLICATION->getThemedIcon("checkupdate");
- }
- virtual QString id() const override
- {
- return "upgrade";
- }
- virtual QString helpPage() const override
- {
- return "Legacy-upgrade";
- }
- virtual bool shouldDisplay() const override;
-
-private slots:
- void on_upgradeButton_clicked();
-
-private:
- void runModalTask(Task *task);
-
-private:
- Ui::LegacyUpgradePage *ui;
- InstancePtr m_inst;
-};
diff --git a/launcher/ui/pages/instance/LegacyUpgradePage.ui b/launcher/ui/pages/instance/LegacyUpgradePage.ui
deleted file mode 100644
index b22c03e5..00000000
--- a/launcher/ui/pages/instance/LegacyUpgradePage.ui
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>LegacyUpgradePage</class>
- <widget class="QWidget" name="LegacyUpgradePage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>546</width>
- <height>405</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_5">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <widget class="QTextBrowser" name="textBrowser">
- <property name="html">
- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Noto Sans'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;h1 style=&quot; margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:xx-large; font-weight:600;&quot;&gt;Upgrade is required&lt;/span&gt;&lt;/h1&gt;
-&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;PolyMC now supports old Minecraft versions and all the required features in the new (OneSix) instance format. As a consequence, the old (Legacy) format has been entirely disabled and old instances need to be upgraded.&lt;/p&gt;
-&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The upgrade will create a new instance with the same contents as the current one, in the new format. The original instance will remain untouched, in case anything goes wrong in the process.&lt;/p&gt;
-&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Please report any issues on our &lt;a href=&quot;https://github.com/PolyMC/PolyMC/issues&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#3584e4;&quot;&gt;github issues page&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="openExternalLinks">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCommandLinkButton" name="upgradeButton">
- <property name="text">
- <string>Upgrade the instance</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp
index 494d32f0..ffb87bbe 100644
--- a/launcher/ui/pages/instance/ModFolderPage.cpp
+++ b/launcher/ui/pages/instance/ModFolderPage.cpp
@@ -143,11 +143,19 @@ ModFolderPage::ModFolderPage(
ui(new Ui::ModFolderPage)
{
ui->setupUi(this);
+
+ // This is structured like that so that these changes
+ // do not affect the Resouce pack and Shader pack tabs
if(id == "mods") {
- auto act = new QAction(tr("Install Mods"), this);
- ui->actionsToolbar->insertActionBefore(ui->actionView_configs,act);
+ auto act = new QAction(tr("Download mods"), this);
+ act->setToolTip(tr("Download mods from online mod platforms"));
+ ui->actionsToolbar->insertActionBefore(ui->actionAdd, act);
connect(act, &QAction::triggered, this, &ModFolderPage::on_actionInstall_mods_triggered);
+
+ ui->actionAdd->setText(tr("Add .jar"));
+ ui->actionAdd->setToolTip(tr("Add mods via local file"));
}
+
ui->actionsToolbar->insertSpacer(ui->actionView_configs);
m_inst = inst;
@@ -365,8 +373,7 @@ void ModFolderPage::on_actionInstall_mods_triggered()
}
ModDownloadDialog mdownload(m_mods, this, m_inst);
if(mdownload.exec()) {
- ModDownloadTask *task = mdownload.getTask();
- if (task) {
+ for(auto task : mdownload.getTasks()){
connect(task, &Task::failed, [this, task](QString reason) {
task->deleteLater();
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
diff --git a/launcher/ui/pages/instance/ModFolderPage.ui b/launcher/ui/pages/instance/ModFolderPage.ui
index 0fb51e84..ab59b0df 100644
--- a/launcher/ui/pages/instance/ModFolderPage.ui
+++ b/launcher/ui/pages/instance/ModFolderPage.ui
@@ -96,7 +96,7 @@
<string>&amp;Add</string>
</property>
<property name="toolTip">
- <string>Add mods</string>
+ <string>Add</string>
</property>
</action>
<action name="actionRemove">
diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp
index 2cf83261..e8afba5a 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp
@@ -175,13 +175,13 @@ void ListModel::performPaginatedSearch()
"pageSize=25&"
"searchFilter=%2&"
"sort=%3&"
- "%4"
+ "modLoaderType=%4&"
"gameVersion=%5"
)
.arg(nextSearchOffset)
.arg(currentSearchTerm)
.arg(sorts[currentSort])
- .arg(hasFabric ? "modLoaderType=4&" : "")
+ .arg(hasFabric ? 4 : 1) // Enum: https://docs.curseforge.com/?http#tocS_ModLoaderType
.arg(mcVersion);
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
index a816c681..114ac907 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
@@ -4,193 +4,214 @@
#include <QKeyEvent>
#include "Application.h"
-#include "Json.h"
-#include "ui/dialogs/ModDownloadDialog.h"
-#include "InstanceImportTask.h"
#include "FlameModModel.h"
+#include "InstanceImportTask.h"
+#include "Json.h"
#include "ModDownloadTask.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
+#include "ui/dialogs/ModDownloadDialog.h"
FlameModPage::FlameModPage(ModDownloadDialog *dialog, BaseInstance *instance)
- : QWidget(dialog), m_instance(instance), ui(new Ui::FlameModPage), dialog(dialog)
-{
- ui->setupUi(this);
- connect(ui->searchButton, &QPushButton::clicked, this, &FlameModPage::triggerSearch);
- ui->searchEdit->installEventFilter(this);
- listModel = new FlameMod::ListModel(this);
- ui->packView->setModel(listModel);
-
- ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300);
-
- // index is used to set the sorting with the flame api
- 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 Downloads"));
-
- connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch()));
- connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameModPage::onSelectionChanged);
- connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FlameModPage::onVersionSelectionChanged);
+ : QWidget(dialog), m_instance(instance), ui(new Ui::FlameModPage),
+ dialog(dialog) {
+ ui->setupUi(this);
+ connect(ui->searchButton, &QPushButton::clicked, this,
+ &FlameModPage::triggerSearch);
+ ui->searchEdit->installEventFilter(this);
+ listModel = new FlameMod::ListModel(this);
+ ui->packView->setModel(listModel);
+
+ ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(
+ Qt::ScrollBarAsNeeded);
+ ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300);
+
+ // index is used to set the sorting with the flame api
+ 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 Downloads"));
+
+ connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(triggerSearch()));
+ connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged,
+ this, &FlameModPage::onSelectionChanged);
+ connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this,
+ &FlameModPage::onVersionSelectionChanged);
+ connect(ui->modSelectionButton, &QPushButton::clicked, this,
+ &FlameModPage::onModSelected);
}
-FlameModPage::~FlameModPage()
-{
- delete ui;
-}
+FlameModPage::~FlameModPage() { delete ui; }
-bool FlameModPage::eventFilter(QObject* watched, QEvent* event)
-{
- if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) {
- QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
- if (keyEvent->key() == Qt::Key_Return) {
- triggerSearch();
- keyEvent->accept();
- return true;
- }
+bool FlameModPage::eventFilter(QObject *watched, QEvent *event) {
+ if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+ if (keyEvent->key() == Qt::Key_Return) {
+ triggerSearch();
+ keyEvent->accept();
+ return true;
}
- return QWidget::eventFilter(watched, event);
+ }
+ return QWidget::eventFilter(watched, event);
}
-bool FlameModPage::shouldDisplay() const
-{
- return true;
-}
+bool FlameModPage::shouldDisplay() const { return true; }
-void FlameModPage::openedImpl()
-{
- suggestCurrent();
- triggerSearch();
+void FlameModPage::openedImpl() {
+ updateSelectionButton();
+ triggerSearch();
}
-void FlameModPage::triggerSearch()
-{
- listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex());
+void FlameModPage::triggerSearch() {
+ listModel->searchWithTerm(ui->searchEdit->text(),
+ ui->sortByBox->currentIndex());
}
-void FlameModPage::onSelectionChanged(QModelIndex first, QModelIndex second)
-{
- ui->versionSelectionBox->clear();
-
- if(!first.isValid())
- {
- if(isOpened)
- {
- dialog->setSuggestedMod();
+void FlameModPage::onSelectionChanged(QModelIndex first, QModelIndex second) {
+ ui->versionSelectionBox->clear();
+
+ if (!first.isValid()) {
+ return;
+ }
+
+ current = listModel->data(first, Qt::UserRole).value<FlameMod::IndexedPack>();
+ QString text = "";
+ QString name = current.name;
+
+ if (current.websiteUrl.isEmpty())
+ text = name;
+ else
+ text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>";
+ if (!current.authors.empty()) {
+ auto authorToStr = [](FlameMod::ModpackAuthor &author) {
+ if (author.url.isEmpty()) {
+ return author.name;
+ }
+ return QString("<a href=\"%1\">%2</a>").arg(author.url, author.name);
+ };
+ QStringList authorStrs;
+ for (auto &author : current.authors) {
+ authorStrs.push_back(authorToStr(author));
+ }
+ text += "<br>" + tr(" by ") + authorStrs.join(", ");
+ }
+ text += "<br><br>";
+
+ ui->packDescription->setHtml(text + current.description);
+
+ if (!current.versionsLoaded) {
+ qDebug() << "Loading flame mod versions";
+
+ ui->modSelectionButton->setText(tr("Loading versions..."));
+ ui->modSelectionButton->setEnabled(false);
+
+ auto netJob =
+ new NetJob(QString("Flame::ModVersions(%1)").arg(current.name),
+ APPLICATION->network());
+ auto response = new QByteArray();
+ int addonId = current.addonId;
+ netJob->addNetAction(Net::Download::makeByteArray(
+ QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files")
+ .arg(addonId),
+ response));
+
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId] {
+ if(addonId != current.addonId){
+ 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 Flame at "
+ << parse_error.offset
+ << " reason: " << parse_error.errorString();
+ qWarning() << *response;
return;
- }
-
- current = listModel->data(first, Qt::UserRole).value<FlameMod::IndexedPack>();
- QString text = "";
- QString name = current.name;
-
- if (current.websiteUrl.isEmpty())
- text = name;
- else
- text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>";
- if (!current.authors.empty()) {
- auto authorToStr = [](FlameMod::ModpackAuthor & author) {
- if(author.url.isEmpty()) {
- return author.name;
- }
- return QString("<a href=\"%1\">%2</a>").arg(author.url, author.name);
- };
- QStringList authorStrs;
- for(auto & author: current.authors) {
- authorStrs.push_back(authorToStr(author));
+ }
+ QJsonArray arr = doc.array();
+ try {
+ FlameMod::loadIndexedPackVersions(current, arr, APPLICATION->network(),
+ m_instance);
+ } catch (const JSONValidationError &e) {
+ qDebug() << *response;
+ qWarning() << "Error while reading Flame mod version: " << e.cause();
+ }
+ auto packProfile = ((MinecraftInstance *)m_instance)->getPackProfile();
+ QString mcVersion = packProfile->getComponentVersion("net.minecraft");
+ QString loaderString =
+ (packProfile->getComponentVersion("net.minecraftforge").isEmpty())
+ ? "fabric"
+ : "forge";
+ for (int i = 0; i < current.versions.size(); i++) {
+ auto version = current.versions[i];
+ if (!version.mcVersion.contains(mcVersion)) {
+ continue;
}
- text += "<br>" + tr(" by ") + authorStrs.join(", ");
+ ui->versionSelectionBox->addItem(version.version, QVariant(i));
+ }
+ if (ui->versionSelectionBox->count() == 0) {
+ ui->versionSelectionBox->addItem(tr("No Valid Version found!"),
+ QVariant(-1));
+ }
+
+ ui->modSelectionButton->setText(tr("Cannot select invalid version :("));
+ updateSelectionButton();
+ });
+ QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
+ netJob->deleteLater();
+ delete response;
+ });
+ netJob->start();
+ } else {
+ for (int i = 0; i < current.versions.size(); i++) {
+ ui->versionSelectionBox->addItem(current.versions[i].version,
+ QVariant(i));
}
- text += "<br><br>";
-
- ui->packDescription->setHtml(text + current.description);
-
- if (!current.versionsLoaded)
- {
- qDebug() << "Loading flame mod versions";
- auto netJob = new NetJob(QString("Flame::ModVersions(%1)").arg(current.name), APPLICATION->network());
- std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
- int addonId = current.addonId;
- netJob->addNetAction(Net::Download::makeByteArray(QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId), response.get()));
-
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response, netJob]
- {
- netJob->deleteLater();
- QJsonParseError parse_error;
- QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
- if(parse_error.error != QJsonParseError::NoError) {
- qWarning() << "Error while parsing JSON response from Flame at " << parse_error.offset << " reason: " << parse_error.errorString();
- qWarning() << *response;
- return;
- }
- QJsonArray arr = doc.array();
- try
- {
- FlameMod::loadIndexedPackVersions(current, arr, APPLICATION->network(), m_instance);
- }
- catch(const JSONValidationError &e)
- {
- qDebug() << *response;
- qWarning() << "Error while reading Flame mod version: " << e.cause();
- }
- auto packProfile = ((MinecraftInstance *)m_instance)->getPackProfile();
- QString mcVersion = packProfile->getComponentVersion("net.minecraft");
- QString loaderString = (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) ? "fabric" : "forge";
- for(int i = 0; i < current.versions.size(); i++) {
- auto version = current.versions[i];
- if(!version.mcVersion.contains(mcVersion)){
- continue;
- }
- ui->versionSelectionBox->addItem(version.version, QVariant(i));
- }
- if(ui->versionSelectionBox->count() == 0){
- ui->versionSelectionBox->addItem(tr("No Valid Version found!"), QVariant(-1));
- }
-
- suggestCurrent();
- });
- netJob->start();
+ if (ui->versionSelectionBox->count() == 0) {
+ ui->versionSelectionBox->addItem(tr("No Valid Version found!"),
+ QVariant(-1));
}
- else
- {
- for(int i = 0; i < current.versions.size(); i++) {
- ui->versionSelectionBox->addItem(current.versions[i].version, QVariant(i));
- }
- if(ui->versionSelectionBox->count() == 0){
- ui->versionSelectionBox->addItem(tr("No Valid Version found!"), QVariant(-1));
- }
- suggestCurrent();
- }
-}
-void FlameModPage::suggestCurrent()
-{
- if(!isOpened)
- {
- return;
- }
+ updateSelectionButton();
+ }
+}
- if (selectedVersion == -1)
- {
- dialog->setSuggestedMod();
- return;
- }
+void FlameModPage::updateSelectionButton() {
+ if (!isOpened || selectedVersion < 0) {
+ ui->modSelectionButton->setEnabled(false);
+ return;
+ }
+
+ ui->modSelectionButton->setEnabled(true);
+ auto &version = current.versions[selectedVersion];
+ if (!dialog->isModSelected(current.name, version.fileName)) {
+ ui->modSelectionButton->setText(tr("Select mod for download"));
+ } else {
+ ui->modSelectionButton->setText(tr("Deselect mod for download"));
+ }
+}
- auto version = current.versions[selectedVersion];
- dialog->setSuggestedMod(current.name, new ModDownloadTask(version.downloadUrl, version.fileName , dialog->mods));
+void FlameModPage::onVersionSelectionChanged(QString data) {
+ if (data.isNull() || data.isEmpty()) {
+ selectedVersion = -1;
+ return;
+ }
+ selectedVersion = ui->versionSelectionBox->currentData().toInt();
+ updateSelectionButton();
}
-void FlameModPage::onVersionSelectionChanged(QString data)
-{
- if(data.isNull() || data.isEmpty())
- {
- selectedVersion = -1;
- return;
- }
- selectedVersion = ui->versionSelectionBox->currentData().toInt();
- suggestCurrent();
+void FlameModPage::onModSelected() {
+ auto &version = current.versions[selectedVersion];
+ if (dialog->isModSelected(current.name, version.fileName)) {
+ dialog->removeSelectedMod(current.name);
+ } else {
+ dialog->addSelectedMod(current.name,
+ new ModDownloadTask(version.downloadUrl,
+ version.fileName, dialog->mods));
+ }
+
+ updateSelectionButton();
}
diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h
index 8fa3248a..b5b19a4f 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModPage.h
+++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h
@@ -50,12 +50,13 @@ public:
BaseInstance *m_instance;
private:
- void suggestCurrent();
+ void updateSelectionButton();
private slots:
void triggerSearch();
void onSelectionChanged(QModelIndex first, QModelIndex second);
void onVersionSelectionChanged(QString data);
+ void onModSelected();
private:
Ui::FlameModPage *ui = nullptr;
diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.ui b/launcher/ui/pages/modplatform/flame/FlameModPage.ui
index 7da0bb4a..36df7e8a 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModPage.ui
+++ b/launcher/ui/pages/modplatform/flame/FlameModPage.ui
@@ -1,90 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>FlameModPage</class>
- <widget class="QWidget" name="FlameModPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>837</width>
- <height>685</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="1" column="0" colspan="2">
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="1" column="0">
- <widget class="QListView" name="packView">
- <property name="iconSize">
- <size>
- <width>48</width>
- <height>48</height>
- </size>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="alternatingRowColors">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QTextBrowser" name="packDescription">
- <property name="openExternalLinks">
- <bool>true</bool>
- </property>
- <property name="openLinks">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="2" column="0" colspan="2">
- <layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0" rowminimumheight="0" columnminimumwidth="0,0,0">
- <item row="0" column="2">
- <widget class="QComboBox" name="versionSelectionBox"/>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Version selected:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QComboBox" name="sortByBox"/>
- </item>
- </layout>
- </item>
- <item row="0" column="1">
- <widget class="QPushButton" name="searchButton">
- <property name="text">
- <string>Search</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLineEdit" name="searchEdit">
- <property name="placeholderText">
- <string>Search and filter ...</string>
- </property>
- </widget>
- </item>
+ <class>FlameModPage</class>
+ <widget class="QWidget" name="FlameModPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>837</width>
+ <height>685</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="2" column="0" colspan="2">
+ <layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0" rowminimumheight="0,0,0" columnminimumwidth="0,0,0">
+ <item row="1" column="2">
+ <widget class="QComboBox" name="versionSelectionBox"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QComboBox" name="sortByBox"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Version selected:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="modSelectionButton">
+ <property name="text">
+ <string>Select mod for download</string>
+ </property>
+ </widget>
+ </item>
</layout>
- </widget>
- <tabstops>
- <tabstop>searchEdit</tabstop>
- <tabstop>searchButton</tabstop>
- <tabstop>packView</tabstop>
- <tabstop>packDescription</tabstop>
- <tabstop>sortByBox</tabstop>
- <tabstop>versionSelectionBox</tabstop>
- </tabstops>
- <resources/>
- <connections/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLineEdit" name="searchEdit">
+ <property name="placeholderText">
+ <string>Search and filter ...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="1" column="0">
+ <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>
+ </item>
+ <item row="1" column="1">
+ <widget class="QTextBrowser" name="packDescription">
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="openLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <widget class="QPushButton" name="searchButton">
+ <property name="text">
+ <string>Search</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>searchEdit</tabstop>
+ <tabstop>searchButton</tabstop>
+ <tabstop>packView</tabstop>
+ <tabstop>packDescription</tabstop>
+ <tabstop>sortByBox</tabstop>
+ <tabstop>versionSelectionBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
</ui>
diff --git a/launcher/ui/pages/modplatform/flame/FlamePage.cpp b/launcher/ui/pages/modplatform/flame/FlamePage.cpp
index 1138a298..7e6ac2fd 100644
--- a/launcher/ui/pages/modplatform/flame/FlamePage.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlamePage.cpp
@@ -109,13 +109,16 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
if (current.versionsLoaded == false)
{
qDebug() << "Loading flame modpack versions";
- NetJob *netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(current.name), APPLICATION->network());
- std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
+ auto netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(current.name), APPLICATION->network());
+ auto response = new QByteArray();
int addonId = current.addonId;
- netJob->addNetAction(Net::Download::makeByteArray(QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId), response.get()));
+ netJob->addNetAction(Net::Download::makeByteArray(QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId), response));
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response]
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId]
{
+ if(addonId != current.addonId){
+ return; //wrong request
+ }
QJsonParseError parse_error;
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
if(parse_error.error != QJsonParseError::NoError) {
@@ -140,6 +143,11 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
suggestCurrent();
});
+ QObject::connect(netJob, &NetJob::finished, this, [response, netJob]
+ {
+ netJob->deleteLater();
+ delete response;
+ });
netJob->start();
}
else
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
index c5a54c29..35cd743a 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
@@ -4,177 +4,202 @@
#include <QKeyEvent>
#include "Application.h"
-#include "Json.h"
-#include "ui/dialogs/ModDownloadDialog.h"
#include "InstanceImportTask.h"
-#include "ModrinthModel.h"
+#include "Json.h"
#include "ModDownloadTask.h"
+#include "ModrinthModel.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
+#include "ui/dialogs/ModDownloadDialog.h"
ModrinthPage::ModrinthPage(ModDownloadDialog *dialog, BaseInstance *instance)
- : QWidget(dialog), m_instance(instance), ui(new Ui::ModrinthPage), dialog(dialog)
-{
- ui->setupUi(this);
- connect(ui->searchButton, &QPushButton::clicked, this, &ModrinthPage::triggerSearch);
- ui->searchEdit->installEventFilter(this);
- listModel = new Modrinth::ListModel(this);
- ui->packView->setModel(listModel);
-
- ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300);
-
- // index is used to set the sorting with the modrinth api
- ui->sortByBox->addItem(tr("Sort by Relevence"));
- 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"));
-
- 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);
+ : QWidget(dialog), m_instance(instance), ui(new Ui::ModrinthPage),
+ dialog(dialog) {
+ ui->setupUi(this);
+ connect(ui->searchButton, &QPushButton::clicked, this,
+ &ModrinthPage::triggerSearch);
+ ui->searchEdit->installEventFilter(this);
+ listModel = new Modrinth::ListModel(this);
+ ui->packView->setModel(listModel);
+
+ ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(
+ Qt::ScrollBarAsNeeded);
+ ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300);
+
+ // index is used to set the sorting with the modrinth api
+ ui->sortByBox->addItem(tr("Sort by Relevence"));
+ 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"));
+
+ 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);
}
-ModrinthPage::~ModrinthPage()
-{
- delete ui;
-}
+ModrinthPage::~ModrinthPage() { delete ui; }
-bool ModrinthPage::eventFilter(QObject* watched, QEvent* event)
-{
- if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) {
- QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
- if (keyEvent->key() == Qt::Key_Return) {
- triggerSearch();
- keyEvent->accept();
- return true;
- }
+bool ModrinthPage::eventFilter(QObject *watched, QEvent *event) {
+ if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+ if (keyEvent->key() == Qt::Key_Return) {
+ triggerSearch();
+ keyEvent->accept();
+ return true;
}
- return QWidget::eventFilter(watched, event);
+ }
+ return QWidget::eventFilter(watched, event);
}
-bool ModrinthPage::shouldDisplay() const
-{
- return true;
-}
+bool ModrinthPage::shouldDisplay() const { return true; }
-void ModrinthPage::openedImpl()
-{
- suggestCurrent();
- triggerSearch();
+void ModrinthPage::openedImpl() {
+ updateSelectionButton();
+ triggerSearch();
}
-void ModrinthPage::triggerSearch()
-{
- listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex());
+void ModrinthPage::triggerSearch() {
+ listModel->searchWithTerm(ui->searchEdit->text(),
+ ui->sortByBox->currentIndex());
}
-void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
-{
- ui->versionSelectionBox->clear();
-
- if(!first.isValid())
- {
- if(isOpened)
- {
- dialog->setSuggestedMod();
+void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) {
+ ui->versionSelectionBox->clear();
+
+ if (!first.isValid()) {
+ return;
+ }
+
+ current = listModel->data(first, Qt::UserRole).value<Modrinth::IndexedPack>();
+ QString text = "";
+ QString name = current.name;
+
+ if (current.websiteUrl.isEmpty())
+ text = name;
+ else
+ text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>";
+ text += "<br>" + tr(" by ") + "<a href=\"" + current.author.url + "\">" +
+ current.author.name + "</a><br><br>";
+ ui->packDescription->setHtml(text + current.description);
+
+ if (!current.versionsLoaded) {
+ qDebug() << "Loading Modrinth mod versions";
+
+ ui->modSelectionButton->setText(tr("Loading versions..."));
+ ui->modSelectionButton->setEnabled(false);
+
+ auto netJob =
+ new NetJob(QString("Modrinth::ModVersions(%1)").arg(current.name),
+ APPLICATION->network());
+ auto response = new QByteArray();
+ QString addonId = current.addonId;
+ netJob->addNetAction(Net::Download::makeByteArray(
+ QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId),
+ response));
+
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId] {
+ if(addonId != current.addonId){
+ return;
}
+ 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;
- }
-
- current = listModel->data(first, Qt::UserRole).value<Modrinth::IndexedPack>();
- QString text = "";
- QString name = current.name;
-
- if (current.websiteUrl.isEmpty())
- text = name;
- else
- text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>";
- text += "<br>"+ tr(" by ") + "<a href=\""+current.author.url+"\">"+current.author.name+"</a><br><br>";
- ui->packDescription->setHtml(text + current.description);
-
- if (!current.versionsLoaded)
- {
- qDebug() << "Loading Modrinth mod versions";
- auto netJob = new NetJob(QString("Modrinth::ModVersions(%1)").arg(current.name), APPLICATION->network());
- std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
- QString addonId = current.addonId;
- netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId), response.get()));
-
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response, netJob]
- {
- netJob->deleteLater();
- 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;
- }
- QJsonArray arr = doc.array();
- try
- {
- Modrinth::loadIndexedPackVersions(current, arr, APPLICATION->network(), m_instance);
- }
- catch(const JSONValidationError &e)
- {
- qDebug() << *response;
- qWarning() << "Error while reading Modrinth mod version: " << e.cause();
- }
- auto packProfile = ((MinecraftInstance *)m_instance)->getPackProfile();
- QString mcVersion = packProfile->getComponentVersion("net.minecraft");
- QString loaderString = (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) ? "fabric" : "forge";
- for(int i = 0; i < current.versions.size(); i++) {
- auto version = current.versions[i];
- if(!version.mcVersion.contains(mcVersion) || !version.loaders.contains(loaderString)){
- continue;
- }
- ui->versionSelectionBox->addItem(version.version, QVariant(i));
- }
- if(ui->versionSelectionBox->count() == 0){
- ui->versionSelectionBox->addItem(tr("No Valid Version found !"), QVariant(-1));
- }
-
- suggestCurrent();
- });
- netJob->start();
- }
- else
- {
- for(int i = 0; i < current.versions.size(); i++) {
- ui->versionSelectionBox->addItem(current.versions[i].version, QVariant(i));
- }
- if(ui->versionSelectionBox->count() == 0){
- ui->versionSelectionBox->addItem(tr("No Valid Version found !"), QVariant(-1));
+ }
+ QJsonArray arr = doc.array();
+ try {
+ Modrinth::loadIndexedPackVersions(current, arr, APPLICATION->network(),
+ m_instance);
+ } catch (const JSONValidationError &e) {
+ qDebug() << *response;
+ qWarning() << "Error while reading Modrinth mod version: " << e.cause();
+ }
+ auto packProfile = ((MinecraftInstance *)m_instance)->getPackProfile();
+ QString mcVersion = packProfile->getComponentVersion("net.minecraft");
+ QString loaderString =
+ (packProfile->getComponentVersion("net.minecraftforge").isEmpty())
+ ? "fabric"
+ : "forge";
+ for (int i = 0; i < current.versions.size(); i++) {
+ auto version = current.versions[i];
+ if (!version.mcVersion.contains(mcVersion) ||
+ !version.loaders.contains(loaderString)) {
+ continue;
}
- suggestCurrent();
+ ui->versionSelectionBox->addItem(version.version, QVariant(i));
+ }
+ if (ui->versionSelectionBox->count() == 0) {
+ ui->versionSelectionBox->addItem(tr("No Valid Version found !"),
+ QVariant(-1));
+ }
+
+ ui->modSelectionButton->setText(tr("Cannot select invalid version :("));
+ updateSelectionButton();
+ });
+
+ QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
+ netJob->deleteLater();
+ delete response;
+ });
+
+ netJob->start();
+ } else {
+ for (int i = 0; i < current.versions.size(); i++) {
+ ui->versionSelectionBox->addItem(current.versions[i].version,
+ QVariant(i));
+ }
+ if (ui->versionSelectionBox->count() == 0) {
+ ui->versionSelectionBox->addItem(tr("No Valid Version found !"),
+ QVariant(-1));
}
+
+ updateSelectionButton();
+ }
}
-void ModrinthPage::suggestCurrent()
-{
- if(!isOpened)
- {
- return;
- }
+void ModrinthPage::updateSelectionButton() {
+ if (!isOpened || selectedVersion < 0) {
+ ui->modSelectionButton->setEnabled(false);
+ return;
+ }
+
+ ui->modSelectionButton->setEnabled(true);
+ auto &version = current.versions[selectedVersion];
+ if (!dialog->isModSelected(current.name, version.fileName)) {
+ ui->modSelectionButton->setText(tr("Select mod for download"));
+ } else {
+ ui->modSelectionButton->setText(tr("Deselect mod for download"));
+ }
+}
- if (selectedVersion == -1)
- {
- dialog->setSuggestedMod();
- return;
- }
- auto version = current.versions[selectedVersion];
- dialog->setSuggestedMod(current.name, new ModDownloadTask(version.downloadUrl, version.fileName , dialog->mods));
+void ModrinthPage::onVersionSelectionChanged(QString data) {
+ if (data.isNull() || data.isEmpty()) {
+ selectedVersion = -1;
+ return;
+ }
+ selectedVersion = ui->versionSelectionBox->currentData().toInt();
+ updateSelectionButton();
}
-void ModrinthPage::onVersionSelectionChanged(QString data)
-{
- if(data.isNull() || data.isEmpty())
- {
- selectedVersion = -1;
- return;
- }
- selectedVersion = ui->versionSelectionBox->currentData().toInt();
- suggestCurrent();
+void ModrinthPage::onModSelected() {
+ auto &version = current.versions[selectedVersion];
+ if (dialog->isModSelected(current.name, version.fileName)) {
+ dialog->removeSelectedMod(current.name);
+ } else {
+ dialog->addSelectedMod(current.name,
+ new ModDownloadTask(version.downloadUrl,
+ version.fileName, dialog->mods));
+ }
+
+ updateSelectionButton();
}
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h
index 3c517069..52b538e3 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h
@@ -50,12 +50,13 @@ public:
BaseInstance *m_instance;
private:
- void suggestCurrent();
+ void updateSelectionButton();
private slots:
void triggerSearch();
void onSelectionChanged(QModelIndex first, QModelIndex second);
void onVersionSelectionChanged(QString data);
+ void onModSelected();
private:
Ui::ModrinthPage *ui = nullptr;
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
index 6d183de5..d0a8b8f7 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
@@ -1,90 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>ModrinthPage</class>
- <widget class="QWidget" name="ModrinthPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>837</width>
- <height>685</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="1" column="0" colspan="2">
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="1" column="0">
- <widget class="QListView" name="packView">
- <property name="iconSize">
- <size>
- <width>48</width>
- <height>48</height>
- </size>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="alternatingRowColors">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QTextBrowser" name="packDescription">
- <property name="openExternalLinks">
- <bool>true</bool>
- </property>
- <property name="openLinks">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="2" column="0" colspan="2">
- <layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0" rowminimumheight="0" columnminimumwidth="0,0,0">
- <item row="0" column="2">
- <widget class="QComboBox" name="versionSelectionBox"/>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Version selected:</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QComboBox" name="sortByBox"/>
- </item>
- </layout>
- </item>
- <item row="0" column="1">
- <widget class="QPushButton" name="searchButton">
- <property name="text">
- <string>Search</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLineEdit" name="searchEdit">
- <property name="placeholderText">
- <string>Search and filter ...</string>
- </property>
- </widget>
- </item>
+ <class>ModrinthPage</class>
+ <widget class="QWidget" name="ModrinthPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>837</width>
+ <height>685</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0" colspan="2">
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="1" column="2">
+ <widget class="QTextBrowser" name="packDescription">
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="openLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <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>
+ </item>
</layout>
- </widget>
- <tabstops>
- <tabstop>searchEdit</tabstop>
- <tabstop>searchButton</tabstop>
- <tabstop>packView</tabstop>
- <tabstop>packDescription</tabstop>
- <tabstop>sortByBox</tabstop>
- <tabstop>versionSelectionBox</tabstop>
- </tabstops>
- <resources/>
- <connections/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QPushButton" name="searchButton">
+ <property name="text">
+ <string>Search</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLineEdit" name="searchEdit">
+ <property name="placeholderText">
+ <string>Search and filter ...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0,0">
+ <item row="0" column="2">
+ <widget class="QComboBox" name="versionSelectionBox"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Version selected:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QComboBox" name="sortByBox"/>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="modSelectionButton">
+ <property name="text">
+ <string>Select mod for download</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>searchEdit</tabstop>
+ <tabstop>searchButton</tabstop>
+ <tabstop>packView</tabstop>
+ <tabstop>packDescription</tabstop>
+ <tabstop>sortByBox</tabstop>
+ <tabstop>versionSelectionBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
</ui>
diff --git a/launcher/ui/widgets/PageContainer.cpp b/launcher/ui/widgets/PageContainer.cpp
index 6de49467..558a98fb 100644
--- a/launcher/ui/widgets/PageContainer.cpp
+++ b/launcher/ui/widgets/PageContainer.cpp
@@ -14,6 +14,7 @@
*/
#include "PageContainer.h"
+#include "BuildConfig.h"
#include "PageContainer_p.h"
#include <QStackedLayout>
@@ -207,7 +208,7 @@ void PageContainer::help()
QString pageId = m_currentPage->helpPage();
if (pageId.isEmpty())
return;
- DesktopServices::openUrl(QUrl("https://github.com/PolyMC/PolyMC/wiki/" + pageId));
+ DesktopServices::openUrl(QUrl(BuildConfig.HELP_URL.arg(pageId)));
}
}