diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:51:45 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:51:45 +0300 |
| commit | d3261e64152397db2dca4d691a990c6bc2a6f4dd (patch) | |
| tree | fac2f7be638651181a72453d714f0f96675c2b8b /archived/projt-launcher/launcher/ui/dialogs/MSALoginDialog.cpp | |
| parent | 31b9a8949ed0a288143e23bf739f2eb64fdc63be (diff) | |
| download | Project-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/MSALoginDialog.cpp')
| -rw-r--r-- | archived/projt-launcher/launcher/ui/dialogs/MSALoginDialog.cpp | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/archived/projt-launcher/launcher/ui/dialogs/MSALoginDialog.cpp b/archived/projt-launcher/launcher/ui/dialogs/MSALoginDialog.cpp new file mode 100644 index 0000000000..6a9cb13d75 --- /dev/null +++ b/archived/projt-launcher/launcher/ui/dialogs/MSALoginDialog.cpp @@ -0,0 +1,294 @@ +// 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> + * + * 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 "MSALoginDialog.h" +#include "Application.h" + +#include "ui_MSALoginDialog.h" + +#include "DesktopServices.h" +#include "minecraft/auth/AuthFlow.hpp" + +#include <QApplication> +#include <QClipboard> +#include <QColor> +#include <QPainter> +#include <QPixmap> +#include <QSize> +#include <QUrl> +#include <QtWidgets/QPushButton> + +#include <qrencode.h> + +MSALoginDialog::MSALoginDialog(QWidget* parent) : QDialog(parent), ui(new Ui::MSALoginDialog) +{ + ui->setupUi(this); + + // make font monospace + QFont font; + font.setPixelSize(ui->code->fontInfo().pixelSize()); + font.setFamily(APPLICATION->settings()->get("ConsoleFont").toString()); + font.setStyleHint(QFont::Monospace); + font.setFixedPitch(true); + ui->code->setFont(font); + + connect(ui->copyCode, + &QPushButton::clicked, + this, + [this] { QApplication::clipboard()->setText(ui->code->text()); }); + connect(ui->loginButton, + &QPushButton::clicked, + this, + [this] + { + if (m_url.isValid()) + { + if (!DesktopServices::openUrl(m_url)) + { + QApplication::clipboard()->setText(m_url.toString()); + } + } + }); + + ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel")); +} + +int MSALoginDialog::exec() +{ + // Setup the login task and start it + m_account = MinecraftAccount::createBlankMSA(); + m_authflow_task = m_account->login(false); + connect(m_authflow_task.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed); + connect(m_authflow_task.get(), &Task::succeeded, this, &QDialog::accept); + connect(m_authflow_task.get(), &Task::aborted, this, &MSALoginDialog::reject); + connect(m_authflow_task.get(), &Task::status, this, &MSALoginDialog::onAuthFlowStatus); + connect(m_authflow_task.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser); + connect(m_authflow_task.get(), + &AuthFlow::authorizeWithBrowserWithExtra, + this, + &MSALoginDialog::authorizeWithBrowserWithExtra); + connect(ui->buttonBox->button(QDialogButtonBox::Cancel), + &QPushButton::clicked, + m_authflow_task.get(), + &Task::abort); + + m_devicecode_task.reset(new AuthFlow(m_account->accountData(), AuthFlow::Action::DeviceCode)); + connect(m_devicecode_task.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed); + connect(m_devicecode_task.get(), &Task::succeeded, this, &QDialog::accept); + connect(m_devicecode_task.get(), &Task::aborted, this, &MSALoginDialog::reject); + connect(m_devicecode_task.get(), &Task::status, this, &MSALoginDialog::onDeviceFlowStatus); + connect(m_devicecode_task.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser); + connect(m_devicecode_task.get(), + &AuthFlow::authorizeWithBrowserWithExtra, + this, + &MSALoginDialog::authorizeWithBrowserWithExtra); + connect(ui->buttonBox->button(QDialogButtonBox::Cancel), + &QPushButton::clicked, + m_devicecode_task.get(), + &Task::abort); + QMetaObject::invokeMethod(m_authflow_task.get(), &Task::start, Qt::QueuedConnection); + QMetaObject::invokeMethod(m_devicecode_task.get(), &Task::start, Qt::QueuedConnection); + + return QDialog::exec(); +} + +MSALoginDialog::~MSALoginDialog() +{ + delete ui; +} + +void MSALoginDialog::onTaskFailed(QString reason) +{ + // Set message + m_authflow_task->disconnect(); + m_devicecode_task->disconnect(); + ui->stackedWidget->setCurrentIndex(0); + auto lines = reason.split('\n'); + QString processed; + for (auto line : lines) + { + if (line.size()) + { + processed += "<font color='red'>" + line + "</font><br />"; + } + else + { + processed += "<br />"; + } + } + ui->status->setText(processed); + auto task = m_authflow_task; + if (task->failReason().isEmpty()) + { + task = m_devicecode_task; + } + if (task) + { + ui->loadingLabel->setText(task->getStatus()); + } + disconnect(ui->buttonBox->button(QDialogButtonBox::Cancel), + &QPushButton::clicked, + m_authflow_task.get(), + &Task::abort); + disconnect(ui->buttonBox->button(QDialogButtonBox::Cancel), + &QPushButton::clicked, + m_devicecode_task.get(), + &Task::abort); + connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &MSALoginDialog::reject); +} + +void MSALoginDialog::authorizeWithBrowser(const QUrl& url) +{ + ui->stackedWidget2->setCurrentIndex(1); + ui->stackedWidget2->adjustSize(); + ui->stackedWidget2->updateGeometry(); + this->adjustSize(); + ui->loginButton->setToolTip(QString("<div style='width: 200px;'>%1</div>").arg(url.toString())); + m_url = url; +} + +// https://stackoverflow.com/questions/21400254/how-to-draw-a-qr-code-with-qt-in-native-c-c +void paintQR(QPainter& painter, const QSize sz, const QString& data, QColor fg) +{ + QRcode* qr = QRcode_encodeString(data.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1); + if (!qr) + { + return; + } + + const int s = qr->width > 0 ? qr->width : 1; + const double w = sz.width(); + const double h = sz.height(); + const double aspect = w / h; + const double size = ((aspect > 1.0) ? h : w); + const double scale = size / (s + 2); + + painter.setPen(Qt::NoPen); + painter.setBrush(fg); + for (int y = 0; y < s; y++) + { + for (int x = 0; x < s; x++) + { + const int color = qr->data[y * s + x] & 1; // LSB is 1 for black, 0 for white + if (0 != color) + { + const double rx1 = (x + 1) * scale, ry1 = (y + 1) * scale; + QRectF r(rx1, ry1, scale, scale); + painter.drawRect(r); + } + } + } + QRcode_free(qr); +} + +void MSALoginDialog::authorizeWithBrowserWithExtra(QString url, QString code, [[maybe_unused]] int expiresIn) +{ + ui->stackedWidget->setCurrentIndex(1); + ui->stackedWidget->adjustSize(); + ui->stackedWidget->updateGeometry(); + this->adjustSize(); + + const auto linkString = QString("<a href=\"%1\">%2</a>").arg(url, url); + if (url == "https://www.microsoft.com/link" && !code.isEmpty()) + { + url += QString("?otc=%1").arg(code); + } + ui->code->setText(code); + + auto size = QSize(150, 150); + QPixmap pixmap(size); + pixmap.fill(Qt::white); + + QPainter painter(&pixmap); + paintQR(painter, size, url, Qt::black); + + // Set the generated pixmap to the label + ui->qr->setPixmap(pixmap); + + ui->qrMessage->setText(tr("Open %1 or scan the QR and enter the above code if needed.").arg(linkString)); +} + +void MSALoginDialog::onDeviceFlowStatus(QString status) +{ + ui->stackedWidget->setCurrentIndex(0); + ui->stackedWidget->adjustSize(); + ui->stackedWidget->updateGeometry(); + this->adjustSize(); + ui->status->setText(status); +} + +void MSALoginDialog::onAuthFlowStatus(QString status) +{ + ui->stackedWidget2->setCurrentIndex(0); + ui->stackedWidget2->adjustSize(); + ui->stackedWidget2->updateGeometry(); + this->adjustSize(); + ui->status2->setText(status); +} + +// Public interface +MinecraftAccountPtr MSALoginDialog::newAccount(QWidget* parent) +{ + MSALoginDialog dlg(parent); + if (dlg.exec() == QDialog::Accepted) + { + return dlg.m_account; + } + return nullptr; +}
\ No newline at end of file |
