mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	citra_qt: Use the new verify backend; UI changes
Displayed username along with nickname (when they are not identical); Requested and displayed user's avatar; Made the dialog bigger for extended names. Added a few functions to web_backend (GetImage, GetPlain) to support getting data in multiple content-types. Added a no_avatar icon for users without avatars.
This commit is contained in:
		
							parent
							
								
									4906c8ce7b
								
							
						
					
					
						commit
						386bf5c861
					
				
					 18 changed files with 263 additions and 80 deletions
				
			
		|  | @ -228,6 +228,10 @@ if (USE_DISCORD_PRESENCE) | |||
|     target_compile_definitions(citra-qt PRIVATE -DUSE_DISCORD_PRESENCE) | ||||
| endif() | ||||
| 
 | ||||
| if (ENABLE_WEB_SERVICE) | ||||
|     target_compile_definitions(citra-qt PRIVATE -DENABLE_WEB_SERVICE) | ||||
| endif() | ||||
| 
 | ||||
| if(UNIX AND NOT APPLE) | ||||
|     install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") | ||||
| endif() | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #include <array> | ||||
| #include <future> | ||||
| #include <QColor> | ||||
| #include <QFutureWatcher> | ||||
| #include <QImage> | ||||
| #include <QList> | ||||
| #include <QLocale> | ||||
|  | @ -12,6 +13,7 @@ | |||
| #include <QMessageBox> | ||||
| #include <QMetaType> | ||||
| #include <QTime> | ||||
| #include <QUrl> | ||||
| #include <QtConcurrent/QtConcurrentRun> | ||||
| #include "citra_qt/game_list_p.h" | ||||
| #include "citra_qt/multiplayer/chat_room.h" | ||||
|  | @ -19,6 +21,9 @@ | |||
| #include "common/logging/log.h" | ||||
| #include "core/announce_multiplayer_session.h" | ||||
| #include "ui_chat_room.h" | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
| #include "web_service/web_backend.h" | ||||
| #endif | ||||
| 
 | ||||
| class ChatMessage { | ||||
| public: | ||||
|  | @ -27,14 +32,21 @@ public: | |||
|         QLocale locale; | ||||
|         timestamp = locale.toString(ts.isValid() ? ts : QTime::currentTime(), QLocale::ShortFormat); | ||||
|         nickname = QString::fromStdString(chat.nickname); | ||||
|         username = QString::fromStdString(chat.username); | ||||
|         message = QString::fromStdString(chat.message); | ||||
|     } | ||||
| 
 | ||||
|     /// Format the message using the players color
 | ||||
|     QString GetPlayerChatMessage(u16 player) const { | ||||
|         auto color = player_color[player % 16]; | ||||
|         QString name; | ||||
|         if (username.isEmpty() || username == nickname) { | ||||
|             name = nickname; | ||||
|         } else { | ||||
|             name = QString("%1 (%2)").arg(nickname, username); | ||||
|         } | ||||
|         return QString("[%1] <font color='%2'><%3></font> %4") | ||||
|             .arg(timestamp, color, nickname.toHtmlEscaped(), message.toHtmlEscaped()); | ||||
|             .arg(timestamp, color, name.toHtmlEscaped(), message.toHtmlEscaped()); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|  | @ -44,6 +56,7 @@ private: | |||
| 
 | ||||
|     QString timestamp; | ||||
|     QString nickname; | ||||
|     QString username; | ||||
|     QString message; | ||||
| }; | ||||
| 
 | ||||
|  | @ -67,22 +80,54 @@ private: | |||
|     QString message; | ||||
| }; | ||||
| 
 | ||||
