Refactor TabAccount and create UserListManager

This commit is contained in:
ZeldaZach 2025-01-14 00:14:41 -05:00
parent 6309e7e318
commit 1d3f5586c5
No known key found for this signature in database
10 changed files with 285 additions and 186 deletions

View file

@ -176,6 +176,7 @@ set(cockatrice_SOURCES
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp
src/client/ui/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
src/client/user_list_manager.cpp
${VERSION_STRING_CPP}
)

View file

@ -6,6 +6,7 @@
#include "../../server/user/user_list.h"
#include "../game_logic/abstract_client.h"
#include "../sound_engine.h"
#include "../user_list_manager.h"
#include "pb/event_add_to_list.pb.h"
#include "pb/event_remove_from_list.pb.h"
#include "pb/event_user_joined.pb.h"
@ -18,36 +19,29 @@
#include <QPushButton>
#include <QVBoxLayout>
TabUserLists::TabUserLists(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User &userInfo)
: Tab(_tabSupervisor), client(_client)
TabUserLists::TabUserLists(TabSupervisor *_tabSupervisor,
AbstractClient *_client,
const ServerInfo_User &userInfo,
UserListManager *_userListManager)
: Tab(_tabSupervisor), client(_client), userListManager(_userListManager)
{
allUsersList = new UserList(_tabSupervisor, client, UserList::AllUsersList);
buddyList = new UserList(_tabSupervisor, client, UserList::BuddyList);
ignoreList = new UserList(_tabSupervisor, client, UserList::IgnoreList);
userInfoBox = new UserInfoBox(client, true);
userInfoBox->updateInfo(userInfo);
connect(allUsersList, &UserList::openMessageDialog, this, &TabUserLists::openMessageDialog);
connect(buddyList, &UserList::openMessageDialog, this, &TabUserLists::openMessageDialog);
connect(ignoreList, &UserList::openMessageDialog, this, &TabUserLists::openMessageDialog);
connect(client, &AbstractClient::userJoinedEventReceived, this, &TabUserLists::processUserJoinedEvent);
connect(client, &AbstractClient::userLeftEventReceived, this, &TabUserLists::processUserLeftEvent);
connect(client, &AbstractClient::buddyListReceived, this, &TabUserLists::buddyListReceived);
connect(client, &AbstractClient::ignoreListReceived, this, &TabUserLists::ignoreListReceived);
connect(client, &AbstractClient::addToListEventReceived, this, &TabUserLists::processAddToListEvent);
connect(client, &AbstractClient::removeFromListEventReceived, this, &TabUserLists::processRemoveFromListEvent);
connect(userListManager->getAllUsersList(), &UserList::openMessageDialog, this, &TabUserLists::openMessageDialog);
connect(userListManager->getBuddyList(), &UserList::openMessageDialog, this, &TabUserLists::openMessageDialog);
connect(userListManager->getIgnoreList(), &UserList::openMessageDialog, this, &TabUserLists::openMessageDialog);
PendingCommand *pend = client->prepareSessionCommand(Command_ListUsers());
connect(pend,
static_cast<void (PendingCommand::*)(const Response &, const CommandContainer &, const QVariant &)>(
&PendingCommand::finished),
this, &TabUserLists::processListUsersResponse);
userListManager, &UserListManager::processListUsersResponse);
client->sendCommand(pend);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(userInfoBox);
vbox->addWidget(allUsersList);
vbox->addWidget(userListManager->getAllUsersList());
QHBoxLayout *addToBuddyList = new QHBoxLayout;
addBuddyEdit = new LineEditUnfocusable;
@ -70,13 +64,12 @@ TabUserLists::TabUserLists(TabSupervisor *_tabSupervisor, AbstractClient *_clien
addToIgnoreList->addWidget(addIgnoreButton);
QVBoxLayout *buddyPanel = new QVBoxLayout;
buddyPanel->addWidget(buddyList);
buddyPanel->addWidget(userListManager->getBuddyList());
buddyPanel->addLayout(addToBuddyList);
QVBoxLayout *ignorePanel = new QVBoxLayout;
ignorePanel->addWidget(ignoreList);
ignorePanel->addWidget(userListManager->getIgnoreList());
ignorePanel->addLayout(addToIgnoreList);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(buddyPanel);
mainLayout->addLayout(ignorePanel);
@ -96,7 +89,7 @@ void TabUserLists::addToBuddyList()
return;
std::string listName = "buddy";
addToList(listName, userName);
userListManager->addToList(listName, userName);
addBuddyEdit->clear();
}
@ -107,122 +100,12 @@ void TabUserLists::addToIgnoreList()
return;
std::string listName = "ignore";
addToList(listName, userName);
userListManager->addToList(listName, userName);
addIgnoreEdit->clear();
}
void TabUserLists::addToList(const std::string &listName, const QString &userName)
{
Command_AddToList cmd;
cmd.set_list(listName);
cmd.set_user_name(userName.toStdString());
client->sendCommand(client->prepareSessionCommand(cmd));
}
void TabUserLists::retranslateUi()
{
allUsersList->retranslateUi();
buddyList->retranslateUi();
ignoreList->retranslateUi();
userInfoBox->retranslateUi();
}
void TabUserLists::processListUsersResponse(const Response &response)
{
const Response_ListUsers &resp = response.GetExtension(Response_ListUsers::ext);
const int userListSize = resp.user_list_size();
for (int i = 0; i < userListSize; ++i) {
const ServerInfo_User &info = resp.user_list(i);
const QString userName = QString::fromStdString(info.name());
allUsersList->processUserInfo(info, true);
ignoreList->setUserOnline(userName, true);
buddyList->setUserOnline(userName, true);
}
allUsersList->sortItems();
ignoreList->sortItems();
buddyList->sortItems();
}
void TabUserLists::processUserJoinedEvent(const Event_UserJoined &event)
{
const ServerInfo_User &info = event.user_info();
const QString userName = QString::fromStdString(info.name());
allUsersList->processUserInfo(info, true);
ignoreList->setUserOnline(userName, true);
buddyList->setUserOnline(userName, true);
allUsersList->sortItems();
ignoreList->sortItems();
buddyList->sortItems();
if (buddyList->getUsers().keys().contains(userName))
soundEngine->playSound("buddy_join");
emit userJoined(info);
}
void TabUserLists::processUserLeftEvent(const Event_UserLeft &event)
{
QString userName = QString::fromStdString(event.name());
if (buddyList->getUsers().keys().contains(userName))
soundEngine->playSound("buddy_leave");
if (allUsersList->deleteUser(userName)) {
ignoreList->setUserOnline(userName, false);
buddyList->setUserOnline(userName, false);
ignoreList->sortItems();
buddyList->sortItems();
emit userLeft(userName);
}
}
void TabUserLists::buddyListReceived(const QList<ServerInfo_User> &_buddyList)
{
for (int i = 0; i < _buddyList.size(); ++i)
buddyList->processUserInfo(_buddyList[i], false);
buddyList->sortItems();
}
void TabUserLists::ignoreListReceived(const QList<ServerInfo_User> &_ignoreList)
{
for (int i = 0; i < _ignoreList.size(); ++i)
ignoreList->processUserInfo(_ignoreList[i], false);
ignoreList->sortItems();
}
void TabUserLists::processAddToListEvent(const Event_AddToList &event)
{
const ServerInfo_User &info = event.user_info();
bool online = allUsersList->getUsers().contains(QString::fromStdString(info.name()));
QString list = QString::fromStdString(event.list_name());
UserList *userList = 0;
if (list == "buddy")
userList = buddyList;
else if (list == "ignore")
userList = ignoreList;
if (!userList)
return;
userList->processUserInfo(info, online);
userList->sortItems();
}
void TabUserLists::processRemoveFromListEvent(const Event_RemoveFromList &event)
{
QString list = QString::fromStdString(event.list_name());
QString user = QString::fromStdString(event.user_name());
UserList *userList = 0;
if (list == "buddy")
userList = buddyList;
else if (list == "ignore")
userList = ignoreList;
if (!userList)
return;
userList->deleteUser(user);
userListManager->retranslateUi();
}

