aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
authorleo78913 <leo3758@riseup.net>2022-10-28 15:46:02 -0300
committerGitHub <noreply@github.com>2022-10-28 15:46:02 -0300
commit4500e345b37f007f9e6311637db9df0351a57dfb (patch)
treec523d60512749da628e822b579b47dda898782bc /launcher
parent43bf601f120c9b1eac1c73feb31c67df54955b6d (diff)
parente885f3c26a030d093e2c7e60770c069e4d958cff (diff)
downloadPrismLauncher-4500e345b37f007f9e6311637db9df0351a57dfb.tar.gz
PrismLauncher-4500e345b37f007f9e6311637db9df0351a57dfb.tar.bz2
PrismLauncher-4500e345b37f007f9e6311637db9df0351a57dfb.zip
Merge branch 'PrismLauncher:develop' into toolbar-icons
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp14
-rw-r--r--launcher/Application.h1
-rw-r--r--launcher/CMakeLists.txt1
-rw-r--r--launcher/FileSystem.cpp1
-rw-r--r--launcher/GZip.cpp4
-rw-r--r--launcher/HoeDown.h2
-rw-r--r--launcher/main.cpp1
-rw-r--r--launcher/modplatform/helpers/NetworkModAPI.cpp1
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackIndex.cpp55
-rw-r--r--launcher/resources/flat_white/flat_white.qrc50
-rw-r--r--launcher/resources/flat_white/index.theme11
-rw-r--r--launcher/resources/flat_white/scalable/about.svg3
-rw-r--r--launcher/resources/flat_white/scalable/accounts.svg3
-rw-r--r--launcher/resources/flat_white/scalable/bug.svg3
-rw-r--r--launcher/resources/flat_white/scalable/cat.svg3
-rw-r--r--launcher/resources/flat_white/scalable/centralmods.svg3
-rw-r--r--launcher/resources/flat_white/scalable/checkupdate.svg3
-rw-r--r--launcher/resources/flat_white/scalable/copy.svg3
-rw-r--r--launcher/resources/flat_white/scalable/coremods.svg3
-rw-r--r--launcher/resources/flat_white/scalable/custom-commands.svg86
-rw-r--r--launcher/resources/flat_white/scalable/delete.svg5
-rw-r--r--launcher/resources/flat_white/scalable/discord.svg4
-rw-r--r--launcher/resources/flat_white/scalable/export.svg5
-rw-r--r--launcher/resources/flat_white/scalable/externaltools.svg3
-rw-r--r--launcher/resources/flat_white/scalable/help.svg17
-rw-r--r--launcher/resources/flat_white/scalable/instance-settings.svg3
-rw-r--r--launcher/resources/flat_white/scalable/jarmods.svg3
-rw-r--r--launcher/resources/flat_white/scalable/java.svg3
-rw-r--r--launcher/resources/flat_white/scalable/language.svg103
-rw-r--r--launcher/resources/flat_white/scalable/launcher.svg2
-rw-r--r--launcher/resources/flat_white/scalable/loadermods.svg3
-rw-r--r--launcher/resources/flat_white/scalable/log.svg3
-rw-r--r--launcher/resources/flat_white/scalable/minecraft.svg3
-rw-r--r--launcher/resources/flat_white/scalable/multimc.svg3
-rw-r--r--launcher/resources/flat_white/scalable/new.svg3
-rw-r--r--launcher/resources/flat_white/scalable/news.svg3
-rw-r--r--launcher/resources/flat_white/scalable/notes.svg3
-rw-r--r--launcher/resources/flat_white/scalable/packages.svg3
-rw-r--r--launcher/resources/flat_white/scalable/patreon.svg3
-rw-r--r--launcher/resources/flat_white/scalable/proxy.svg3
-rw-r--r--launcher/resources/flat_white/scalable/quickmods.svg3
-rw-r--r--launcher/resources/flat_white/scalable/reddit-alien.svg3
-rw-r--r--launcher/resources/flat_white/scalable/refresh.svg3
-rw-r--r--launcher/resources/flat_white/scalable/rename.svg4
-rw-r--r--launcher/resources/flat_white/scalable/resourcepacks.svg3
-rw-r--r--launcher/resources/flat_white/scalable/screenshot-placeholder.svg3
-rw-r--r--launcher/resources/flat_white/scalable/screenshots.svg3
-rw-r--r--launcher/resources/flat_white/scalable/settings.svg3
-rw-r--r--launcher/resources/flat_white/scalable/shaderpacks.svg56
-rw-r--r--launcher/resources/flat_white/scalable/star.svg3
-rw-r--r--launcher/resources/flat_white/scalable/status-bad.svg3
-rw-r--r--launcher/resources/flat_white/scalable/status-good.svg3
-rw-r--r--launcher/resources/flat_white/scalable/status-running.svg3
-rw-r--r--launcher/resources/flat_white/scalable/status-yellow.svg3
-rw-r--r--launcher/resources/flat_white/scalable/tag.svg4
-rw-r--r--launcher/resources/flat_white/scalable/viewfolder.svg3
-rw-r--r--launcher/resources/flat_white/scalable/worlds.svg3
-rw-r--r--launcher/tasks/Task.cpp2
-rw-r--r--launcher/ui/dialogs/ModUpdateDialog.cpp15
-rw-r--r--launcher/ui/pages/global/LauncherPage.cpp13
-rw-r--r--launcher/ui/pages/global/LauncherPage.ui5
-rw-r--r--launcher/ui/pages/modplatform/ModModel.cpp25
-rw-r--r--launcher/ui/pages/modplatform/ModModel.h1
-rw-r--r--launcher/ui/themes/DarkTheme.cpp2
64 files changed, 546 insertions, 52 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index 97f757f7..f6b41850 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -245,7 +245,8 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
{{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
{{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
{"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
- {{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"}
+ {{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"},
+ {"show", "Opens the window for the specified instance (by instance ID)", "show"}
});
parser.addHelpOption();
parser.addVersionOption();
@@ -257,6 +258,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_profileToUse = parser.value("profile");
m_liveCheck = parser.isSet("alive");
m_zipToImport = parser.value("import");
+ m_instanceIdToShowWindowOf = parser.value("show");
// error if --launch is missing with --server or --profile
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
@@ -986,6 +988,16 @@ void Application::performMainStartupAction()
return;
}
}
+ if(!m_instanceIdToShowWindowOf.isEmpty())
+ {
+ auto inst = instances()->getInstanceById(m_instanceIdToShowWindowOf);
+ if(inst)
+ {
+ qDebug() << "<> Showing window of instance " << m_instanceIdToShowWindowOf;
+ showInstanceWindow(inst);
+ return;
+ }
+ }
if(!m_mainWindow)
{
// normal main window
diff --git a/launcher/Application.h b/launcher/Application.h
index 34ad8c15..c453cc28 100644
--- a/launcher/Application.h
+++ b/launcher/Application.h
@@ -301,6 +301,7 @@ public:
QString m_profileToUse;
bool m_liveCheck = false;
QUrl m_zipToImport;
+ QString m_instanceIdToShowWindowOf;
std::unique_ptr<QFile> logFile;
};
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 79ac49c7..0dae47df 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -602,6 +602,7 @@ SET(LAUNCHER_SOURCES
resources/OSX/OSX.qrc
resources/iOS/iOS.qrc
resources/flat/flat.qrc
+ resources/flat_white/flat_white.qrc
resources/documents/documents.qrc
../${Launcher_Branding_LogoQRC}
diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp
index 39e68c20..76cfccb0 100644
--- a/launcher/FileSystem.cpp
+++ b/launcher/FileSystem.cpp
@@ -401,6 +401,7 @@ bool overrideFolder(QString overwritten_path, QString override_path)
std::error_code err;
fs::copy_options opt = copy_opts::recursive | copy_opts::overwrite_existing;
+ // FIXME: hello traveller! Apparently std::copy does NOT overwrite existing files on GNU libstdc++ on Windows?
fs::copy(toStdString(override_path), toStdString(overwritten_path), opt, err);
if (err) {
diff --git a/launcher/GZip.cpp b/launcher/GZip.cpp
index 067104cf..e36dc8a4 100644
--- a/launcher/GZip.cpp
+++ b/launcher/GZip.cpp
@@ -72,7 +72,7 @@ bool GZip::unzip(const QByteArray &compressedBytes, QByteArray &uncompressedByte
uncompLength *= 2;
}
- strm.next_out = (Bytef *)(uncompressedBytes.data() + strm.total_out);
+ strm.next_out = reinterpret_cast<Bytef *>((uncompressedBytes.data() + strm.total_out));
strm.avail_out = uncompLength - strm.total_out;
// Inflate another chunk.
@@ -129,7 +129,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
{
compressedBytes.resize(compressedBytes.size() * 2);
}
- zs.next_out = (Bytef *) (compressedBytes.data() + offset);
+ zs.next_out = reinterpret_cast<Bytef*>((compressedBytes.data() + offset));
temp = zs.avail_out = compressedBytes.size() - offset;
ret = deflate(&zs, Z_FINISH);
offset += temp - zs.avail_out;
diff --git a/launcher/HoeDown.h b/launcher/HoeDown.h
index b9e06ffb..cb62de6c 100644
--- a/launcher/HoeDown.h
+++ b/launcher/HoeDown.h
@@ -42,7 +42,7 @@ public:
}
void put(QByteArray input)
{
- hoedown_buffer_put(buf, (uint8_t *) input.data(), input.size());
+ hoedown_buffer_put(buf, reinterpret_cast<uint8_t *>(input.data()), input.size());
}
const uint8_t * data() const
{
diff --git a/launcher/main.cpp b/launcher/main.cpp
index c6a7614c..e2116f38 100644
--- a/launcher/main.cpp
+++ b/launcher/main.cpp
@@ -84,6 +84,7 @@ int main(int argc, char *argv[])
Q_INIT_RESOURCE(OSX);
Q_INIT_RESOURCE(iOS);
Q_INIT_RESOURCE(flat);
+ Q_INIT_RESOURCE(flat_white);
return app.exec();
}
case Application::Failed:
diff --git a/launcher/modplatform/helpers/NetworkModAPI.cpp b/launcher/modplatform/helpers/NetworkModAPI.cpp
index 866e7540..7633030e 100644
--- a/launcher/modplatform/helpers/NetworkModAPI.cpp
+++ b/launcher/modplatform/helpers/NetworkModAPI.cpp
@@ -15,6 +15,7 @@ void NetworkModAPI::searchMods(CallerType* caller, SearchArgs&& args) const
QObject::connect(netJob, &NetJob::started, caller, [caller, netJob] { caller->setActiveJob(netJob); });
QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed);
+ QObject::connect(netJob, &NetJob::aborted, caller, &CallerType::searchRequestAborted);
QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] {
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
index 3e53becb..ae45e096 100644
--- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
+++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
@@ -1,20 +1,20 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
-* PolyMC - Minecraft Launcher
-* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
-*
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, version 3.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
#include "ModrinthPackIndex.h"
#include "ModrinthAPI.h"
@@ -35,7 +35,7 @@ void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
pack.provider = ModPlatform::Provider::MODRINTH;
pack.name = Json::requireString(obj, "title");
-
+
pack.slug = Json::ensureString(obj, "slug", "");
if (!pack.slug.isEmpty())
pack.websiteUrl = "https://modrinth.com/mod/" + pack.slug;
@@ -59,23 +59,23 @@ void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
void Modrinth::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& obj)
{
pack.extraData.issuesUrl = Json::ensureString(obj, "issues_url");
- if(pack.extraData.issuesUrl.endsWith('/'))
+ if (pack.extraData.issuesUrl.endsWith('/'))
pack.extraData.issuesUrl.chop(1);
pack.extraData.sourceUrl = Json::ensureString(obj, "source_url");
- if(pack.extraData.sourceUrl.endsWith('/'))
+ if (pack.extraData.sourceUrl.endsWith('/'))
pack.extraData.sourceUrl.chop(1);
pack.extraData.wikiUrl = Json::ensureString(obj, "wiki_url");
- if(pack.extraData.wikiUrl.endsWith('/'))
+ if (pack.extraData.wikiUrl.endsWith('/'))
pack.extraData.wikiUrl.chop(1);
pack.extraData.discordUrl = Json::ensureString(obj, "discord_url");
- if(pack.extraData.discordUrl.endsWith('/'))
+ if (pack.extraData.discordUrl.endsWith('/'))
pack.extraData.discordUrl.chop(1);
auto donate_arr = Json::ensureArray(obj, "donation_urls");
- for(auto d : donate_arr){
+ for (auto d : donate_arr) {
auto d_obj = Json::requireObject(d);
ModPlatform::DonationData donate;
@@ -104,7 +104,7 @@ void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
auto obj = versionIter.toObject();
auto file = loadIndexedPackVersion(obj);
- if(file.fileId.isValid()) // Heuristic to check if the returned value is valid
+ if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
unsortedVersions.append(file);
}
auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
@@ -116,7 +116,8 @@ void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
pack.versionsLoaded = true;
}
-auto Modrinth::loadIndexedPackVersion(QJsonObject &obj, QString preferred_hash_type, QString preferred_file_name) -> ModPlatform::IndexedVersion
+auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_type, QString preferred_file_name)
+ -> ModPlatform::IndexedVersion
{
ModPlatform::IndexedVersion file;
@@ -141,6 +142,12 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject &obj, QString preferred_hash_t
auto files = Json::requireArray(obj, "files");
int i = 0;
+ if (files.empty()) {
+ // This should not happen normally, but check just in case
+ qWarning() << "Modrinth returned an unexpected empty list of files:" << obj;
+ return {};
+ }
+
// Find correct file (needed in cases where one version may have multiple files)
// Will default to the last one if there's no primary (though I think Modrinth requires that
// at least one file is primary, idk)
@@ -167,7 +174,7 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject &obj, QString preferred_hash_t
file.fileName = Json::requireString(parent, "filename");
file.is_preferred = Json::requireBoolean(parent, "primary") || (files.count() == 1);
auto hash_list = Json::requireObject(parent, "hashes");
-
+
if (hash_list.contains(preferred_hash_type)) {
file.hash = Json::requireString(hash_list, preferred_hash_type);
file.hash_type = preferred_hash_type;
diff --git a/launcher/resources/flat_white/flat_white.qrc b/launcher/resources/flat_white/flat_white.qrc
new file mode 100644
index 00000000..9df69060
--- /dev/null
+++ b/launcher/resources/flat_white/flat_white.qrc
@@ -0,0 +1,50 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource prefix="/icons/flat_white">
+ <file>index.theme</file>
+ <file>scalable/about.svg</file>
+ <file>scalable/accounts.svg</file>
+ <file>scalable/bug.svg</file>
+ <file>scalable/cat.svg</file>
+ <file>scalable/centralmods.svg</file>
+ <file>scalable/checkupdate.svg</file>
+ <file>scalable/copy.svg</file>
+ <file>scalable/coremods.svg</file>
+ <file>scalable/custom-commands.svg</file>
+ <file>scalable/discord.svg</file>
+ <file>scalable/externaltools.svg</file>
+ <file>scalable/help.svg</file>
+ <file>scalable/instance-settings.svg</file>
+ <file>scalable/jarmods.svg</file>
+ <file>scalable/java.svg</file>
+ <file>scalable/language.svg</file>
+ <file>scalable/launcher.svg</file>
+ <file>scalable/loadermods.svg</file>
+ <file>scalable/log.svg</file>
+ <file>scalable/minecraft.svg</file>
+ <file>scalable/new.svg</file>
+ <file>scalable/news.svg</file>
+ <file>scalable/notes.svg</file>
+ <file>scalable/packages.svg</file>
+ <file>scalable/proxy.svg</file>
+ <file>scalable/quickmods.svg</file>
+ <file>scalable/reddit-alien.svg</file>
+ <file>scalable/refresh.svg</file>
+ <file>scalable/resourcepacks.svg</file>
+ <file>scalable/shaderpacks.svg</file>
+ <file>scalable/screenshot-placeholder.svg</file>
+ <file>scalable/screenshots.svg</file>
+ <file>scalable/settings.svg</file>
+ <file>scalable/star.svg</file>
+ <file>scalable/status-bad.svg</file>
+ <file>scalable/status-good.svg</file>
+ <file>scalable/status-running.svg</file>
+ <file>scalable/status-yellow.svg</file>
+ <file>scalable/viewfolder.svg</file>
+ <file>scalable/worlds.svg</file>
+ <file>scalable/delete.svg</file>
+ <file>scalable/export.svg</file>
+ <file>scalable/rename.svg</file>
+ <file>scalable/tag.svg</file>
+ </qresource>
+</RCC>
diff --git a/launcher/resources/flat_white/index.theme b/launcher/resources/flat_white/index.theme
new file mode 100644
index 00000000..54dd0e10
--- /dev/null
+++ b/launcher/resources/flat_white/index.theme
@@ -0,0 +1,11 @@
+[Icon Theme]
+Name=Flat (White)
+Comment=White version of the flat icons (dark mode)
+Inherits=multimc
+Directories=scalable
+
+[scalable]
+Size=48
+Type=Scalable
+MinSize=16
+MaxSize=256
diff --git a/launcher/resources/flat_white/scalable/about.svg b/launcher/resources/flat_white/scalable/about.svg
new file mode 100644
index 00000000..e42ca948
--- /dev/null
+++ b/launcher/resources/flat_white/scalable/about.svg
@@ -0,0 +1,3 @@
+<svg fill="#D8DEE9" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+ <path d="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z"/>
+</svg> \ No newline at end of file
diff --git a/launcher/resources/flat_white/scalable/accounts.svg b/launcher/resources/flat_white/scalable/accounts.svg
new file mode 100644
index 00000000..e714bde1
--- /dev/null
+++ b/launcher/resources/flat_white/scalable/accounts.svg
@@ -0,0 +1,3 @@
+<svg fill="#D8DEE9" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+ <path d="M16,13C15.71,13 15.38,13 15.03,13.05C16.19,13.89 17,15 17,16.5V19H23V16.5C23,14.17 18.33,13 16,13M8,13C5.67,13 1,14.17 1,16.5V19H15V16.5C15,14.17 10.33,13 8,13M8,11A3,3 0 0,0 11,8A3,3 0 0,0 8,5A3,3 0 0,0 5,8A3,3 0 0,0 8,11M16,11A3,3 0 0,0 19,8A3,3 0 0,0 16,5A3,3 0 0,0 13,8A3,3 0 0,0 16,11Z"/>
+</svg> \ No newline at end of file
diff --git a/launcher/resources/flat_white/scalable/bug.svg b/launcher/resources/flat_white/scalable/bug.svg
new file mode 100644
index 00000000..3122702e
--- /dev/null
+++ b/launcher/resources/flat_white/scalable/bug.svg
@@ -0,0 +1,3 @@
+<svg fill="#D8DEE9" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+ <path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"/>
+</svg> \ No newline at end of file
diff --git a/launcher/resources/flat_white/scalable/cat.svg b/launcher/resources/flat_white/scalable/cat.svg
new file mode 100644
index 00000000..18da097a
--- /dev/null
+++ b/launcher/resources/flat_white/scalable/cat.svg
@@ -0,0 +1,3 @@
+<svg fill="#D8DEE9" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+ <path d="M12,8L10.67,8.09C9.81,7.07 7.4,4.5 5,4.5C5,4.5 3.03,7.46 4.96,11.41C4.41,12.24 4.07,12.67 4,13.66L2.07,13.95L2.28,14.93L4.04,14.67L4.18,15.38L2.61,16.32L3.08,17.21L4.53,16.32C5.68,18.76 8.59,20 12,20C15.41,20 18.32,18.76 19.47,16.32L20.92,17.21L21.39,16.32L19.82,15.38L19.96,14.67L21.72,14.93L21.93,13.95L20,13.66C19.93,12.67 19.59,12.24 19.04,11.41C20.97,7.46 19,4.5 19,4.5C16.6,4.5 14.19,7.07 13.33,8.09L12,8M9,11A1,1 0 0,1 10,12A1,1 0 0,1 9,13A1,1 0 0,1 8,12A1,1 0 0,1 9,11M15,11A1,1 0 0,1 16,12A1,1 0 0,1 15,13A1,1 0 0,1 14,12A1,1 0 0,1 15,11M11,14H13L12.3,15.39C12.5,16.03 13.06,16.5 13.75,16.5A1.5,1.5 0 0,0 15.25,15H15.75A2,2 0 0,1 13.75,17C13,17 12.35,16.59 12,16V16H12C11.65,16.59 11,17 10.25,17A2,2 0 0,1 8.25,15H8.75A1.5,1.5 0 0,0 10.25,16.5C10.94,16.5 11.5,16.03 11.7,15.39L11,14Z"/>
+</svg> \ No newline at end of file
diff --git a/launcher/resources/flat_white/scalable/centralmods.svg b/launcher/resources/flat_white/scalable/centralmods.svg
new file mode 100644
index 00000000..d8d10f2f
--- /dev/null
+++ b/launcher/resources/flat_white/scalable/centralmods.svg<