summaryrefslogtreecommitdiff
path: root/archived/projt-launcher/launcher/ui/dialogs/ProfileSetupDialog.cpp
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:51:45 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:51:45 +0300
commitd3261e64152397db2dca4d691a990c6bc2a6f4dd (patch)
treefac2f7be638651181a72453d714f0f96675c2b8b /archived/projt-launcher/launcher/ui/dialogs/ProfileSetupDialog.cpp
parent31b9a8949ed0a288143e23bf739f2eb64fdc63be (diff)
downloadProject-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.tar.gz
Project-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.zip
NOISSUE add archived projects
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'archived/projt-launcher/launcher/ui/dialogs/ProfileSetupDialog.cpp')
-rw-r--r--archived/projt-launcher/launcher/ui/dialogs/ProfileSetupDialog.cpp345
1 files changed, 345 insertions, 0 deletions
diff --git a/archived/projt-launcher/launcher/ui/dialogs/ProfileSetupDialog.cpp b/archived/projt-launcher/launcher/ui/dialogs/ProfileSetupDialog.cpp
new file mode 100644
index 0000000000..2c4a523121
--- /dev/null
+++ b/archived/projt-launcher/launcher/ui/dialogs/ProfileSetupDialog.cpp
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-3.0-only
+// SPDX-FileCopyrightText: 2026 Project Tick
+// SPDX-FileContributor: Project Tick Team
+/*
+ * ProjT Launcher - Minecraft Launcher
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * === Upstream License Block (Do Not Modify) ==============================
+ *
+ *
+ *
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
+ *
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * 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 "ProfileSetupDialog.h"
+#include "net/RawHeaderProxy.h"
+#include "ui_ProfileSetupDialog.h"
+
+#include <QAction>
+#include <QDebug>
+#include <QJsonDocument>
+#include <QPushButton>
+#include <QRegularExpressionValidator>
+
+#include "ui/dialogs/ProgressDialog.h"
+
+#include <Application.h>
+#include "minecraft/auth/Parsers.hpp"
+#include "net/Upload.h"
+
+ProfileSetupDialog::ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidget* parent)
+ : QDialog(parent),
+ m_accountToSetup(accountToSetup),
+ ui(new Ui::ProfileSetupDialog)
+{
+ ui->setupUi(this);
+ ui->errorLabel->setVisible(false);
+
+ goodIcon = QIcon::fromTheme("status-good");
+ yellowIcon = QIcon::fromTheme("status-yellow");
+ badIcon = QIcon::fromTheme("status-bad");
+
+ static const QRegularExpression s_permittedNames("[a-zA-Z0-9_]{3,16}");
+ auto nameEdit = ui->nameEdit;
+ nameEdit->setValidator(new QRegularExpressionValidator(s_permittedNames));
+ nameEdit->setClearButtonEnabled(true);
+ validityAction = nameEdit->addAction(yellowIcon, QLineEdit::LeadingPosition);
+ connect(nameEdit, &QLineEdit::textEdited, this, &ProfileSetupDialog::nameEdited);
+
+ checkStartTimer.setSingleShot(true);
+ connect(&checkStartTimer, &QTimer::timeout, this, &ProfileSetupDialog::startCheck);
+
+ setNameStatus(NameStatus::NotSet, QString());
+
+ ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
+}
+
+ProfileSetupDialog::~ProfileSetupDialog()
+{
+ delete ui;
+}
+
+void ProfileSetupDialog::on_buttonBox_accepted()
+{
+ setupProfile(currentCheck);
+}
+
+void ProfileSetupDialog::on_buttonBox_rejected()
+{
+ reject();
+}
+
+void ProfileSetupDialog::setNameStatus(ProfileSetupDialog::NameStatus status, QString errorString = QString())
+{
+ nameStatus = status;
+ auto okButton = ui->buttonBox->button(QDialogButtonBox::Ok);
+ switch (nameStatus)
+ {
+ case NameStatus::Available:
+ {
+ validityAction->setIcon(goodIcon);
+ okButton->setEnabled(true);
+ }
+ break;
+ case NameStatus::NotSet:
+ case NameStatus::Pending:
+ validityAction->setIcon(yellowIcon);
+ okButton->setEnabled(false);
+ break;
+ case NameStatus::Exists:
+ case NameStatus::Error:
+ validityAction->setIcon(badIcon);
+ okButton->setEnabled(false);
+ break;
+ }
+ if (!errorString.isEmpty())
+ {
+ ui->errorLabel->setText(errorString);
+ ui->errorLabel->setVisible(true);
+ }
+ else
+ {
+ ui->errorLabel->setVisible(false);
+ }
+}
+
+void ProfileSetupDialog::nameEdited(const QString& name)
+{
+ if (!ui->nameEdit->hasAcceptableInput())
+ {
+ setNameStatus(NameStatus::NotSet, tr("Name is too short - must be between 3 and 16 characters long."));
+ return;
+ }
+ scheduleCheck(name);
+}
+
+void ProfileSetupDialog::scheduleCheck(const QString& name)
+{
+ queuedCheck = name;
+ setNameStatus(NameStatus::Pending);
+ checkStartTimer.start(1000);
+}
+
+void ProfileSetupDialog::startCheck()
+{
+ if (isChecking)
+ {
+ return;
+ }
+ if (queuedCheck.isNull())
+ {
+ return;
+ }
+ checkName(queuedCheck);
+}
+
+void ProfileSetupDialog::checkName(const QString& name)
+{
+ if (isChecking)
+ {
+ return;
+ }
+
+ currentCheck = name;
+ isChecking = true;
+
+ QUrl url(QString("https://api.minecraftservices.com/minecraft/profile/name/%1/available").arg(name));
+ auto headers = QList<Net::HeaderPair>{ { "Content-Type", "application/json" },
+ { "Accept", "application/json" },
+ { "Authorization",
+ QString("Bearer %1").arg(m_accountToSetup->accessToken()).toUtf8() } };
+
+ m_check_response.reset(new QByteArray());
+ if (m_check_task)
+ disconnect(m_check_task.get(), nullptr, this, nullptr);
+ m_check_task = Net::Download::makeByteArray(url, m_check_response);
+ m_check_task->addHeaderProxy(new Net::RawHeaderProxy(headers));
+
+ connect(m_check_task.get(), &Task::finished, this, &ProfileSetupDialog::checkFinished);
+
+ m_check_task->setNetwork(APPLICATION->network());
+ m_check_task->start();
+}
+
+void ProfileSetupDialog::checkFinished()
+{
+ if (m_check_task->error() == QNetworkReply::NoError)
+ {
+ auto doc = QJsonDocument::fromJson(*m_check_response);
+ auto root = doc.object();
+ auto statusValue = root.value("status").toString("INVALID");
+ if (statusValue == "AVAILABLE")
+ {
+ setNameStatus(NameStatus::Available);
+ }
+ else if (statusValue == "DUPLICATE")
+ {
+ setNameStatus(NameStatus::Exists, tr("Minecraft profile with name %1 already exists.").arg(currentCheck));
+ }
+ else if (statusValue == "NOT_ALLOWED")
+ {
+ setNameStatus(NameStatus::Exists, tr("The name %1 is not allowed.").arg(currentCheck));
+ }
+ else
+ {
+ setNameStatus(NameStatus::Error, tr("Unhandled profile name status: %1").arg(statusValue));
+ }
+ }
+ else
+ {
+ setNameStatus(NameStatus::Error, tr("Failed to check name availability."));
+ }
+ isChecking = false;
+}
+
+void ProfileSetupDialog::setupProfile(const QString& profileName)
+{
+ if (isWorking)
+ {
+ return;
+ }
+
+ QString payloadTemplate("{\"profileName\":\"%1\"}");
+
+ QUrl url("https://api.minecraftservices.com/minecraft/profile");
+ auto headers = QList<Net::HeaderPair>{ { "Content-Type", "application/json" },
+ { "Accept", "application/json" },
+ { "Authorization",
+ QString("Bearer %1").arg(m_accountToSetup->accessToken()).toUtf8() } };
+
+ m_profile_response.reset(new QByteArray());
+ m_profile_task = Net::Upload::makeByteArray(url, m_profile_response, payloadTemplate.arg(profileName).toUtf8());
+ m_profile_task->addHeaderProxy(new Net::RawHeaderProxy(headers));
+
+ connect(m_profile_task.get(), &Task::finished, this, &ProfileSetupDialog::setupProfileFinished);
+
+ m_profile_task->setNetwork(APPLICATION->network());
+ m_profile_task->start();
+
+ isWorking = true;
+
+ auto button = ui->buttonBox->button(QDialogButtonBox::Cancel);
+ button->setEnabled(false);
+}
+
+namespace
+{
+
+ struct MojangError
+ {
+ static MojangError fromJSON(QByteArray data)
+ {
+ MojangError out;
+ out.rawError = QString::fromUtf8(data);
+ auto doc = QJsonDocument::fromJson(data, &out.parseError);
+
+ out.fullyParsed = false;
+ if (!out.parseError.error)
+ {
+ auto object = doc.object();
+ out.fullyParsed = true;
+ out.fullyParsed &= Parsers::getString(object.value("path"), out.path);
+ out.fullyParsed &= Parsers::getString(object.value("error"), out.error);
+ out.fullyParsed &= Parsers::getString(object.value("errorMessage"), out.errorMessage);
+ }
+
+ return out;
+ }
+
+ QString rawError;
+ QJsonParseError parseError;
+ bool fullyParsed;
+
+ QString path;
+ QString error;
+ QString errorMessage;
+ };
+
+} // namespace
+
+void ProfileSetupDialog::setupProfileFinished()
+{
+ isWorking = false;
+ if (m_profile_task->error() == QNetworkReply::NoError)
+ {
+ /*
+ * data contains the profile in the response
+ * ... we could parse it and update the account, but let's just return back to the normal login flow instead...
+ */
+ accept();
+ }
+ else
+ {
+ auto parsedError = MojangError::fromJSON(*m_profile_response);
+ ui->errorLabel->setVisible(true);
+
+ QString errorMessage =
+ tr("Network Error: %1\nHTTP Status: %2")
+ .arg(m_profile_task->errorString(), QString::number(m_profile_task->replyStatusCode()));
+
+ if (parsedError.fullyParsed)
+ {
+ errorMessage += "Path: " + parsedError.path + "\n";
+ errorMessage += "Error: " + parsedError.error + "\n";
+ errorMessage += "Message: " + parsedError.errorMessage + "\n";
+ }
+ else
+ {
+ errorMessage += "Failed to parse error from Mojang API: " + parsedError.parseError.errorString() + "\n";
+ errorMessage += "Log:\n" + parsedError.rawError + "\n";
+ }
+
+ ui->errorLabel->setText(tr("The server responded with the following error:") + "\n\n" + errorMessage);
+ qDebug() << parsedError.rawError;
+ auto button = ui->buttonBox->button(QDialogButtonBox::Cancel);
+ button->setEnabled(true);
+ }
+}