View file

@ -8,7 +8,7 @@ class AbstractClient;
class UserList;
class UserInfoBox;
class LineEditUnfocusable;
class UserListManager;
class Event_ListRooms;
class Event_UserJoined;
class Event_UserLeft;
@ -22,48 +22,27 @@ class TabUserLists : public Tab
Q_OBJECT
signals:
void openMessageDialog(const QString &userName, bool focus);
void userLeft(const QString &userName);
void userJoined(const ServerInfo_User &userInfo);
private slots:
void processListUsersResponse(const Response &response);
void processUserJoinedEvent(const Event_UserJoined &event);
void processUserLeftEvent(const Event_UserLeft &event);
void buddyListReceived(const QList<ServerInfo_User> &_buddyList);
void ignoreListReceived(const QList<ServerInfo_User> &_ignoreList);
void processAddToListEvent(const Event_AddToList &event);
void processRemoveFromListEvent(const Event_RemoveFromList &event);
void addToIgnoreList();
void addToBuddyList();
private:
AbstractClient *client;
UserList *allUsersList;
UserList *buddyList;
UserList *ignoreList;
UserListManager *userListManager;
UserInfoBox *userInfoBox;
LineEditUnfocusable *addBuddyEdit;
LineEditUnfocusable *addIgnoreEdit;
void addToList(const std::string &listName, const QString &userName);
public:
TabUserLists(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User &userInfo);
TabUserLists(TabSupervisor *_tabSupervisor,
AbstractClient *_client,
const ServerInfo_User &userInfo,
UserListManager *_userListManager);
void retranslateUi() override;
QString getTabText() const override
{
return tr("Account");
}
const UserList *getAllUsersList() const
{
return allUsersList;
}
const UserList *getBuddyList() const
{
return buddyList;
}
const UserList *getIgnoreList() const
{
return ignoreList;
}
};
#endif

