configure_system: Contrain profile usernames to 32 characters

Previously, we would let a user enter an unbounded name and then
silently truncate away characters that went over the 32-character limit.
This is kind of bad from the UX point of view, because we're essentially
not doing what the user intended in certain scenarios.

Instead, we clamp it to 32 characters and make that visually apparent in
the dialog box to provide a name for a user.
master
Lioncash 2018-10-28 18:11:17 +07:00
parent b5f8a5f0a3
commit a6830e61b8
5 changed files with 114 additions and 26 deletions

@ -57,7 +57,8 @@ struct UUID {
}; };
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
using ProfileUsername = std::array<u8, 0x20>; constexpr std::size_t profile_username_size = 32;
using ProfileUsername = std::array<u8, profile_username_size>;
using ProfileData = std::array<u8, MAX_DATA>; using ProfileData = std::array<u8, MAX_DATA>;
using UserIDArray = std::array<UUID, MAX_USERS>; using UserIDArray = std::array<UUID, MAX_USERS>;

@ -56,6 +56,8 @@ add_executable(yuzu
main.h main.h
ui_settings.cpp ui_settings.cpp
ui_settings.h ui_settings.h
util/limitable_input_dialog.cpp
util/limitable_input_dialog.h
util/spinbox.cpp util/spinbox.cpp
util/spinbox.h util/spinbox.h
util/util.cpp util/util.cpp

@ -6,20 +6,20 @@
#include <QFileDialog> #include <QFileDialog>
#include <QGraphicsItem> #include <QGraphicsItem>
#include <QGraphicsScene> #include <QGraphicsScene>
#include <QInputDialog> #include <QHeaderView>
#include <QMessageBox> #include <QMessageBox>
#include <QStandardItemModel> #include <QStandardItemModel>
#include <QTreeView> #include <QTreeView>
#include <QVBoxLayout> #include <QVBoxLayout>
#include "common/common_paths.h" #include "common/assert.h"
#include "common/logging/backend.h" #include "common/file_util.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/acc/profile_manager.h"
#include "core/settings.h" #include "core/settings.h"
#include "ui_configure_system.h" #include "ui_configure_system.h"
#include "yuzu/configuration/configure_system.h" #include "yuzu/configuration/configure_system.h"
#include "yuzu/main.h" #include "yuzu/util/limitable_input_dialog.h"
namespace { namespace {
constexpr std::array<int, 12> days_in_month = {{ constexpr std::array<int, 12> days_in_month = {{
@ -83,6 +83,12 @@ QPixmap GetIcon(Service::Account::UUID uuid) {
return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
} }
QString GetProfileUsernameFromUser(QWidget* parent, const QString& description_text) {
return LimitableInputDialog::GetText(parent, ConfigureSystem::tr("Enter Username"),
description_text, 1,
static_cast<int>(Service::Account::profile_username_size));
}
} // Anonymous namespace } // Anonymous namespace
ConfigureSystem::ConfigureSystem(QWidget* parent) ConfigureSystem::ConfigureSystem(QWidget* parent)
@ -244,15 +250,13 @@ void ConfigureSystem::SelectUser(const QModelIndex& index) {
} }
void ConfigureSystem::AddUser() { void ConfigureSystem::AddUser() {
const auto uuid = Service::Account::UUID::Generate();
bool ok = false;
const auto username = const auto username =
QInputDialog::getText(this, tr("Enter Username"), tr("Enter a username for the new user:"), GetProfileUsernameFromUser(this, tr("Enter a username for the new user:"));
QLineEdit::Normal, QString(), &ok); if (username.isEmpty()) {
if (!ok)
return; return;
}
const auto uuid = Service::Account::UUID::Generate();
profile_manager->CreateNewUser(uuid, username.toStdString()); profile_manager->CreateNewUser(uuid, username.toStdString());
item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)});
@ -267,24 +271,15 @@ void ConfigureSystem::RenameUser() {
if (!profile_manager->GetProfileBase(*uuid, profile)) if (!profile_manager->GetProfileBase(*uuid, profile))
return; return;
bool ok = false; const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:"));
const auto old_username = GetAccountUsername(*profile_manager, *uuid); if (new_username.isEmpty()) {
const auto new_username =
QInputDialog::getText(this, tr("Enter Username"), tr("Enter a new username:"),
QLineEdit::Normal, old_username, &ok);
if (!ok)
return; return;
std::fill(profile.username.begin(), profile.username.end(), '\0');
const auto username_std = new_username.toStdString();
if (username_std.size() > profile.username.size()) {
std::copy_n(username_std.begin(), std::min(profile.username.size(), username_std.size()),
profile.username.begin());
} else {
std::copy(username_std.begin(), username_std.end(), profile.username.begin());
} }
const auto username_std = new_username.toStdString();
std::fill(profile.username.begin(), profile.username.end(), '\0');
std::copy(username_std.begin(), username_std.end(), profile.username.begin());
profile_manager->SetProfileBase(*uuid, profile); profile_manager->SetProfileBase(*uuid, profile);
item_model->setItem( item_model->setItem(

@ -0,0 +1,59 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QDialogButtonBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include "yuzu/util/limitable_input_dialog.h"
LimitableInputDialog::LimitableInputDialog(QWidget* parent) : QDialog{parent} {
CreateUI();
ConnectEvents();
}
LimitableInputDialog::~LimitableInputDialog() = default;
void LimitableInputDialog::CreateUI() {
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
text_label = new QLabel(this);
text_entry = new QLineEdit(this);
buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
auto* const layout = new QVBoxLayout;
layout->addWidget(text_label);
layout->addWidget(text_entry);
layout->addWidget(buttons);
setLayout(layout);
}
void LimitableInputDialog::ConnectEvents() {
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
QString LimitableInputDialog::GetText(QWidget* parent, const QString& title, const QString& text,
int min_character_limit, int max_character_limit) {
Q_ASSERT(min_character_limit <= max_character_limit);
LimitableInputDialog dialog{parent};
dialog.setWindowTitle(title);
dialog.text_label->setText(text);
dialog.text_entry->setMaxLength(max_character_limit);
auto* const ok_button = dialog.buttons->button(QDialogButtonBox::Ok);
ok_button->setEnabled(false);
connect(dialog.text_entry, &QLineEdit::textEdited, [&](const QString& new_text) {
ok_button->setEnabled(new_text.length() >= min_character_limit);
});
if (dialog.exec() != QDialog::Accepted) {
return {};
}
return dialog.text_entry->text();
}

@ -0,0 +1,31 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <QDialog>
class QDialogButtonBox;
class QLabel;
class QLineEdit;
/// A QDialog that functions similarly to QInputDialog, however, it allows
/// restricting the minimum and total number of characters that can be entered.
class LimitableInputDialog final : public QDialog {
Q_OBJECT
public:
explicit LimitableInputDialog(QWidget* parent = nullptr);
~LimitableInputDialog() override;
static QString GetText(QWidget* parent, const QString& title, const QString& text,
int min_character_limit, int max_character_limit);
private:
void CreateUI();
void ConnectEvents();
QLabel* text_label;
QLineEdit* text_entry;
QDialogButtonBox* buttons;
};