From ea004846a9612146fab57409855c0fb746615076 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Tue, 7 Oct 2025 01:07:50 +0500 Subject: [PATCH] Create a unified dialog to ask user for offline name Signed-off-by: Octol1ttle --- launcher/CMakeLists.txt | 6 +- launcher/LaunchController.cpp | 12 +- .../ui/dialogs/ChooseOfflineNameDialog.cpp | 74 ++++++++++++ launcher/ui/dialogs/ChooseOfflineNameDialog.h | 50 +++++++++ .../ui/dialogs/ChooseOfflineNameDialog.ui | 58 ++++++++++ launcher/ui/dialogs/OfflineLoginDialog.cpp | 105 ------------------ launcher/ui/dialogs/OfflineLoginDialog.h | 40 ------- launcher/ui/dialogs/OfflineLoginDialog.ui | 80 ------------- launcher/ui/pages/global/AccountListPage.cpp | 11 +- 9 files changed, 201 insertions(+), 235 deletions(-) create mode 100644 launcher/ui/dialogs/ChooseOfflineNameDialog.cpp create mode 100644 launcher/ui/dialogs/ChooseOfflineNameDialog.h create mode 100644 launcher/ui/dialogs/ChooseOfflineNameDialog.ui delete mode 100644 launcher/ui/dialogs/OfflineLoginDialog.cpp delete mode 100644 launcher/ui/dialogs/OfflineLoginDialog.h delete mode 100644 launcher/ui/dialogs/OfflineLoginDialog.ui diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 6d6e2ae7f..0b4758c8b 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -1053,8 +1053,6 @@ SET(LAUNCHER_SOURCES ui/dialogs/ImportResourceDialog.h ui/dialogs/MSALoginDialog.cpp ui/dialogs/MSALoginDialog.h - ui/dialogs/OfflineLoginDialog.cpp - ui/dialogs/OfflineLoginDialog.h ui/dialogs/NewComponentDialog.cpp ui/dialogs/NewComponentDialog.h ui/dialogs/NewInstanceDialog.cpp @@ -1081,6 +1079,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/ResourceUpdateDialog.h ui/dialogs/InstallLoaderDialog.cpp ui/dialogs/InstallLoaderDialog.h + ui/dialogs/ChooseOfflineNameDialog.cpp + ui/dialogs/ChooseOfflineNameDialog.h ui/dialogs/skins/SkinManageDialog.cpp ui/dialogs/skins/SkinManageDialog.h @@ -1234,13 +1234,13 @@ qt_wrap_ui(LAUNCHER_UI ui/dialogs/IconPickerDialog.ui ui/dialogs/ImportResourceDialog.ui ui/dialogs/MSALoginDialog.ui - ui/dialogs/OfflineLoginDialog.ui ui/dialogs/AboutDialog.ui ui/dialogs/ReviewMessageBox.ui ui/dialogs/ScrollMessageBox.ui ui/dialogs/BlockedModsDialog.ui ui/dialogs/ChooseProviderDialog.ui ui/dialogs/skins/SkinManageDialog.ui + ui/dialogs/ChooseOfflineNameDialog.ui ) qt_wrap_ui(PRISM_UPDATE_UI diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 26f539e15..2273318ee 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -61,6 +61,7 @@ #include "JavaCommon.h" #include "launch/steps/TextPrint.h" #include "tasks/Task.h" +#include "ui/dialogs/ChooseOfflineNameDialog.h" LaunchController::LaunchController() : Task() {} @@ -157,10 +158,15 @@ QString LaunchController::askOfflineName(QString playerName, bool demo, bool& ok QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString(); QString usedname = lastOfflinePlayerName.isEmpty() ? playerName : lastOfflinePlayerName; - QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok); - if (!ok) + + ChooseOfflineNameDialog dialog(message, m_parentWidget); + dialog.setWindowTitle(tr("Player name")); + dialog.setUsername(usedname); + if (dialog.exec() != QDialog::Accepted) { return {}; - if (name.length()) { + } + + if (const QString name = dialog.getUsername(); !name.isEmpty()) { usedname = name; APPLICATION->settings()->set("LastOfflinePlayerName", usedname); } diff --git a/launcher/ui/dialogs/ChooseOfflineNameDialog.cpp b/launcher/ui/dialogs/ChooseOfflineNameDialog.cpp new file mode 100644 index 000000000..79a567404 --- /dev/null +++ b/launcher/ui/dialogs/ChooseOfflineNameDialog.cpp @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2025 Octol1ttle + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ChooseOfflineNameDialog.h" + +#include +#include + +#include "ui_ChooseOfflineNameDialog.h" + +ChooseOfflineNameDialog::ChooseOfflineNameDialog(const QString& message, QWidget* parent) : QDialog(parent), ui(new Ui::ChooseOfflineNameDialog) +{ + ui->setupUi(this); + ui->label->setText(message); + + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel")); + ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK")); + + const QRegularExpression usernameRegExp("^[A-Za-z0-9_]{3,16}$"); + m_usernameValidator = new QRegularExpressionValidator(usernameRegExp, this); + ui->usernameTextBox->setValidator(m_usernameValidator); + + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + +ChooseOfflineNameDialog::~ChooseOfflineNameDialog() +{ + delete ui; +} + +QString ChooseOfflineNameDialog::getUsername() const +{ + return ui->usernameTextBox->text(); +} + +void ChooseOfflineNameDialog::setUsername(const QString& username) const +{ + ui->usernameTextBox->setText(username); + updateAcceptAllowed(username); +} + +void ChooseOfflineNameDialog::updateAcceptAllowed(const QString& username) const +{ + const bool allowed = ui->allowInvalidUsernames->isChecked() ? !username.isEmpty() : ui->usernameTextBox->hasAcceptableInput(); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowed); +} + +void ChooseOfflineNameDialog::on_usernameTextBox_textEdited(const QString& newText) const +{ + updateAcceptAllowed(newText); +} + +void ChooseOfflineNameDialog::on_allowInvalidUsernames_checkStateChanged(const Qt::CheckState checkState) const +{ + ui->usernameTextBox->setValidator(checkState == Qt::Checked ? nullptr : m_usernameValidator); + updateAcceptAllowed(getUsername()); +} diff --git a/launcher/ui/dialogs/ChooseOfflineNameDialog.h b/launcher/ui/dialogs/ChooseOfflineNameDialog.h new file mode 100644 index 000000000..fb3bb4257 --- /dev/null +++ b/launcher/ui/dialogs/ChooseOfflineNameDialog.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2025 Octol1ttle + * + * 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 . + */ + +#pragma once + +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class ChooseOfflineNameDialog; +} +QT_END_NAMESPACE + +class ChooseOfflineNameDialog final : public QDialog { + Q_OBJECT + + public: + explicit ChooseOfflineNameDialog(const QString& message, QWidget* parent = nullptr); + ~ChooseOfflineNameDialog() override; + + QString getUsername() const; + void setUsername(const QString& username) const; + + private: + void updateAcceptAllowed(const QString& username) const; + + protected slots: + void on_usernameTextBox_textEdited(const QString& newText) const; + void on_allowInvalidUsernames_checkStateChanged(Qt::CheckState checkState) const; + + private: + Ui::ChooseOfflineNameDialog* ui; + QRegularExpressionValidator* m_usernameValidator; +}; \ No newline at end of file diff --git a/launcher/ui/dialogs/ChooseOfflineNameDialog.ui b/launcher/ui/dialogs/ChooseOfflineNameDialog.ui new file mode 100644 index 000000000..51a10e5b8 --- /dev/null +++ b/launcher/ui/dialogs/ChooseOfflineNameDialog.ui @@ -0,0 +1,58 @@ + + + ChooseOfflineNameDialog + + + + 0 + 0 + 400 + 158 + + + + Choose Offline Name + + + + + + + 0 + 0 + + + + Message label placeholder. + + + + + + + Username + + + + + + + A username is valid only if it is from 3 to 16 characters in length, uses English letters, numbers, and underscores. An invalid username may prevent joining servers and singleplayer worlds. + + + Allow invalid usernames + + + + + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + + diff --git a/launcher/ui/dialogs/OfflineLoginDialog.cpp b/launcher/ui/dialogs/OfflineLoginDialog.cpp deleted file mode 100644 index d8fbc04fd..000000000 --- a/launcher/ui/dialogs/OfflineLoginDialog.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "OfflineLoginDialog.h" -#include "ui_OfflineLoginDialog.h" - -#include - -OfflineLoginDialog::OfflineLoginDialog(QWidget* parent) : QDialog(parent), ui(new Ui::OfflineLoginDialog) -{ - ui->setupUi(this); - ui->progressBar->setVisible(false); - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - - ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel")); - ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK")); - - connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -} - -OfflineLoginDialog::~OfflineLoginDialog() -{ - delete ui; -} - -// Stage 1: User interaction -void OfflineLoginDialog::accept() -{ - setUserInputsEnabled(false); - ui->progressBar->setVisible(true); - - // Setup the login task and start it - m_account = MinecraftAccount::createOffline(ui->userTextBox->text()); - m_loginTask = m_account->login(); - connect(m_loginTask.get(), &Task::failed, this, &OfflineLoginDialog::onTaskFailed); - connect(m_loginTask.get(), &Task::succeeded, this, &OfflineLoginDialog::onTaskSucceeded); - connect(m_loginTask.get(), &Task::status, this, &OfflineLoginDialog::onTaskStatus); - connect(m_loginTask.get(), &Task::progress, this, &OfflineLoginDialog::onTaskProgress); - m_loginTask->start(); -} - -void OfflineLoginDialog::setUserInputsEnabled(bool enable) -{ - ui->userTextBox->setEnabled(enable); - ui->buttonBox->setEnabled(enable); -} - -void OfflineLoginDialog::on_allowLongUsernames_stateChanged(int value) -{ - if (value == Qt::Checked) { - ui->userTextBox->setMaxLength(INT_MAX); - } else { - ui->userTextBox->setMaxLength(16); - } -} - -// Enable the OK button only when the textbox contains something. -void OfflineLoginDialog::on_userTextBox_textEdited(const QString& newText) -{ - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!newText.isEmpty()); -} - -void OfflineLoginDialog::onTaskFailed(const QString& reason) -{ - // Set message - auto lines = reason.split('\n'); - QString processed; - for (auto line : lines) { - if (line.size()) { - processed += "" + line + "
"; - } else { - processed += "
"; - } - } - ui->label->setText(processed); - - // Re-enable user-interaction - setUserInputsEnabled(true); - ui->progressBar->setVisible(false); -} - -void OfflineLoginDialog::onTaskSucceeded() -{ - QDialog::accept(); -} - -void OfflineLoginDialog::onTaskStatus(const QString& status) -{ - ui->label->setText(status); -} - -void OfflineLoginDialog::onTaskProgress(qint64 current, qint64 total) -{ - ui->progressBar->setMaximum(total); - ui->progressBar->setValue(current); -} - -// Public interface -MinecraftAccountPtr OfflineLoginDialog::newAccount(QWidget* parent, QString msg) -{ - OfflineLoginDialog dlg(parent); - dlg.ui->label->setText(msg); - if (dlg.exec() == QDialog::Accepted) { - return dlg.m_account; - } - return nullptr; -} diff --git a/launcher/ui/dialogs/OfflineLoginDialog.h b/launcher/ui/dialogs/OfflineLoginDialog.h deleted file mode 100644 index 6660a18ec..000000000 --- a/launcher/ui/dialogs/OfflineLoginDialog.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include - -#include "minecraft/auth/MinecraftAccount.h" -#include "tasks/Task.h" - -namespace Ui { -class OfflineLoginDialog; -} - -class OfflineLoginDialog : public QDialog { - Q_OBJECT - - public: - ~OfflineLoginDialog(); - - static MinecraftAccountPtr newAccount(QWidget* parent, QString message); - - private: - explicit OfflineLoginDialog(QWidget* parent = 0); - - void setUserInputsEnabled(bool enable); - - protected slots: - void accept(); - - void onTaskFailed(const QString& reason); - void onTaskSucceeded(); - void onTaskStatus(const QString& status); - void onTaskProgress(qint64 current, qint64 total); - - void on_userTextBox_textEdited(const QString& newText); - void on_allowLongUsernames_stateChanged(int value); - - private: - Ui::OfflineLoginDialog* ui; - MinecraftAccountPtr m_account; - Task::Ptr m_loginTask; -}; diff --git a/launcher/ui/dialogs/OfflineLoginDialog.ui b/launcher/ui/dialogs/OfflineLoginDialog.ui deleted file mode 100644 index 4633cbe3a..000000000 --- a/launcher/ui/dialogs/OfflineLoginDialog.ui +++ /dev/null @@ -1,80 +0,0 @@ - - - OfflineLoginDialog - - - - 0 - 0 - 400 - 150 - - - - - 0 - 0 - - - - Add Account - - - - - - Message label placeholder. - - - Qt::RichText - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - 16 - - - Username - - - - - - - Usernames longer than 16 characters cannot be used for LAN games or offline-mode servers. - - - Allow long usernames - - - - - - - 69 - - - false - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp index 041b8faff..ff250888a 100644 --- a/launcher/ui/pages/global/AccountListPage.cpp +++ b/launcher/ui/pages/global/AccountListPage.cpp @@ -45,8 +45,8 @@ #include #include "ui/dialogs/CustomMessageBox.h" +#include "ui/dialogs/ChooseOfflineNameDialog.h" #include "ui/dialogs/MSALoginDialog.h" -#include "ui/dialogs/OfflineLoginDialog.h" #include "Application.h" @@ -149,10 +149,13 @@ void AccountListPage::on_actionAddOffline_triggered() return; } - MinecraftAccountPtr account = - OfflineLoginDialog::newAccount(this, tr("Please enter your desired username to add your offline account.")); + ChooseOfflineNameDialog dialog(tr("Please enter your desired username to add your offline account."), this); + if (dialog.exec() != QDialog::Accepted) { + return; + } - if (account) { + if (const MinecraftAccountPtr account = MinecraftAccount::createOffline(dialog.getUsername())) { + account->login()->start(); // The task will complete here. m_accounts->addAccount(account); if (m_accounts->count() == 1) { m_accounts->setDefaultAccount(account);