View file

@ -282,7 +282,7 @@ void TabRoom::processRoomSayEvent(const Event_RoomSay &event)
QString senderName = QString::fromStdString(event.name());
QString message = QString::fromStdString(event.message());
if (tabSupervisor->getUserListsTab()->getIgnoreList()->getUsers().contains(senderName))
if (tabSupervisor->getUserListManger()->getIgnoreList()->getUsers().contains(senderName))
return;
UserListTWI *twi = userList->getUsers().value(senderName);

View file

@ -10,7 +10,6 @@
#include "pb/event_user_message.pb.h"
#include "pb/game_event_container.pb.h"
#include "pb/game_replay.pb.h"
#include "pb/moderator_commands.pb.h"
#include "pb/room_commands.pb.h"
#include "pb/room_event.pb.h"
#include "pb/serverinfo_room.pb.h"
@ -28,7 +27,6 @@
#include "visual_deck_storage/tab_deck_storage_visual.h"
#include <QApplication>
#include <QDebug>
#include <QMessageBox>
#include <QPainter>
#include <QSystemTrayIcon>
@ -49,7 +47,7 @@ CloseButton::CloseButton(QWidget *parent) : QAbstractButton(parent)
{
setFocusPolicy(Qt::NoFocus);
setCursor(Qt::ArrowCursor);
resize(sizeHint());
resize(CloseButton::sizeHint());
}
QSize CloseButton::sizeHint() const
@ -102,7 +100,8 @@ void CloseButton::paintEvent(QPaintEvent * /*event*/)
TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *parent)
: QTabWidget(parent), userInfo(0), client(_client), tabsMenu(tabsMenu), tabVisualDeckStorage(nullptr), tabServer(0),
tabUserLists(0), tabDeckStorage(0), tabReplays(0), tabAdmin(0), tabLog(0)
tabUserLists(0), tabDeckStorage(0), tabReplays(0), tabAdmin(0), tabLog(0),
userListManager(new UserListManager(this, client))
{
setElideMode(Qt::ElideRight);
setMovable(true);
@ -432,10 +431,10 @@ void TabSupervisor::actTabServer(bool checked)
void TabSupervisor::actTabUserLists(bool checked)
{
if (checked && !tabUserLists) {
tabUserLists = new TabUserLists(this, client, *userInfo);
tabUserLists = new TabUserLists(this, client, *userInfo, userListManager);
connect(tabUserLists, &TabUserLists::openMessageDialog, this, &TabSupervisor::addMessageTab);
connect(tabUserLists, &TabUserLists::userJoined, this, &TabSupervisor::processUserJoined);
connect(tabUserLists, &TabUserLists::userLeft, this, &TabSupervisor::processUserLeft);
connect(userListManager, &UserListManager::userJoined, this, &TabSupervisor::processUserJoined);
connect(userListManager, &UserListManager::userLeft, this, &TabSupervisor::processUserLeft);
myAddTab(tabUserLists);
connect(tabUserLists, &Tab::closed, this, [this] {
tabUserLists = nullptr;
@ -616,7 +615,7 @@ TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus
return nullptr;
ServerInfo_User otherUser;
UserListTWI *twi = tabUserLists->getAllUsersList()->getUsers().value(receiverName);
UserListTWI *twi = userListManager->getAllUsersList()->getUsers().value(receiverName);
if (twi)
otherUser = twi->getUserInfo();
else
@ -717,7 +716,7 @@ void TabSupervisor::processUserMessageEvent(const Event_UserMessage &event)
if (!tab)
tab = messageTabs.value(QString::fromStdString(event.receiver_name()));
if (!tab) {
UserListTWI *twi = tabUserLists->getAllUsersList()->getUsers().value(senderName);
UserListTWI *twi = userListManager->getAllUsersList()->getUsers().value(senderName);
if (twi) {
UserLevelFlags userLevel = UserLevelFlags(twi->getUserInfo().user_level());
if (SettingsCache::instance().getIgnoreUnregisteredUserMessages() &&
@ -861,33 +860,42 @@ QString TabSupervisor::getOwnUsername() const
bool TabSupervisor::isUserBuddy(const QString &userName) const
{
if (!getUserListsTab())
if (!getUserListsTab()) {
return false;
if (!getUserListsTab()->getBuddyList())
}
if (!userListManager->getBuddyList()) {
return false;
QMap<QString, UserListTWI *> buddyList = getUserListsTab()->getBuddyList()->getUsers();
}
QMap<QString, UserListTWI *> buddyList = userListManager->getBuddyList()->getUsers();
bool senderIsBuddy = buddyList.contains(userName);
return senderIsBuddy;
}
bool TabSupervisor::isUserIgnored(const QString &userName) const
{
if (!getUserListsTab())
if (!getUserListsTab()) {
return false;
if (!getUserListsTab()->getIgnoreList())
}
if (!userListManager->getIgnoreList()) {
return false;
QMap<QString, UserListTWI *> buddyList = getUserListsTab()->getIgnoreList()->getUsers();
}
QMap<QString, UserListTWI *> buddyList = userListManager->getIgnoreList()->getUsers();
bool senderIsBuddy = buddyList.contains(userName);
return senderIsBuddy;
}
const ServerInfo_User *TabSupervisor::getOnlineUser(const QString &userName) const
{
if (!getUserListsTab())
if (!getUserListsTab()) {
return nullptr;
if (!getUserListsTab()->getAllUsersList())
}
if (!userListManager->getAllUsersList()) {
return nullptr;
QMap<QString, UserListTWI *> userList = getUserListsTab()->getAllUsersList()->getUsers();
}
QMap<QString, UserListTWI *> userList = userListManager->getAllUsersList()->getUsers();
const QString &userNameToMatchLower = userName.toLower();
QMap<QString, UserListTWI *>::iterator i;
@ -898,7 +906,7 @@ const ServerInfo_User *TabSupervisor::getOnlineUser(const QString &userName) con
}
return nullptr;
};
}
bool TabSupervisor::switchToGameTabIfAlreadyExists(const int gameId)
{

View file

@ -3,6 +3,7 @@
#include "../../deck/deck_loader.h"
#include "../../server/chat_view/user_list_proxy.h"
#include "../user_list_manager.h"
#include "visual_deck_storage/tab_deck_storage_visual.h"
#include <QAbstractButton>
@ -77,6 +78,7 @@ private:
TabReplays *tabReplays;
TabAdmin *tabAdmin;
TabLog *tabLog;
UserListManager *userListManager;
QMap<int, TabRoom *> roomTabs;
QMap<int, TabGame *> gameTabs;
QList<TabGame *> replayTabs;
@ -117,6 +119,9 @@ public:
return userInfo;
}
AbstractClient *getClient() const;
const UserListManager *getUserListManger() const {
return userListManager;
}
const QMap<int, TabRoom *> &getRoomTabs() const
{
return roomTabs;

View file

@ -0,0 +1,160 @@
#include "user_list_manager.h"
#include "../server/pending_command.h"
#include "../server/user/user_info_box.h"
#include "../server/user/user_list.h"
#include "game_logic/abstract_client.h"
#include "pb/event_add_to_list.pb.h"
#include "pb/event_remove_from_list.pb.h"
#include "pb/event_user_joined.pb.h"
#include "pb/event_user_left.pb.h"
#include "pb/response_list_users.pb.h"
#include "pb/session_commands.pb.h"
#include "sound_engine.h"
#include "trice_limits.h"
UserListManager::UserListManager(TabSupervisor *_tabSupervisor, AbstractClient *_client)
: client(_client), tabSupervisor(_tabSupervisor)
{
allUsersList = new UserList(_tabSupervisor, _client, UserList::AllUsersList);
buddyList = new UserList(_tabSupervisor, _client, UserList::BuddyList);
ignoreList = new UserList(_tabSupervisor, _client, UserList::IgnoreList);
connect(client, &AbstractClient::userJoinedEventReceived, this, &UserListManager::processUserJoinedEvent);
connect(client, &AbstractClient::userLeftEventReceived, this, &UserListManager::processUserLeftEvent);
connect(client, &AbstractClient::buddyListReceived, this, &UserListManager::buddyListReceived);
connect(client, &AbstractClient::ignoreListReceived, this, &UserListManager::ignoreListReceived);
connect(client, &AbstractClient::addToListEventReceived, this, &UserListManager::processAddToListEvent);
connect(client, &AbstractClient::removeFromListEventReceived, this, &UserListManager::processRemoveFromListEvent);
}
void UserListManager::handleConnect()
{
}
void UserListManager::handleDisconnect()
{
}
void UserListManager::processListUsersResponse(const Response &response)
{
const Response_ListUsers &resp = response.GetExtension(Response_ListUsers::ext);
const int userListSize = resp.user_list_size();
for (int i = 0; i < userListSize; ++i) {
const ServerInfo_User &info = resp.user_list(i);
const QString userName = QString::fromStdString(info.name());
allUsersList->processUserInfo(info, true);
ignoreList->setUserOnline(userName, true);
buddyList->setUserOnline(userName, true);
}
allUsersList->sortItems();
ignoreList->sortItems();
buddyList->sortItems();
}
void UserListManager::processUserJoinedEvent(const Event_UserJoined &event)
{
const ServerInfo_User &info = event.user_info();
const QString userName = QString::fromStdString(info.name());
allUsersList->processUserInfo(info, true);
ignoreList->setUserOnline(userName, true);
buddyList->setUserOnline(userName, true);
allUsersList->sortItems();
ignoreList->sortItems();
buddyList->sortItems();
if (buddyList->getUsers().keys().contains(userName)) {
soundEngine->playSound("buddy_join");
}
emit userJoined(info);
}
void UserListManager::processUserLeftEvent(const Event_UserLeft &event)
{
QString userName = QString::fromStdString(event.name());
if (buddyList->getUsers().keys().contains(userName)) {
soundEngine->playSound("buddy_leave");
}
if (allUsersList->deleteUser(userName)) {
ignoreList->setUserOnline(userName, false);
buddyList->setUserOnline(userName, false);
ignoreList->sortItems();
buddyList->sortItems();
emit userLeft(userName);
}
}
void UserListManager::buddyListReceived(const QList<ServerInfo_User> &_buddyList)
{
for (int i = 0; i < _buddyList.size(); ++i) {
buddyList->processUserInfo(_buddyList[i], false);
}
buddyList->sortItems();
}
void UserListManager::ignoreListReceived(const QList<ServerInfo_User> &_ignoreList)
{
for (int i = 0; i < _ignoreList.size(); ++i) {
ignoreList->processUserInfo(_ignoreList[i], false);
}
ignoreList->sortItems();
}
void UserListManager::processAddToListEvent(const Event_AddToList &event)
{
const ServerInfo_User &info = event.user_info();
bool online = allUsersList->getUsers().contains(QString::fromStdString(info.name()));
QString list = QString::fromStdString(event.list_name());
UserList *userList = nullptr;
if (list == "buddy") {
userList = buddyList;
} else if (list == "ignore") {
userList = ignoreList;
}
if (!userList) {
return;
}
userList->processUserInfo(info, online);
userList->sortItems();
}
void UserListManager::processRemoveFromListEvent(const Event_RemoveFromList &event)
{
QString list = QString::fromStdString(event.list_name());
QString user = QString::fromStdString(event.user_name());
UserList *userList = nullptr;
if (list == "buddy") {
userList = buddyList;
} else if (list == "ignore") {
userList = ignoreList;
}
if (!userList) {
return;
}
userList->deleteUser(user);
}
void UserListManager::addToList(const std::string &listName, const QString &userName)
{
Command_AddToList cmd;
cmd.set_list(listName);
cmd.set_user_name(userName.toStdString());
client->sendCommand(client->prepareSessionCommand(cmd));
}

View file

@ -0,0 +1,66 @@
#ifndef COCKATRICE_USER_LISTS_H
#define COCKATRICE_USER_LISTS_H
#include "pb/serverinfo_user.pb.h"
#include <QWidget>
class AbstractClient;
class Event_AddToList;
class Event_ListRooms;
class Event_RemoveFromList;
class Event_UserJoined;
class Event_UserLeft;
class LineEditUnfocusable;
class Response;
class ServerInfo_User;
class TabSupervisor;
class UserInfoBox;
class UserList;
class UserListManager : public QWidget
{
Q_OBJECT
private:
AbstractClient *client;
TabSupervisor *tabSupervisor;
UserList *allUsersList, *buddyList, *ignoreList;
private slots:
void processUserJoinedEvent(const Event_UserJoined &event);
void processUserLeftEvent(const Event_UserLeft &event);
void buddyListReceived(const QList<ServerInfo_User> &_buddyList);
void ignoreListReceived(const QList<ServerInfo_User> &_ignoreList);
void processAddToListEvent(const Event_AddToList &event);
void processRemoveFromListEvent(const Event_RemoveFromList &event);
public:
explicit UserListManager(TabSupervisor *_tabSupervisor, AbstractClient *_client);
[[nodiscard]] UserList *getAllUsersList() const
{
return allUsersList;
}
[[nodiscard]] UserList *getBuddyList() const
{
return buddyList;
}
[[nodiscard]] UserList *getIgnoreList() const
{
return ignoreList;
}
void retranslateUi() {};
public slots:
void handleConnect();
void handleDisconnect();
void processListUsersResponse(const Response &response);
void addToList(const std::string &listName, const QString &userName);
signals:
void userLeft(const QString &userName);
void userJoined(const ServerInfo_User &userInfo);
};
#endif // COCKATRICE_USER_LISTS_H

View file

@ -508,7 +508,7 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
if (!showBuddiesOnlyGames && game.only_buddies()) {
return false;
}
if (hideIgnoredUserGames && tabSupervisor->getUserListsTab()->getIgnoreList()->getUsers().contains(
if (hideIgnoredUserGames && tabSupervisor->getUserListManger()->getIgnoreList()->getUsers().contains(
QString::fromStdString(game.creator_info().name()))) {
return false;
}

View file

@ -138,13 +138,10 @@ private slots:
void userClicked(QTreeWidgetItem *item, int column);
signals:
void openMessageDialog(const QString &userName, bool focus);
void addBuddy(const QString &userName);
void removeBuddy(const QString &userName);
void addIgnore(const QString &userName);
void removeIgnore(const QString &userName);
public:
UserList(TabSupervisor *_tabSupervisor, AbstractClient *_client, UserListType _type, QWidget *parent = nullptr);
explicit UserList(TabSupervisor *_tabSupervisor, AbstractClient *_client, UserListType _type, QWidget *parent = nullptr);
void retranslateUi();
void processUserInfo(const ServerInfo_User &user, bool online);
bool deleteUser(const QString &userName);