| class PlayerListItem : public QStandardItem { | ||||
| public: | ||||
|     static const int NicknameRole = Qt::UserRole + 1; | ||||
|     static const int UsernameRole = Qt::UserRole + 2; | ||||
|     static const int AvatarUrlRole = Qt::UserRole + 3; | ||||
|     static const int GameNameRole = Qt::UserRole + 4; | ||||
| 
 | ||||
|     PlayerListItem() = default; | ||||
|     explicit PlayerListItem(const std::string& nickname, const std::string& username, | ||||
|                             const std::string& avatar_url, const std::string& game_name) { | ||||
|         setEditable(false); | ||||
|         setData(QString::fromStdString(nickname), NicknameRole); | ||||
|         setData(QString::fromStdString(username), UsernameRole); | ||||
|         setData(QString::fromStdString(avatar_url), AvatarUrlRole); | ||||
|         if (game_name.empty()) { | ||||
|             setData(QObject::tr("Not playing a game"), GameNameRole); | ||||
|         } else { | ||||
|             setData(QString::fromStdString(game_name), GameNameRole); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     QVariant data(int role) const override { | ||||
|         if (role != Qt::DisplayRole) { | ||||
|             return QStandardItem::data(role); | ||||
|         } | ||||
|         QString name; | ||||
|         const QString nickname = data(NicknameRole).toString(); | ||||
|         const QString username = data(UsernameRole).toString(); | ||||
|         if (username.isEmpty() || username == nickname) { | ||||
|             name = nickname; | ||||
|         } else { | ||||
|             name = QString("%1 (%2)").arg(nickname, username); | ||||
|         } | ||||
|         return QString("%1\n      %2").arg(name, data(GameNameRole).toString()); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| ChatRoom::ChatRoom(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::ChatRoom>()) { | ||||
|     ui->setupUi(this); | ||||
| 
 | ||||
|     // set the item_model for player_view
 | ||||
|     enum { | ||||
|         COLUMN_NAME, | ||||
|         COLUMN_GAME, | ||||
|         COLUMN_COUNT, // Number of columns
 | ||||
|     }; | ||||
| 
 | ||||
|     player_list = new QStandardItemModel(ui->player_view); | ||||
|     ui->player_view->setModel(player_list); | ||||
|     ui->player_view->setContextMenuPolicy(Qt::CustomContextMenu); | ||||
|     player_list->insertColumns(0, COLUMN_COUNT); | ||||
|     player_list->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name")); | ||||
|     player_list->setHeaderData(COLUMN_GAME, Qt::Horizontal, tr("Game")); | ||||
|     // set a header to make it look better though there is only one column
 | ||||
|     player_list->insertColumns(0, 1); | ||||
|     player_list->setHeaderData(0, Qt::Horizontal, tr("Members")); | ||||
| 
 | ||||
|     ui->chat_history->document()->setMaximumBlockCount(max_chat_lines); | ||||
| 
 | ||||
|  | @ -157,7 +202,8 @@ void ChatRoom::OnChatReceive(const Network::ChatEntry& chat) { | |||
|         auto members = room->GetMemberInformation(); | ||||
|         auto it = std::find_if(members.begin(), members.end(), | ||||
|                                [&chat](const Network::RoomMember::MemberInformation& member) { | ||||
|                                    return member.nickname == chat.nickname; | ||||
|                                    return member.nickname == chat.nickname && | ||||
|                                           member.username == chat.username; | ||||
|                                }); | ||||
|         if (it == members.end()) { | ||||
|             LOG_INFO(Network, "Chat message received from unknown player. Ignoring it."); | ||||
|  | @ -184,12 +230,14 @@ void ChatRoom::OnSendChat() { | |||
|             return; | ||||
|         } | ||||
|         auto nick = room->GetNickname(); | ||||
|         Network::ChatEntry chat{nick, message}; | ||||
|         auto username = room->GetUsername(); | ||||
|         Network::ChatEntry chat{nick, username, message}; | ||||
| 
 | ||||
|         auto members = room->GetMemberInformation(); | ||||
|         auto it = std::find_if(members.begin(), members.end(), | ||||
|                                [&chat](const Network::RoomMember::MemberInformation& member) { | ||||
|                                    return member.nickname == chat.nickname; | ||||
|                                    return member.nickname == chat.nickname && | ||||
|                                           member.username == chat.username; | ||||
|                                }); | ||||
|         if (it == members.end()) { | ||||
|             LOG_INFO(Network, "Cannot find self in the player list when sending a message."); | ||||
|  | @ -202,20 +250,64 @@ void ChatRoom::OnSendChat() { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void ChatRoom::UpdateIconDisplay() { | ||||
|     for (int row = 0; row < player_list->invisibleRootItem()->rowCount(); ++row) { | ||||
|         QStandardItem* item = player_list->invisibleRootItem()->child(row); | ||||
|         const std::string avatar_url = | ||||
|             item->data(PlayerListItem::AvatarUrlRole).toString().toStdString(); | ||||
|         if (icon_cache.count(avatar_url)) { | ||||
|             item->setData(icon_cache.at(avatar_url), Qt::DecorationRole); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ChatRoom::SetPlayerList(const Network::RoomMember::MemberList& member_list) { | ||||
|     // TODO(B3N30): Remember which row is selected
 | ||||
|     player_list->removeRows(0, player_list->rowCount()); | ||||
|     for (const auto& member : member_list) { | ||||
|         if (member.nickname.empty()) | ||||
|             continue; | ||||
|         QList<QStandardItem*> l; | ||||
|         std::vector<std::string> elements = {member.nickname, member.game_info.name}; | ||||
|         for (const auto& item : elements) { | ||||
|             QStandardItem* child = new QStandardItem(QString::fromStdString(item)); | ||||
|             child->setEditable(false); | ||||
|             l.append(child); | ||||
|         QStandardItem* name_item = new PlayerListItem(member.nickname, member.username, | ||||
|                                                       member.avatar_url, member.game_info.name); | ||||
| 
 | ||||
|         if (!icon_cache.count(member.avatar_url)) { | ||||
|             // Emplace a default question mark icon as avatar
 | ||||
|             icon_cache.emplace(member.avatar_url, QIcon::fromTheme("no_avatar").pixmap(48)); | ||||
|             if (!member.avatar_url.empty()) { | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
|                 // Start a request to get the member's avatar
 | ||||
|                 const QUrl url(QString::fromStdString(member.avatar_url)); | ||||
|                 QFuture<std::string> future = QtConcurrent::run([url] { | ||||
|                     WebService::Client client( | ||||
|                         QString("%1://%2").arg(url.scheme(), url.host()).toStdString(), "", ""); | ||||
|                     auto result = client.GetImage(url.path().toStdString(), true); | ||||
|                     if (result.returned_data.empty()) { | ||||
|                         LOG_ERROR(WebService, "Failed to get avatar"); | ||||
|                     } | ||||
|                     return result.returned_data; | ||||
|                 }); | ||||
|                 auto* future_watcher = new QFutureWatcher<std::string>(this); | ||||
|                 connect(future_watcher, &QFutureWatcher<std::string>::finished, this, | ||||
|                         [this, future_watcher, avatar_url = member.avatar_url] { | ||||
|                             const std::string result = future_watcher->result(); | ||||
|                             if (result.empty()) | ||||
|                                 return; | ||||
|                             QPixmap pixmap; | ||||
|                             if (!pixmap.loadFromData(reinterpret_cast<const u8*>(result.data()), | ||||
|                                                      result.size())) | ||||
|                                 return; | ||||
|                             icon_cache[avatar_url] = pixmap.scaled(48, 48, Qt::IgnoreAspectRatio, | ||||
|                                                                    Qt::SmoothTransformation); | ||||
|                             // Update all the displayed icons with the new icon_cache
 | ||||
|                             UpdateIconDisplay(); | ||||
|                         }); | ||||
|                 future_watcher->setFuture(future); | ||||
| #endif | ||||
|             } | ||||
|         } | ||||
|         player_list->invisibleRootItem()->appendRow(l); | ||||
|         name_item->setData(icon_cache.at(member.avatar_url), Qt::DecorationRole); | ||||
| 
 | ||||
|         player_list->invisibleRootItem()->appendRow(name_item); | ||||
|     } | ||||
|     // TODO(B3N30): Restore row selection
 | ||||
| } | ||||
|  | @ -230,7 +322,8 @@ void ChatRoom::PopupContextMenu(const QPoint& menu_location) { | |||
|     if (!item.isValid()) | ||||
|         return; | ||||
| 
 | ||||
|     std::string nickname = player_list->item(item.row())->text().toStdString(); | ||||
|     std::string nickname = | ||||
|         player_list->item(item.row())->data(PlayerListItem::NicknameRole).toString().toStdString(); | ||||
|     if (auto room = Network::GetRoomMember().lock()) { | ||||
|         // You can't block yourself
 | ||||
|         if (nickname == room->GetNickname()) | ||||
|  |  | |||
|  | @ -52,9 +52,12 @@ private: | |||
|     static constexpr u32 max_chat_lines = 1000; | ||||
|     void AppendChatMessage(const QString&); | ||||
|     bool ValidateMessage(const std::string&); | ||||
|     void UpdateIconDisplay(); | ||||
| 
 | ||||
|     QStandardItemModel* player_list; | ||||
|     std::unique_ptr<Ui::ChatRoom> ui; | ||||
|     std::unordered_set<std::string> block_list; | ||||
|     std::unordered_map<std::string, QPixmap> icon_cache; | ||||
| }; | ||||
| 
 | ||||
| Q_DECLARE_METATYPE(Network::ChatEntry); | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ | |||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>607</width> | ||||
|     <width>807</width> | ||||
|     <height>432</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ | |||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>607</width> | ||||
|     <width>807</width> | ||||
|     <height>432</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|  |  | |||
|  | @ -22,6 +22,9 @@ | |||
| #include "core/hle/service/cfg/cfg.h" | ||||
| #include "core/settings.h" | ||||
| #include "ui_host_room.h" | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
| #include "web_service/verify_user_jwt.h" | ||||
| #endif | ||||
| 
 | ||||
| HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list, | ||||
|                                std::shared_ptr<Core::AnnounceMultiplayerSession> session) | ||||
|  | @ -79,6 +82,21 @@ void HostRoomWindow::RetranslateUi() { | |||
|     ui->retranslateUi(this); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Network::VerifyUser::Backend> HostRoomWindow::CreateVerifyBackend( | ||||
|     bool use_validation) const { | ||||
|     std::unique_ptr<Network::VerifyUser::Backend> verify_backend; | ||||
|     if (use_validation) { | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
|         verify_backend = std::make_unique<WebService::VerifyUserJWT>(Settings::values.web_api_url); | ||||
| #else | ||||
|         verify_backend = std::make_unique<Network::VerifyUser::NullBackend>(); | ||||
| #endif | ||||
|     } else { | ||||
|         verify_backend = std::make_unique<Network::VerifyUser::NullBackend>(); | ||||
|     } | ||||
|     return verify_backend; | ||||
| } | ||||
| 
 | ||||
| void HostRoomWindow::Host() { | ||||
|     if (!ui->username->hasAcceptableInput()) { | ||||
|         NetworkMessage::ShowError(NetworkMessage::USERNAME_NOT_VALID); | ||||
|  | @ -108,11 +126,12 @@ void HostRoomWindow::Host() { | |||
|         auto game_id = ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong(); | ||||
|         auto port = ui->port->isModified() ? ui->port->text().toInt() : Network::DefaultRoomPort; | ||||
|         auto password = ui->password->text().toStdString(); | ||||
|         const bool is_public = ui->host_type->currentIndex() == 0; | ||||
|         if (auto room = Network::GetRoom().lock()) { | ||||
|             bool created = | ||||
|                 room->Create(ui->room_name->text().toStdString(), | ||||
|                              ui->room_description->toPlainText().toStdString(), "", port, password, | ||||
|                              ui->max_player->value(), game_name.toStdString(), game_id); | ||||
|             bool created = room->Create(ui->room_name->text().toStdString(), | ||||
|                                         ui->room_description->toPlainText().toStdString(), "", port, | ||||
|                                         password, ui->max_player->value(), game_name.toStdString(), | ||||
|                                         game_id, CreateVerifyBackend(is_public)); | ||||
|             if (!created) { | ||||
|                 NetworkMessage::ShowError(NetworkMessage::COULD_NOT_CREATE_ROOM); | ||||
|                 LOG_ERROR(Network, "Could not create room!"); | ||||
|  | @ -120,9 +139,34 @@ void HostRoomWindow::Host() { | |||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         // Start the announce session if they chose Public
 | ||||
|         if (is_public) { | ||||
|             if (auto session = announce_multiplayer_session.lock()) { | ||||
|                 // Register the room first to ensure verify_UID is present when we connect
 | ||||
|                 session->Register(); | ||||
|                 session->Start(); | ||||
|             } else { | ||||
|                 LOG_ERROR(Network, "Starting announce session failed"); | ||||
|             } | ||||
|         } | ||||
|         std::string token; | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
|         if (is_public) { | ||||
|             WebService::Client client(Settings::values.web_api_url, Settings::values.citra_username, | ||||
|                                       Settings::values.citra_token); | ||||
|             if (auto room = Network::GetRoom().lock()) { | ||||
|                 token = client.GetExternalJWT(room->GetVerifyUID()).returned_data; | ||||
|             } | ||||
|             if (token.empty()) { | ||||
|                 LOG_ERROR(WebService, "Could not get external JWT, verification may fail"); | ||||
|             } else { | ||||
|                 LOG_INFO(WebService, "Successfully requested external JWT: size={}", token.size()); | ||||
|             } | ||||
|         } | ||||
| #endif | ||||
|         member->Join(ui->username->text().toStdString(), | ||||
|                      Service::CFG::GetConsoleIdHash(Core::System::GetInstance()), "127.0.0.1", port, | ||||
|                      0, Network::NoPreferredMac, password); | ||||
|                      0, Network::NoPreferredMac, password, token); | ||||
| 
 | ||||
|         // Store settings
 | ||||
|         UISettings::values.room_nickname = ui->username->text(); | ||||
|  | @ -137,24 +181,8 @@ void HostRoomWindow::Host() { | |||
|                                            : QString::number(Network::DefaultRoomPort); | ||||
|         UISettings::values.room_description = ui->room_description->toPlainText(); | ||||
|         Settings::Apply(); | ||||
|         OnConnection(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void HostRoomWindow::OnConnection() { | ||||
|     ui->host->setEnabled(true); | ||||
|     if (auto room_member = Network::GetRoomMember().lock()) { | ||||
|         if (room_member->GetState() == Network::RoomMember::State::Joining) { | ||||
|             // Start the announce session if they chose Public
 | ||||
|             if (ui->host_type->currentIndex() == 0) { | ||||
|                 if (auto session = announce_multiplayer_session.lock()) { | ||||
|                     session->Start(); | ||||
|                 } else { | ||||
|                     LOG_ERROR(Network, "Starting announce session failed"); | ||||
|                 } | ||||
|             } | ||||
|             close(); | ||||
|         } | ||||
|         ui->host->setEnabled(true); | ||||
|         close(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,6 +26,10 @@ class ComboBoxProxyModel; | |||
| 
 | ||||
| class ChatMessage; | ||||
| 
 | ||||
| namespace Network::VerifyUser { | ||||
| class Backend; | ||||
| }; | ||||
| 
 | ||||
| class HostRoomWindow : public QDialog { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
|  | @ -36,15 +40,9 @@ public: | |||
| 
 | ||||
|     void RetranslateUi(); | ||||
| 
 | ||||
| private slots: | ||||
|     /**
 | ||||
|      * Handler for connection status changes. Launches the chat window if successful or | ||||
|      * displays an error | ||||
|      */ | ||||
|     void OnConnection(); | ||||
| 
 | ||||
| private: | ||||
|     void Host(); | ||||
|     std::unique_ptr<Network::VerifyUser::Backend> CreateVerifyBackend(bool use_validation) const; | ||||
| 
 | ||||
|     std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session; | ||||
|     QStandardItemModel* game_list; | ||||
|  |  | |||
|  | @ -18,6 +18,9 @@ | |||
| #include "core/hle/service/cfg/cfg.h" | ||||
| #include "core/settings.h" | ||||
| #include "network/network.h" | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
| #include "web_service/web_backend.h" | ||||
| #endif | ||||
| 
 | ||||
| Lobby::Lobby(QWidget* parent, QStandardItemModel* list, | ||||
|              std::shared_ptr<Core::AnnounceMultiplayerSession> session) | ||||
|  | @ -136,12 +139,27 @@ void Lobby::OnJoinRoom(const QModelIndex& source) { | |||
|     const std::string ip = | ||||
|         proxy->data(connection_index, LobbyItemHost::HostIPRole).toString().toStdString(); | ||||
|     int port = proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt(); | ||||
|     const std::string verify_UID = | ||||
|         proxy->data(connection_index, LobbyItemHost::HostVerifyUIDRole).toString().toStdString(); | ||||
| 
 | ||||
|     // attempt to connect in a different thread
 | ||||
|     QFuture<void> f = QtConcurrent::run([nickname, ip, port, password] { | ||||
|     QFuture<void> f = QtConcurrent::run([nickname, ip, port, password, verify_UID] { | ||||
|         std::string token; | ||||
| #ifdef ENABLE_WEB_SERVICE | ||||
|         if (!Settings::values.citra_username.empty() && !Settings::values.citra_token.empty()) { | ||||
|             WebService::Client client(Settings::values.web_api_url, Settings::values.citra_username, | ||||
|                                       Settings::values.citra_token); | ||||
|             token = client.GetExternalJWT(verify_UID).returned_data; | ||||
|             if (token.empty()) { | ||||
|                 LOG_ERROR(WebService, "Could not get external JWT, verification may fail"); | ||||
|             } else { | ||||
|                 LOG_INFO(WebService, "Successfully requested external JWT: size={}", token.size()); | ||||
|             } | ||||
|         } | ||||
| #endif | ||||
|         if (auto room_member = Network::GetRoomMember().lock()) { | ||||
|             room_member->Join(nickname, Service::CFG::GetConsoleIdHash(Core::System::GetInstance()), | ||||
|                               ip.c_str(), port, 0, Network::NoPreferredMac, password); | ||||
|                               ip.c_str(), port, 0, Network::NoPreferredMac, password, token); | ||||
|         } | ||||
|     }); | ||||
|     watcher->setFuture(f); | ||||
|  | @ -193,7 +211,8 @@ void Lobby::OnRefreshLobby() { | |||
|         QList<QVariant> members; | ||||
|         for (auto member : room.members) { | ||||
|             QVariant var; | ||||
|             var.setValue(LobbyMember{QString::fromStdString(member.name), member.game_id, | ||||
|             var.setValue(LobbyMember{QString::fromStdString(member.username), | ||||
|                                      QString::fromStdString(member.nickname), member.game_id, | ||||
|                                      QString::fromStdString(member.game_name)}); | ||||
|             members.append(var); | ||||
|         } | ||||
|  | @ -205,7 +224,7 @@ void Lobby::OnRefreshLobby() { | |||
|             new LobbyItemGame(room.preferred_game_id, QString::fromStdString(room.preferred_game), | ||||
|                               smdh_icon), | ||||
|             new LobbyItemHost(QString::fromStdString(room.owner), QString::fromStdString(room.ip), | ||||
|                               room.port), | ||||
|                               room.port, QString::fromStdString(room.verify_UID)), | ||||
|             new LobbyItemMemberList(members, room.max_player), | ||||
|         }); | ||||
|         model->appendRow(row); | ||||
|  |  | |||
|  | @ -120,12 +120,14 @@ public: | |||
|     static const int HostUsernameRole = Qt::UserRole + 1; | ||||
|     static const int HostIPRole = Qt::UserRole + 2; | ||||
|     static const int HostPortRole = Qt::UserRole + 3; | ||||
|     static const int HostVerifyUIDRole = Qt::UserRole + 4; | ||||
| 
 | ||||
|     LobbyItemHost() = default; | ||||
|     explicit LobbyItemHost(QString username, QString ip, u16 port) { | ||||
|     explicit LobbyItemHost(QString username, QString ip, u16 port, QString verify_UID) { | ||||
|         setData(username, HostUsernameRole); | ||||
|         setData(ip, HostIPRole); | ||||
|         setData(port, HostPortRole); | ||||
|         setData(verify_UID, HostVerifyUIDRole); | ||||
|     } | ||||
| 
 | ||||
|     QVariant data(int role) const override { | ||||
|  | @ -146,12 +148,17 @@ class LobbyMember { | |||
| public: | ||||
|     LobbyMember() = default; | ||||
|     LobbyMember(const LobbyMember& other) = default; | ||||
|     explicit LobbyMember(QString username, u64 title_id, QString game_name) | ||||
|         : username(std::move(username)), title_id(title_id), game_name(std::move(game_name)) {} | ||||
|     explicit LobbyMember(QString username, QString nickname, u64 title_id, QString game_name) | ||||
|         : username(std::move(username)), nickname(std::move(nickname)), title_id(title_id), | ||||
|           game_name(std::move(game_name)) {} | ||||
|     ~LobbyMember() = default; | ||||
| 
 | ||||
|     QString GetUsername() const { | ||||
|         return username; | ||||
|     QString GetName() const { | ||||
|         if (username.isEmpty() || username == nickname) { | ||||
|             return nickname; | ||||
|         } else { | ||||
|             return QString("%1 (%2)").arg(nickname, username); | ||||
|         } | ||||
|     } | ||||
|     u64 GetTitleId() const { | ||||
|         return title_id; | ||||
|  | @ -162,6 +169,7 @@ public: | |||
| 
 | ||||
| private: | ||||
|     QString username; | ||||
|     QString nickname; | ||||
|     u64 title_id; | ||||
|     QString game_name; | ||||
| }; | ||||
|  | @ -220,10 +228,9 @@ public: | |||
|                 out += '\n'; | ||||
|             const auto& m = member.value<LobbyMember>(); | ||||
|             if (m.GetGameName().isEmpty()) { | ||||
|                 out += QString(QObject::tr("%1 is not playing a game")).arg(m.GetUsername()); | ||||
|                 out += QString(QObject::tr("%1 is not playing a game")).arg(m.GetName()); | ||||
|             } else { | ||||
|                 out += | ||||
|                     QString(QObject::tr("%1 is playing %2")).arg(m.GetUsername(), m.GetGameName()); | ||||
|                 out += QString(QObject::tr("%1 is playing %2")).arg(m.GetName(), m.GetGameName()); | ||||
|             } | ||||
|             first = false; | ||||
|         } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue