mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	qt: Move profile manager to own UI tab
This commit is contained in:
		
							parent
							
								
									c5262b1890
								
							
						
					
					
						commit
						54d7b664da
					
				| @ -37,6 +37,8 @@ add_executable(yuzu | |||||||
|     configuration/configure_input_simple.h |     configuration/configure_input_simple.h | ||||||
|     configuration/configure_mouse_advanced.cpp |     configuration/configure_mouse_advanced.cpp | ||||||
|     configuration/configure_mouse_advanced.h |     configuration/configure_mouse_advanced.h | ||||||
|  |     configuration/configure_profile_manager.cpp | ||||||
|  |     configuration/configure_profile_manager.h | ||||||
|     configuration/configure_system.cpp |     configuration/configure_system.cpp | ||||||
|     configuration/configure_system.h |     configuration/configure_system.h | ||||||
|     configuration/configure_per_general.cpp |     configuration/configure_per_general.cpp | ||||||
| @ -94,6 +96,7 @@ set(UIS | |||||||
|     configuration/configure_input_simple.ui |     configuration/configure_input_simple.ui | ||||||
|     configuration/configure_mouse_advanced.ui |     configuration/configure_mouse_advanced.ui | ||||||
|     configuration/configure_per_general.ui |     configuration/configure_per_general.ui | ||||||
|  |     configuration/configure_profile_manager.ui | ||||||
|     configuration/configure_system.ui |     configuration/configure_system.ui | ||||||
|     configuration/configure_touchscreen_advanced.ui |     configuration/configure_touchscreen_advanced.ui | ||||||
|     configuration/configure_web.ui |     configuration/configure_web.ui | ||||||
|  | |||||||
| @ -52,6 +52,11 @@ | |||||||
|          <string>System</string> |          <string>System</string> | ||||||
|         </attribute> |         </attribute> | ||||||
|        </widget> |        </widget> | ||||||
|  |        <widget class="ConfigureProfileManager" name="profileManagerTab"> | ||||||
|  |         <attribute name="title"> | ||||||
|  |          <string>Profiles</string> | ||||||
|  |         </attribute> | ||||||
|  |        </widget> | ||||||
|        <widget class="ConfigureInputSimple" name="inputTab"> |        <widget class="ConfigureInputSimple" name="inputTab"> | ||||||
|         <attribute name="title"> |         <attribute name="title"> | ||||||
|          <string>Input</string> |          <string>Input</string> | ||||||
| @ -103,6 +108,12 @@ | |||||||
|    <header>configuration/configure_system.h</header> |    <header>configuration/configure_system.h</header> | ||||||
|    <container>1</container> |    <container>1</container> | ||||||
|   </customwidget> |   </customwidget> | ||||||
|  |   <customwidget> | ||||||
|  |    <class>ConfigureProfileManager</class> | ||||||
|  |    <extends>QWidget</extends> | ||||||
|  |    <header>configuration/configure_profile_manager.h</header> | ||||||
|  |    <container>1</container> | ||||||
|  |   </customwidget> | ||||||
|   <customwidget> |   <customwidget> | ||||||
|    <class>ConfigureAudio</class> |    <class>ConfigureAudio</class> | ||||||
|    <extends>QWidget</extends> |    <extends>QWidget</extends> | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ void ConfigureDialog::applyConfiguration() { | |||||||
|     ui->generalTab->applyConfiguration(); |     ui->generalTab->applyConfiguration(); | ||||||
|     ui->gameListTab->applyConfiguration(); |     ui->gameListTab->applyConfiguration(); | ||||||
|     ui->systemTab->applyConfiguration(); |     ui->systemTab->applyConfiguration(); | ||||||
|  |     ui->profileManagerTab->applyConfiguration(); | ||||||
|     ui->inputTab->applyConfiguration(); |     ui->inputTab->applyConfiguration(); | ||||||
|     ui->graphicsTab->applyConfiguration(); |     ui->graphicsTab->applyConfiguration(); | ||||||
|     ui->audioTab->applyConfiguration(); |     ui->audioTab->applyConfiguration(); | ||||||
| @ -43,7 +44,7 @@ void ConfigureDialog::applyConfiguration() { | |||||||
| void ConfigureDialog::PopulateSelectionList() { | void ConfigureDialog::PopulateSelectionList() { | ||||||
|     const std::array<std::pair<QString, QStringList>, 4> items{ |     const std::array<std::pair<QString, QStringList>, 4> items{ | ||||||
|         {{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("Game List")}}, |         {{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("Game List")}}, | ||||||
|          {tr("System"), {tr("System"), tr("Audio")}}, |          {tr("System"), {tr("System"), tr("Profiles"), tr("Audio")}}, | ||||||
|          {tr("Graphics"), {tr("Graphics")}}, |          {tr("Graphics"), {tr("Graphics")}}, | ||||||
|          {tr("Controls"), {tr("Input")}}}}; |          {tr("Controls"), {tr("Input")}}}}; | ||||||
| 
 | 
 | ||||||
| @ -60,11 +61,15 @@ void ConfigureDialog::UpdateVisibleTabs() { | |||||||
|     if (items.isEmpty()) |     if (items.isEmpty()) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     const std::map<QString, QWidget*> widgets = { |     const std::map<QString, QWidget*> widgets = {{tr("General"), ui->generalTab}, | ||||||
|         {tr("General"), ui->generalTab}, {tr("System"), ui->systemTab}, |                                                  {tr("System"), ui->systemTab}, | ||||||
|         {tr("Input"), ui->inputTab},     {tr("Graphics"), ui->graphicsTab}, |                                                  {tr("Profiles"), ui->profileManagerTab}, | ||||||
|         {tr("Audio"), ui->audioTab},     {tr("Debug"), ui->debugTab}, |                                                  {tr("Input"), ui->inputTab}, | ||||||
|         {tr("Web"), ui->webTab},         {tr("Game List"), ui->gameListTab}}; |                                                  {tr("Graphics"), ui->graphicsTab}, | ||||||
|  |                                                  {tr("Audio"), ui->audioTab}, | ||||||
|  |                                                  {tr("Debug"), ui->debugTab}, | ||||||
|  |                                                  {tr("Web"), ui->webTab}, | ||||||
|  |                                                  {tr("Game List"), ui->gameListTab}}; | ||||||
| 
 | 
 | ||||||
|     ui->tabWidget->clear(); |     ui->tabWidget->clear(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										300
									
								
								src/yuzu/configuration/configure_profile_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								src/yuzu/configuration/configure_profile_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,300 @@ | |||||||
|  | // Copyright 2016 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <QFileDialog> | ||||||
|  | #include <QGraphicsItem> | ||||||
|  | #include <QGraphicsScene> | ||||||
|  | #include <QHeaderView> | ||||||
|  | #include <QMessageBox> | ||||||
|  | #include <QStandardItemModel> | ||||||
|  | #include <QTreeView> | ||||||
|  | #include <QVBoxLayout> | ||||||
|  | #include "common/assert.h" | ||||||
|  | #include "common/file_util.h" | ||||||
|  | #include "common/string_util.h" | ||||||
|  | #include "core/core.h" | ||||||
|  | #include "core/hle/service/acc/profile_manager.h" | ||||||
|  | #include "core/settings.h" | ||||||
|  | #include "ui_configure_profile_manager.h" | ||||||
|  | #include "yuzu/configuration/configure_profile_manager.h" | ||||||
|  | #include "yuzu/util/limitable_input_dialog.h" | ||||||
|  | 
 | ||||||
|  | namespace { | ||||||
|  | // Same backup JPEG used by acc IProfile::GetImage if no jpeg found
 | ||||||
|  | constexpr std::array<u8, 107> backup_jpeg{ | ||||||
|  |     0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, | ||||||
|  |     0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05, | ||||||
|  |     0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, | ||||||
|  |     0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13, | ||||||
|  |     0x12, 0x10, 0x13, 0x0f, 0x10, 0x10, 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, | ||||||
|  |     0x01, 0x01, 0x11, 0x00, 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, | ||||||
|  |     0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | QString GetImagePath(Service::Account::UUID uuid) { | ||||||
|  |     const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | ||||||
|  |                       "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; | ||||||
|  |     return QString::fromStdString(path); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QString GetAccountUsername(const Service::Account::ProfileManager& manager, | ||||||
|  |                            Service::Account::UUID uuid) { | ||||||
|  |     Service::Account::ProfileBase profile; | ||||||
|  |     if (!manager.GetProfileBase(uuid, profile)) { | ||||||
|  |         return {}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto text = Common::StringFromFixedZeroTerminatedBuffer( | ||||||
|  |         reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); | ||||||
|  |     return QString::fromStdString(text); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QString FormatUserEntryText(const QString& username, Service::Account::UUID uuid) { | ||||||
|  |     return ConfigureProfileManager::tr("%1\n%2", | ||||||
|  |                                        "%1 is the profile username, %2 is the formatted UUID (e.g. " | ||||||
|  |                                        "00112233-4455-6677-8899-AABBCCDDEEFF))") | ||||||
|  |         .arg(username, QString::fromStdString(uuid.FormatSwitch())); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QPixmap GetIcon(Service::Account::UUID uuid) { | ||||||
|  |     QPixmap icon{GetImagePath(uuid)}; | ||||||
|  | 
 | ||||||
|  |     if (!icon) { | ||||||
|  |         icon.fill(Qt::black); | ||||||
|  |         icon.loadFromData(backup_jpeg.data(), static_cast<u32>(backup_jpeg.size())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QString GetProfileUsernameFromUser(QWidget* parent, const QString& description_text) { | ||||||
|  |     return LimitableInputDialog::GetText(parent, ConfigureProfileManager::tr("Enter Username"), | ||||||
|  |                                          description_text, 1, | ||||||
|  |                                          static_cast<int>(Service::Account::profile_username_size)); | ||||||
|  | } | ||||||
|  | } // Anonymous namespace
 | ||||||
|  | 
 | ||||||
|  | ConfigureProfileManager ::ConfigureProfileManager(QWidget* parent) | ||||||
|  |     : QWidget(parent), ui(new Ui::ConfigureProfileManager), | ||||||
|  |       profile_manager(std::make_unique<Service::Account::ProfileManager>()) { | ||||||
|  |     ui->setupUi(this); | ||||||
|  | 
 | ||||||
|  |     layout = new QVBoxLayout; | ||||||
|  |     tree_view = new QTreeView; | ||||||
|  |     item_model = new QStandardItemModel(tree_view); | ||||||
|  |     tree_view->setModel(item_model); | ||||||
|  | 
 | ||||||
|  |     tree_view->setAlternatingRowColors(true); | ||||||
|  |     tree_view->setSelectionMode(QHeaderView::SingleSelection); | ||||||
|  |     tree_view->setSelectionBehavior(QHeaderView::SelectRows); | ||||||
|  |     tree_view->setVerticalScrollMode(QHeaderView::ScrollPerPixel); | ||||||
|  |     tree_view->setHorizontalScrollMode(QHeaderView::ScrollPerPixel); | ||||||
|  |     tree_view->setSortingEnabled(true); | ||||||
|  |     tree_view->setEditTriggers(QHeaderView::NoEditTriggers); | ||||||
|  |     tree_view->setUniformRowHeights(true); | ||||||
|  |     tree_view->setIconSize({64, 64}); | ||||||
|  |     tree_view->setContextMenuPolicy(Qt::NoContextMenu); | ||||||
|  | 
 | ||||||
|  |     item_model->insertColumns(0, 1); | ||||||
|  |     item_model->setHeaderData(0, Qt::Horizontal, "Users"); | ||||||
|  | 
 | ||||||
|  |     // We must register all custom types with the Qt Automoc system so that we are able to use it
 | ||||||
|  |     // with signals/slots. In this case, QList falls under the umbrells of custom types.
 | ||||||
|  |     qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>"); | ||||||
|  | 
 | ||||||
|  |     layout->setContentsMargins(0, 0, 0, 0); | ||||||
|  |     layout->setSpacing(0); | ||||||
|  |     layout->addWidget(tree_view); | ||||||
|  | 
 | ||||||
|  |     ui->scrollArea->setLayout(layout); | ||||||
|  | 
 | ||||||
|  |     connect(tree_view, &QTreeView::clicked, this, &ConfigureProfileManager::SelectUser); | ||||||
|  | 
 | ||||||
|  |     connect(ui->pm_add, &QPushButton::pressed, this, &ConfigureProfileManager::AddUser); | ||||||
|  |     connect(ui->pm_rename, &QPushButton::pressed, this, &ConfigureProfileManager::RenameUser); | ||||||
|  |     connect(ui->pm_remove, &QPushButton::pressed, this, &ConfigureProfileManager::DeleteUser); | ||||||
|  |     connect(ui->pm_set_image, &QPushButton::pressed, this, &ConfigureProfileManager::SetUserImage); | ||||||
|  | 
 | ||||||
|  |     scene = new QGraphicsScene; | ||||||
|  |     ui->current_user_icon->setScene(scene); | ||||||
|  | 
 | ||||||
|  |     this->setConfiguration(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ConfigureProfileManager::~ConfigureProfileManager() = default; | ||||||
|  | 
 | ||||||
|  | void ConfigureProfileManager::setConfiguration() { | ||||||
|  |     enabled = !Core::System::GetInstance().IsPoweredOn(); | ||||||
|  |     item_model->removeRows(0, item_model->rowCount()); | ||||||
|  |     list_items.clear(); | ||||||
|  | 
 | ||||||
|  |     PopulateUserList(); | ||||||
|  |     UpdateCurrentUser(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureProfileManager::PopulateUserList() { | ||||||
|  |     const auto& profiles = profile_manager->GetAllUsers(); | ||||||
|  |     for (const auto& user : profiles) { | ||||||
|  |         Service::Account::ProfileBase profile; | ||||||
|  |         if (!profile_manager->GetProfileBase(user, profile)) | ||||||
|  |             continue; | ||||||
|  | 
 | ||||||
|  |         const auto username = Common::StringFromFixedZeroTerminatedBuffer( | ||||||
|  |             reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); | ||||||
|  | 
 | ||||||
|  |         list_items.push_back(QList<QStandardItem*>{new QStandardItem{ | ||||||
|  |             GetIcon(user), FormatUserEntryText(QString::fromStdString(username), user)}}); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (const auto& item : list_items) | ||||||
|  |         item_model->appendRow(item); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureProfileManager::UpdateCurrentUser() { | ||||||
|  |     ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS); | ||||||
|  | 
 | ||||||
|  |     const auto& current_user = profile_manager->GetUser(Settings::values.current_user); | ||||||
|  |     ASSERT(current_user); | ||||||
|  |     const auto username = GetAccountUsername(*profile_manager, *current_user); | ||||||
|  | 
 | ||||||
|  |     scene->clear(); | ||||||
|  |     scene->addPixmap( | ||||||
|  |         GetIcon(*current_user).scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | ||||||
|  |     ui->current_user_username->setText(username); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureProfileManager::applyConfiguration() { | ||||||
|  |     if (!enabled) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     Settings::Apply(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureProfileManager::SelectUser(const QModelIndex& index) { | ||||||
|  |     Settings::values.current_user = | ||||||
|  |         std::clamp<s32>(index.row(), 0, static_cast<s32>(profile_manager->GetUserCount() - 1)); | ||||||
|  | 
 | ||||||
|  |     UpdateCurrentUser(); | ||||||
|  | 
 | ||||||
|  |     ui->pm_remove->setEnabled(profile_manager->GetUserCount() >= 2); | ||||||
|  |     ui->pm_rename->setEnabled(true); | ||||||
|  |     ui->pm_set_image->setEnabled(true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureProfileManager::AddUser() { | ||||||
|  |     const auto username = | ||||||
|  |         GetProfileUsernameFromUser(this, tr("Enter a username for the new user:")); | ||||||
|  |     if (username.isEmpty()) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto uuid = Service::Account::UUID::Generate(); | ||||||
|  |     profile_manager->CreateNewUser(uuid, username.toStdString()); | ||||||
|  | 
 | ||||||
|  |     item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureProfileManager::RenameUser() { | ||||||
|  |     const auto user = tree_view->currentIndex().row(); | ||||||
|  |     const auto uuid = profile_manager->GetUser(user); | ||||||
|  |     ASSERT(uuid); | ||||||
|  | 
 | ||||||
|  |     Service::Account::ProfileBase profile; | ||||||
|  |     if (!profile_manager->GetProfileBase(*uuid, profile)) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:")); | ||||||
|  |     if (new_username.isEmpty()) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  | 
 | ||||||
|  |     item_model->setItem( | ||||||
|  |         user, 0, | ||||||
|  |         new QStandardItem{GetIcon(*uuid), | ||||||
|  |                           FormatUserEntryText(QString::fromStdString(username_std), *uuid)}); | ||||||
|  |     UpdateCurrentUser(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureProfileManager::DeleteUser() { | ||||||
|  |     const auto index = tree_view->currentIndex().row(); | ||||||
|  |     const auto uuid = profile_manager->GetUser(index); | ||||||
|  |     ASSERT(uuid); | ||||||
|  |     const auto username = GetAccountUsername(*profile_manager, *uuid); | ||||||
|  | 
 | ||||||
|  |     const auto confirm = QMessageBox::question( | ||||||
|  |         this, tr("Confirm Delete"), | ||||||
|  |         tr("You are about to delete user with name \"%1\". Are you sure?").arg(username)); | ||||||
|  | 
 | ||||||
|  |     if (confirm == QMessageBox::No) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     if (Settings::values.current_user == tree_view->currentIndex().row()) | ||||||
|  |         Settings::values.current_user = 0; | ||||||
|  |     UpdateCurrentUser(); | ||||||
|  | 
 | ||||||
|  |     if (!profile_manager->RemoveUser(*uuid)) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     item_model->removeRows(tree_view->currentIndex().row(), 1); | ||||||
|  |     tree_view->clearSelection(); | ||||||
|  | 
 | ||||||
|  |     ui->pm_remove->setEnabled(false); | ||||||
|  |     ui->pm_rename->setEnabled(false); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureProfileManager::SetUserImage() { | ||||||
|  |     const auto index = tree_view->currentIndex().row(); | ||||||
|  |     const auto uuid = profile_manager->GetUser(index); | ||||||
|  |     ASSERT(uuid); | ||||||
|  | 
 | ||||||
|  |     const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), | ||||||
|  |                                                    tr("JPEG Images (*.jpg *.jpeg)")); | ||||||
|  | 
 | ||||||
|  |     if (file.isEmpty()) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto image_path = GetImagePath(*uuid); | ||||||
|  |     if (QFile::exists(image_path) && !QFile::remove(image_path)) { | ||||||
|  |         QMessageBox::warning( | ||||||
|  |             this, tr("Error deleting image"), | ||||||
|  |             tr("Error occurred attempting to overwrite previous image at: %1.").arg(image_path)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto raw_path = QString::fromStdString( | ||||||
|  |         FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010"); | ||||||
|  |     const QFileInfo raw_info{raw_path}; | ||||||
|  |     if (raw_info.exists() && !raw_info.isDir() && !QFile::remove(raw_path)) { | ||||||
|  |         QMessageBox::warning(this, tr("Error deleting file"), | ||||||
|  |                              tr("Unable to delete existing file: %1.").arg(raw_path)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const QString absolute_dst_path = QFileInfo{image_path}.absolutePath(); | ||||||
|  |     if (!QDir{raw_path}.mkpath(absolute_dst_path)) { | ||||||
|  |         QMessageBox::warning( | ||||||
|  |             this, tr("Error creating user image directory"), | ||||||
|  |             tr("Unable to create directory %1 for storing user images.").arg(absolute_dst_path)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!QFile::copy(file, image_path)) { | ||||||
|  |         QMessageBox::warning(this, tr("Error copying user image"), | ||||||
|  |                              tr("Unable to copy image from %1 to %2").arg(file, image_path)); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto username = GetAccountUsername(*profile_manager, *uuid); | ||||||
|  |     item_model->setItem(index, 0, | ||||||
|  |                         new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)}); | ||||||
|  |     UpdateCurrentUser(); | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								src/yuzu/configuration/configure_profile_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/yuzu/configuration/configure_profile_manager.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | |||||||
|  | // Copyright 2016 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | 
 | ||||||
|  | #include <QList> | ||||||
|  | #include <QWidget> | ||||||
|  | 
 | ||||||
|  | class QGraphicsScene; | ||||||
|  | class QStandardItem; | ||||||
|  | class QStandardItemModel; | ||||||
|  | class QTreeView; | ||||||
|  | class QVBoxLayout; | ||||||
|  | 
 | ||||||
|  | namespace Service::Account { | ||||||
|  | class ProfileManager; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Ui { | ||||||
|  | class ConfigureProfileManager; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class ConfigureProfileManager : public QWidget { | ||||||
|  |     Q_OBJECT | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     explicit ConfigureProfileManager(QWidget* parent = nullptr); | ||||||
|  |     ~ConfigureProfileManager() override; | ||||||
|  | 
 | ||||||
|  |     void applyConfiguration(); | ||||||
|  |     void setConfiguration(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void PopulateUserList(); | ||||||
|  |     void UpdateCurrentUser(); | ||||||
|  | 
 | ||||||
|  |     void SelectUser(const QModelIndex& index); | ||||||
|  |     void AddUser(); | ||||||
|  |     void RenameUser(); | ||||||
|  |     void DeleteUser(); | ||||||
|  |     void SetUserImage(); | ||||||
|  | 
 | ||||||
|  |     QVBoxLayout* layout; | ||||||
|  |     QTreeView* tree_view; | ||||||
|  |     QStandardItemModel* item_model; | ||||||
|  |     QGraphicsScene* scene; | ||||||
|  | 
 | ||||||
|  |     std::vector<QList<QStandardItem*>> list_items; | ||||||
|  | 
 | ||||||
|  |     std::unique_ptr<Ui::ConfigureProfileManager> ui; | ||||||
|  |     bool enabled = false; | ||||||
|  | 
 | ||||||
|  |     std::unique_ptr<Service::Account::ProfileManager> profile_manager; | ||||||
|  | }; | ||||||
							
								
								
									
										172
									
								
								src/yuzu/configuration/configure_profile_manager.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								src/yuzu/configuration/configure_profile_manager.ui
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,172 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <ui version="4.0"> | ||||||
|  |  <class>ConfigureProfileManager</class> | ||||||
|  |  <widget class="QWidget" name="ConfigureProfileManager"> | ||||||
|  |   <property name="geometry"> | ||||||
|  |    <rect> | ||||||
|  |     <x>0</x> | ||||||
|  |     <y>0</y> | ||||||
|  |     <width>366</width> | ||||||
|  |     <height>483</height> | ||||||
|  |    </rect> | ||||||
|  |   </property> | ||||||
|  |   <property name="windowTitle"> | ||||||
|  |    <string>Form</string> | ||||||
|  |   </property> | ||||||
|  |   <layout class="QHBoxLayout" name="horizontalLayout"> | ||||||
|  |    <item> | ||||||
|  |     <layout class="QVBoxLayout" name="verticalLayout"> | ||||||
|  |      <item> | ||||||
|  |       <widget class="QGroupBox" name="gridGroupBox"> | ||||||
|  |        <property name="title"> | ||||||
|  |         <string>Profile Manager</string> | ||||||
|  |        </property> | ||||||
|  |        <layout class="QGridLayout" name="gridLayout_2"> | ||||||
|  |         <property name="sizeConstraint"> | ||||||
|  |          <enum>QLayout::SetNoConstraint</enum> | ||||||
|  |         </property> | ||||||
|  |         <item row="0" column="0"> | ||||||
|  |          <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QLabel" name="label"> | ||||||
|  |             <property name="sizePolicy"> | ||||||
|  |              <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> | ||||||
|  |               <horstretch>0</horstretch> | ||||||
|  |               <verstretch>0</verstretch> | ||||||
|  |              </sizepolicy> | ||||||
|  |             </property> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Current User</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QGraphicsView" name="current_user_icon"> | ||||||
|  |             <property name="minimumSize"> | ||||||
|  |              <size> | ||||||
|  |               <width>48</width> | ||||||
|  |               <height>48</height> | ||||||
|  |              </size> | ||||||
|  |             </property> | ||||||
|  |             <property name="maximumSize"> | ||||||
|  |              <size> | ||||||
|  |               <width>48</width> | ||||||
|  |               <height>48</height> | ||||||
|  |              </size> | ||||||
|  |             </property> | ||||||
|  |             <property name="verticalScrollBarPolicy"> | ||||||
|  |              <enum>Qt::ScrollBarAlwaysOff</enum> | ||||||
|  |             </property> | ||||||
|  |             <property name="horizontalScrollBarPolicy"> | ||||||
|  |              <enum>Qt::ScrollBarAlwaysOff</enum> | ||||||
|  |             </property> | ||||||
|  |             <property name="interactive"> | ||||||
|  |              <bool>false</bool> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QLabel" name="current_user_username"> | ||||||
|  |             <property name="sizePolicy"> | ||||||
|  |              <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> | ||||||
|  |               <horstretch>0</horstretch> | ||||||
|  |               <verstretch>0</verstretch> | ||||||
|  |              </sizepolicy> | ||||||
|  |             </property> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Username</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |         <item row="1" column="0"> | ||||||
|  |          <widget class="QScrollArea" name="scrollArea"> | ||||||
|  |           <property name="sizePolicy"> | ||||||
|  |            <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||||||
|  |             <horstretch>0</horstretch> | ||||||
|  |             <verstretch>0</verstretch> | ||||||
|  |            </sizepolicy> | ||||||
|  |           </property> | ||||||
|  |           <property name="frameShape"> | ||||||
|  |            <enum>QFrame::StyledPanel</enum> | ||||||
|  |           </property> | ||||||
|  |           <property name="widgetResizable"> | ||||||
|  |            <bool>false</bool> | ||||||
|  |           </property> | ||||||
|  |          </widget> | ||||||
|  |         </item> | ||||||
|  |         <item row="2" column="0"> | ||||||
|  |          <layout class="QHBoxLayout" name="horizontalLayout_3"> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QPushButton" name="pm_set_image"> | ||||||
|  |             <property name="enabled"> | ||||||
|  |              <bool>false</bool> | ||||||
|  |             </property> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Set Image</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <spacer name="horizontalSpacer"> | ||||||
|  |             <property name="orientation"> | ||||||
|  |              <enum>Qt::Horizontal</enum> | ||||||
|  |             </property> | ||||||
|  |             <property name="sizeHint" stdset="0"> | ||||||
|  |              <size> | ||||||
|  |               <width>40</width> | ||||||
|  |               <height>20</height> | ||||||
|  |              </size> | ||||||
|  |             </property> | ||||||
|  |            </spacer> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QPushButton" name="pm_add"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Add</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QPushButton" name="pm_rename"> | ||||||
|  |             <property name="enabled"> | ||||||
|  |              <bool>false</bool> | ||||||
|  |             </property> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Rename</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QPushButton" name="pm_remove"> | ||||||
|  |             <property name="enabled"> | ||||||
|  |              <bool>false</bool> | ||||||
|  |             </property> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Remove</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |        </layout> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |      <item> | ||||||
|  |       <widget class="QLabel" name="label_disable_info"> | ||||||
|  |        <property name="text"> | ||||||
|  |         <string>Profile management is available only when game is not running.</string> | ||||||
|  |        </property> | ||||||
|  |        <property name="wordWrap"> | ||||||
|  |         <bool>true</bool> | ||||||
|  |        </property> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |     </layout> | ||||||
|  |    </item> | ||||||
|  |   </layout> | ||||||
|  |  </widget> | ||||||
|  |  <resources/> | ||||||
|  |  <connections/> | ||||||
|  | </ui> | ||||||
| @ -15,7 +15,6 @@ | |||||||
| #include "common/file_util.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/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" | ||||||
| @ -36,64 +35,9 @@ constexpr std::array<int, 12> days_in_month = {{ | |||||||
|     30, |     30, | ||||||
|     31, |     31, | ||||||
| }}; | }}; | ||||||
| 
 |  | ||||||
| // Same backup JPEG used by acc IProfile::GetImage if no jpeg found
 |  | ||||||
| constexpr std::array<u8, 107> backup_jpeg{ |  | ||||||
|     0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, |  | ||||||
|     0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05, |  | ||||||
|     0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, |  | ||||||
|     0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13, |  | ||||||
|     0x12, 0x10, 0x13, 0x0f, 0x10, 0x10, 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, |  | ||||||
|     0x01, 0x01, 0x11, 0x00, 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, |  | ||||||
|     0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| QString GetImagePath(Service::Account::UUID uuid) { |  | ||||||
|     const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + |  | ||||||
|                       "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; |  | ||||||
|     return QString::fromStdString(path); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QString GetAccountUsername(const Service::Account::ProfileManager& manager, |  | ||||||
|                            Service::Account::UUID uuid) { |  | ||||||
|     Service::Account::ProfileBase profile; |  | ||||||
|     if (!manager.GetProfileBase(uuid, profile)) { |  | ||||||
|         return {}; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const auto text = Common::StringFromFixedZeroTerminatedBuffer( |  | ||||||
|         reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); |  | ||||||
|     return QString::fromStdString(text); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QString FormatUserEntryText(const QString& username, Service::Account::UUID uuid) { |  | ||||||
|     return ConfigureSystem::tr("%1\n%2", |  | ||||||
|                                "%1 is the profile username, %2 is the formatted UUID (e.g. " |  | ||||||
|                                "00112233-4455-6677-8899-AABBCCDDEEFF))") |  | ||||||
|         .arg(username, QString::fromStdString(uuid.FormatSwitch())); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QPixmap GetIcon(Service::Account::UUID uuid) { |  | ||||||
|     QPixmap icon{GetImagePath(uuid)}; |  | ||||||
| 
 |  | ||||||
|     if (!icon) { |  | ||||||
|         icon.fill(Qt::black); |  | ||||||
|         icon.loadFromData(backup_jpeg.data(), static_cast<u32>(backup_jpeg.size())); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     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) : QWidget(parent), ui(new Ui::ConfigureSystem) { | ||||||
|     : QWidget(parent), ui(new Ui::ConfigureSystem), |  | ||||||
|       profile_manager(std::make_unique<Service::Account::ProfileManager>()) { |  | ||||||
|     ui->setupUi(this); |     ui->setupUi(this); | ||||||
|     connect(ui->combo_birthmonth, |     connect(ui->combo_birthmonth, | ||||||
|             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, |             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, | ||||||
| @ -101,51 +45,12 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) | |||||||
|     connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, |     connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, | ||||||
|             &ConfigureSystem::RefreshConsoleID); |             &ConfigureSystem::RefreshConsoleID); | ||||||
| 
 | 
 | ||||||
|     layout = new QVBoxLayout; |  | ||||||
|     tree_view = new QTreeView; |  | ||||||
|     item_model = new QStandardItemModel(tree_view); |  | ||||||
|     tree_view->setModel(item_model); |  | ||||||
| 
 |  | ||||||
|     tree_view->setAlternatingRowColors(true); |  | ||||||
|     tree_view->setSelectionMode(QHeaderView::SingleSelection); |  | ||||||
|     tree_view->setSelectionBehavior(QHeaderView::SelectRows); |  | ||||||
|     tree_view->setVerticalScrollMode(QHeaderView::ScrollPerPixel); |  | ||||||
|     tree_view->setHorizontalScrollMode(QHeaderView::ScrollPerPixel); |  | ||||||
|     tree_view->setSortingEnabled(true); |  | ||||||
|     tree_view->setEditTriggers(QHeaderView::NoEditTriggers); |  | ||||||
|     tree_view->setUniformRowHeights(true); |  | ||||||
|     tree_view->setIconSize({64, 64}); |  | ||||||
|     tree_view->setContextMenuPolicy(Qt::NoContextMenu); |  | ||||||
| 
 |  | ||||||
|     item_model->insertColumns(0, 1); |  | ||||||
|     item_model->setHeaderData(0, Qt::Horizontal, "Users"); |  | ||||||
| 
 |  | ||||||
|     // We must register all custom types with the Qt Automoc system so that we are able to use it
 |  | ||||||
|     // with signals/slots. In this case, QList falls under the umbrells of custom types.
 |  | ||||||
|     qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>"); |  | ||||||
| 
 |  | ||||||
|     layout->setContentsMargins(0, 0, 0, 0); |  | ||||||
|     layout->setSpacing(0); |  | ||||||
|     layout->addWidget(tree_view); |  | ||||||
| 
 |  | ||||||
|     ui->scrollArea->setLayout(layout); |  | ||||||
| 
 |  | ||||||
|     connect(tree_view, &QTreeView::clicked, this, &ConfigureSystem::SelectUser); |  | ||||||
| 
 |  | ||||||
|     connect(ui->pm_add, &QPushButton::pressed, this, &ConfigureSystem::AddUser); |  | ||||||
|     connect(ui->pm_rename, &QPushButton::pressed, this, &ConfigureSystem::RenameUser); |  | ||||||
|     connect(ui->pm_remove, &QPushButton::pressed, this, &ConfigureSystem::DeleteUser); |  | ||||||
|     connect(ui->pm_set_image, &QPushButton::pressed, this, &ConfigureSystem::SetUserImage); |  | ||||||
| 
 |  | ||||||
|     connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) { |     connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) { | ||||||
|         ui->rng_seed_edit->setEnabled(checked); |         ui->rng_seed_edit->setEnabled(checked); | ||||||
|         if (!checked) |         if (!checked) | ||||||
|             ui->rng_seed_edit->setText(QStringLiteral("00000000")); |             ui->rng_seed_edit->setText(QStringLiteral("00000000")); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     scene = new QGraphicsScene; |  | ||||||
|     ui->current_user_icon->setScene(scene); |  | ||||||
| 
 |  | ||||||
|     this->setConfiguration(); |     this->setConfiguration(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -156,12 +61,6 @@ void ConfigureSystem::setConfiguration() { | |||||||
| 
 | 
 | ||||||
|     ui->combo_language->setCurrentIndex(Settings::values.language_index); |     ui->combo_language->setCurrentIndex(Settings::values.language_index); | ||||||
| 
 | 
 | ||||||
|     item_model->removeRows(0, item_model->rowCount()); |  | ||||||
|     list_items.clear(); |  | ||||||
| 
 |  | ||||||
|     PopulateUserList(); |  | ||||||
|     UpdateCurrentUser(); |  | ||||||
| 
 |  | ||||||
|     ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value()); |     ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value()); | ||||||
|     ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value()); |     ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value()); | ||||||
| 
 | 
 | ||||||
| @ -170,37 +69,6 @@ void ConfigureSystem::setConfiguration() { | |||||||
|     ui->rng_seed_edit->setText(rng_seed); |     ui->rng_seed_edit->setText(rng_seed); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::PopulateUserList() { |  | ||||||
|     const auto& profiles = profile_manager->GetAllUsers(); |  | ||||||
|     for (const auto& user : profiles) { |  | ||||||
|         Service::Account::ProfileBase profile; |  | ||||||
|         if (!profile_manager->GetProfileBase(user, profile)) |  | ||||||
|             continue; |  | ||||||
| 
 |  | ||||||
|         const auto username = Common::StringFromFixedZeroTerminatedBuffer( |  | ||||||
|             reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); |  | ||||||
| 
 |  | ||||||
|         list_items.push_back(QList<QStandardItem*>{new QStandardItem{ |  | ||||||
|             GetIcon(user), FormatUserEntryText(QString::fromStdString(username), user)}}); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     for (const auto& item : list_items) |  | ||||||
|         item_model->appendRow(item); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ConfigureSystem::UpdateCurrentUser() { |  | ||||||
|     ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS); |  | ||||||
| 
 |  | ||||||
|     const auto& current_user = profile_manager->GetUser(Settings::values.current_user); |  | ||||||
|     ASSERT(current_user); |  | ||||||
|     const auto username = GetAccountUsername(*profile_manager, *current_user); |  | ||||||
| 
 |  | ||||||
|     scene->clear(); |  | ||||||
|     scene->addPixmap( |  | ||||||
|         GetIcon(*current_user).scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); |  | ||||||
|     ui->current_user_username->setText(username); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ConfigureSystem::ReadSystemSettings() {} | void ConfigureSystem::ReadSystemSettings() {} | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::applyConfiguration() { | void ConfigureSystem::applyConfiguration() { | ||||||
| @ -256,130 +124,3 @@ void ConfigureSystem::RefreshConsoleID() { | |||||||
|     ui->label_console_id->setText( |     ui->label_console_id->setText( | ||||||
|         tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper())); |         tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper())); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| void ConfigureSystem::SelectUser(const QModelIndex& index) { |  | ||||||
|     Settings::values.current_user = |  | ||||||
|         std::clamp<s32>(index.row(), 0, static_cast<s32>(profile_manager->GetUserCount() - 1)); |  | ||||||
| 
 |  | ||||||
|     UpdateCurrentUser(); |  | ||||||
| 
 |  | ||||||
|     ui->pm_remove->setEnabled(profile_manager->GetUserCount() >= 2); |  | ||||||
|     ui->pm_rename->setEnabled(true); |  | ||||||
|     ui->pm_set_image->setEnabled(true); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ConfigureSystem::AddUser() { |  | ||||||
|     const auto username = |  | ||||||
|         GetProfileUsernameFromUser(this, tr("Enter a username for the new user:")); |  | ||||||
|     if (username.isEmpty()) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const auto uuid = Service::Account::UUID::Generate(); |  | ||||||
|     profile_manager->CreateNewUser(uuid, username.toStdString()); |  | ||||||
| 
 |  | ||||||
|     item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ConfigureSystem::RenameUser() { |  | ||||||
|     const auto user = tree_view->currentIndex().row(); |  | ||||||
|     const auto uuid = profile_manager->GetUser(user); |  | ||||||
|     ASSERT(uuid); |  | ||||||
| 
 |  | ||||||
|     Service::Account::ProfileBase profile; |  | ||||||
|     if (!profile_manager->GetProfileBase(*uuid, profile)) |  | ||||||
|         return; |  | ||||||
| 
 |  | ||||||
|     const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:")); |  | ||||||
|     if (new_username.isEmpty()) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     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); |  | ||||||
| 
 |  | ||||||
|     item_model->setItem( |  | ||||||
|         user, 0, |  | ||||||
|         new QStandardItem{GetIcon(*uuid), |  | ||||||
|                           FormatUserEntryText(QString::fromStdString(username_std), *uuid)}); |  | ||||||
|     UpdateCurrentUser(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ConfigureSystem::DeleteUser() { |  | ||||||
|     const auto index = tree_view->currentIndex().row(); |  | ||||||
|     const auto uuid = profile_manager->GetUser(index); |  | ||||||
|     ASSERT(uuid); |  | ||||||
|     const auto username = GetAccountUsername(*profile_manager, *uuid); |  | ||||||
| 
 |  | ||||||
|     const auto confirm = QMessageBox::question( |  | ||||||
|         this, tr("Confirm Delete"), |  | ||||||
|         tr("You are about to delete user with name \"%1\". Are you sure?").arg(username)); |  | ||||||
| 
 |  | ||||||
|     if (confirm == QMessageBox::No) |  | ||||||
|         return; |  | ||||||
| 
 |  | ||||||
|     if (Settings::values.current_user == tree_view->currentIndex().row()) |  | ||||||
|         Settings::values.current_user = 0; |  | ||||||
|     UpdateCurrentUser(); |  | ||||||
| 
 |  | ||||||
|     if (!profile_manager->RemoveUser(*uuid)) |  | ||||||
|         return; |  | ||||||
| 
 |  | ||||||
|     item_model->removeRows(tree_view->currentIndex().row(), 1); |  | ||||||
|     tree_view->clearSelection(); |  | ||||||
| 
 |  | ||||||
|     ui->pm_remove->setEnabled(false); |  | ||||||
|     ui->pm_rename->setEnabled(false); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ConfigureSystem::SetUserImage() { |  | ||||||
|     const auto index = tree_view->currentIndex().row(); |  | ||||||
|     const auto uuid = profile_manager->GetUser(index); |  | ||||||
|     ASSERT(uuid); |  | ||||||
| 
 |  | ||||||
|     const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), |  | ||||||
|                                                    tr("JPEG Images (*.jpg *.jpeg)")); |  | ||||||
| 
 |  | ||||||
|     if (file.isEmpty()) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const auto image_path = GetImagePath(*uuid); |  | ||||||
|     if (QFile::exists(image_path) && !QFile::remove(image_path)) { |  | ||||||
|         QMessageBox::warning( |  | ||||||
|             this, tr("Error deleting image"), |  | ||||||
|             tr("Error occurred attempting to overwrite previous image at: %1.").arg(image_path)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const auto raw_path = QString::fromStdString( |  | ||||||
|         FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010"); |  | ||||||
|     const QFileInfo raw_info{raw_path}; |  | ||||||
|     if (raw_info.exists() && !raw_info.isDir() && !QFile::remove(raw_path)) { |  | ||||||
|         QMessageBox::warning(this, tr("Error deleting file"), |  | ||||||
|                              tr("Unable to delete existing file: %1.").arg(raw_path)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const QString absolute_dst_path = QFileInfo{image_path}.absolutePath(); |  | ||||||
|     if (!QDir{raw_path}.mkpath(absolute_dst_path)) { |  | ||||||
|         QMessageBox::warning( |  | ||||||
|             this, tr("Error creating user image directory"), |  | ||||||
|             tr("Unable to create directory %1 for storing user images.").arg(absolute_dst_path)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (!QFile::copy(file, image_path)) { |  | ||||||
|         QMessageBox::warning(this, tr("Error copying user image"), |  | ||||||
|                              tr("Unable to copy image from %1 to %2").arg(file, image_path)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const auto username = GetAccountUsername(*profile_manager, *uuid); |  | ||||||
|     item_model->setItem(index, 0, |  | ||||||
|                         new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)}); |  | ||||||
|     UpdateCurrentUser(); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -9,16 +9,6 @@ | |||||||
| #include <QList> | #include <QList> | ||||||
| #include <QWidget> | #include <QWidget> | ||||||
| 
 | 
 | ||||||
| class QGraphicsScene; |  | ||||||
| class QStandardItem; |  | ||||||
| class QStandardItemModel; |  | ||||||
| class QTreeView; |  | ||||||
| class QVBoxLayout; |  | ||||||
| 
 |  | ||||||
| namespace Service::Account { |  | ||||||
| class ProfileManager; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| namespace Ui { | namespace Ui { | ||||||
| class ConfigureSystem; | class ConfigureSystem; | ||||||
| } | } | ||||||
| @ -39,21 +29,6 @@ private: | |||||||
|     void UpdateBirthdayComboBox(int birthmonth_index); |     void UpdateBirthdayComboBox(int birthmonth_index); | ||||||
|     void RefreshConsoleID(); |     void RefreshConsoleID(); | ||||||
| 
 | 
 | ||||||
|     void PopulateUserList(); |  | ||||||
|     void UpdateCurrentUser(); |  | ||||||
|     void SelectUser(const QModelIndex& index); |  | ||||||
|     void AddUser(); |  | ||||||
|     void RenameUser(); |  | ||||||
|     void DeleteUser(); |  | ||||||
|     void SetUserImage(); |  | ||||||
| 
 |  | ||||||
|     QVBoxLayout* layout; |  | ||||||
|     QTreeView* tree_view; |  | ||||||
|     QStandardItemModel* item_model; |  | ||||||
|     QGraphicsScene* scene; |  | ||||||
| 
 |  | ||||||
|     std::vector<QList<QStandardItem*>> list_items; |  | ||||||
| 
 |  | ||||||
|     std::unique_ptr<Ui::ConfigureSystem> ui; |     std::unique_ptr<Ui::ConfigureSystem> ui; | ||||||
|     bool enabled = false; |     bool enabled = false; | ||||||
| 
 | 
 | ||||||
| @ -61,6 +36,4 @@ private: | |||||||
|     int birthday = 0; |     int birthday = 0; | ||||||
|     int language_index = 0; |     int language_index = 0; | ||||||
|     int sound_index = 0; |     int sound_index = 0; | ||||||
| 
 |  | ||||||
|     std::unique_ptr<Service::Account::ProfileManager> profile_manager; |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -280,141 +280,17 @@ | |||||||
|       </widget> |       </widget> | ||||||
|      </item> |      </item> | ||||||
|      <item> |      <item> | ||||||
|       <widget class="QGroupBox" name="gridGroupBox"> |       <spacer name="verticalSpacer"> | ||||||
|        <property name="title"> |        <property name="orientation"> | ||||||
|         <string>Profile Manager</string> |         <enum>Qt::Vertical</enum> | ||||||
|        </property> |        </property> | ||||||
|        <layout class="QGridLayout" name="gridLayout_2"> |        <property name="sizeHint" stdset="0"> | ||||||
|         <property name="sizeConstraint"> |         <size> | ||||||
|          <enum>QLayout::SetNoConstraint</enum> |          <width>20</width> | ||||||
|         </property> |          <height>40</height> | ||||||
|         <item row="0" column="0"> |         </size> | ||||||
|          <layout class="QHBoxLayout" name="horizontalLayout_2"> |        </property> | ||||||
|           <item> |       </spacer> | ||||||
|            <widget class="QLabel" name="label"> |  | ||||||
|             <property name="sizePolicy"> |  | ||||||
|              <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> |  | ||||||
|               <horstretch>0</horstretch> |  | ||||||
|               <verstretch>0</verstretch> |  | ||||||
|              </sizepolicy> |  | ||||||
|             </property> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>Current User</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QGraphicsView" name="current_user_icon"> |  | ||||||
|             <property name="minimumSize"> |  | ||||||
|              <size> |  | ||||||
|               <width>48</width> |  | ||||||
|               <height>48</height> |  | ||||||
|              </size> |  | ||||||
|             </property> |  | ||||||
|             <property name="maximumSize"> |  | ||||||
|              <size> |  | ||||||
|               <width>48</width> |  | ||||||
|               <height>48</height> |  | ||||||
|              </size> |  | ||||||
|             </property> |  | ||||||
|             <property name="verticalScrollBarPolicy"> |  | ||||||
|              <enum>Qt::ScrollBarAlwaysOff</enum> |  | ||||||
|             </property> |  | ||||||
|             <property name="horizontalScrollBarPolicy"> |  | ||||||
|              <enum>Qt::ScrollBarAlwaysOff</enum> |  | ||||||
|             </property> |  | ||||||
|             <property name="interactive"> |  | ||||||
|              <bool>false</bool> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QLabel" name="current_user_username"> |  | ||||||
|             <property name="sizePolicy"> |  | ||||||
|              <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> |  | ||||||
|               <horstretch>0</horstretch> |  | ||||||
|               <verstretch>0</verstretch> |  | ||||||
|              </sizepolicy> |  | ||||||
|             </property> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>Username</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|          </layout> |  | ||||||
|         </item> |  | ||||||
|         <item row="1" column="0"> |  | ||||||
|          <widget class="QScrollArea" name="scrollArea"> |  | ||||||
|           <property name="sizePolicy"> |  | ||||||
|            <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> |  | ||||||
|             <horstretch>0</horstretch> |  | ||||||
|             <verstretch>0</verstretch> |  | ||||||
|            </sizepolicy> |  | ||||||
|           </property> |  | ||||||
|           <property name="frameShape"> |  | ||||||
|            <enum>QFrame::StyledPanel</enum> |  | ||||||
|           </property> |  | ||||||
|           <property name="widgetResizable"> |  | ||||||
|            <bool>false</bool> |  | ||||||
|           </property> |  | ||||||
|          </widget> |  | ||||||
|         </item> |  | ||||||
|         <item row="2" column="0"> |  | ||||||
|          <layout class="QHBoxLayout" name="horizontalLayout_3"> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QPushButton" name="pm_set_image"> |  | ||||||
|             <property name="enabled"> |  | ||||||
|              <bool>false</bool> |  | ||||||
|             </property> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>Set Image</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <spacer name="horizontalSpacer"> |  | ||||||
|             <property name="orientation"> |  | ||||||
|              <enum>Qt::Horizontal</enum> |  | ||||||
|             </property> |  | ||||||
|             <property name="sizeHint" stdset="0"> |  | ||||||
|              <size> |  | ||||||
|               <width>40</width> |  | ||||||
|               <height>20</height> |  | ||||||
|              </size> |  | ||||||
|             </property> |  | ||||||
|            </spacer> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QPushButton" name="pm_add"> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>Add</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QPushButton" name="pm_rename"> |  | ||||||
|             <property name="enabled"> |  | ||||||
|              <bool>false</bool> |  | ||||||
|             </property> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>Rename</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|           <item> |  | ||||||
|            <widget class="QPushButton" name="pm_remove"> |  | ||||||
|             <property name="enabled"> |  | ||||||
|              <bool>false</bool> |  | ||||||
|             </property> |  | ||||||
|             <property name="text"> |  | ||||||
|              <string>Remove</string> |  | ||||||
|             </property> |  | ||||||
|            </widget> |  | ||||||
|           </item> |  | ||||||
|          </layout> |  | ||||||
|         </item> |  | ||||||
|        </layout> |  | ||||||
|       </widget> |  | ||||||
|      </item> |      </item> | ||||||
|      <item> |      <item> | ||||||
|       <widget class="QLabel" name="label_disable_info"> |       <widget class="QLabel" name="label_disable_info"> | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Zach Hilman
						Zach Hilman