mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-21 09:05:10 -07:00
[UserList] Context menu invite (#7138)
* [Client] Send game invites from the user context menu via a private message The user context menu gains an "Invite to Game" submenu listing the inviteable games in the room (the inviter's own games, honoring the buddy-only setting). Picking one opens a private message to the target user with a cockatrice://joingame link naming the game, so the target gets a clickable invite instead of a raw URL. Multi-game rooms offer a picker; a single inviteable game sends directly. Sending a message to an offline user no longer swallows the draft — it reports that the user is offline and keeps the typed text. Took 50 seconds Took 3 minutes * [Client] Extract sendPrivateMessage() to fix invite message draft overwrite sendInviteMessage() was calling sayEdit->setText(text) then sendMessage(), which overwrites any text the user had typed. Extract the command-building and sending logic into a new sendPrivateMessage(const QString &text) method that takes the text directly. sendMessage() now calls it after its guards and clears sayEdit; sendInviteMessage() calls it directly without touching the input field at all. Took 33 minutes * Rename method, address comments. Took 5 minutes --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
776f917ffc
commit
765ebf8fb1
9 changed files with 179 additions and 14 deletions
|
|
@ -355,6 +355,7 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
|
|||
{
|
||||
QAction *aCopyToClipBoard = nullptr, *aRemoveMessages = nullptr;
|
||||
aUserName->setText(userName);
|
||||
const bool anotherUser = userName != userListProxy->getOwnUsername();
|
||||
|
||||
auto *menu = new QMenu(static_cast<QWidget *>(parent()));
|
||||
menu->addAction(aUserName);
|
||||
|
|
@ -366,6 +367,17 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
|
|||
menu->addAction(aDetails);
|
||||
menu->addAction(aShowGames);
|
||||
menu->addAction(aChat);
|
||||
const QList<GameInviteOption> inviteOptions = inviteOptionsForUser(userName);
|
||||
if (!inviteOptions.isEmpty()) {
|
||||
auto *inviteMenu = new QMenu(tr("&Invite to Game"), menu);
|
||||
for (const GameInviteOption &option : inviteOptions) {
|
||||
QAction *inviteAction = inviteMenu->addAction(option.label);
|
||||
inviteAction->setEnabled(anotherUser && online);
|
||||
connect(inviteAction, &QAction::triggered, this,
|
||||
[this, userName, option] { execInvite(userName, option); });
|
||||
}
|
||||
menu->addMenu(inviteMenu);
|
||||
}
|
||||
if (userLevel.testFlag(ServerInfo_User::IsRegistered) && userListProxy->isOwnUserRegistered()) {
|
||||
menu->addSeparator();
|
||||
if (userListProxy->isUserBuddy(userName)) {
|
||||
|
|
@ -416,7 +428,6 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
|
|||
menu->addAction(aPromoteToJudge);
|
||||
}
|
||||
}
|
||||
bool anotherUser = userName != userListProxy->getOwnUsername();
|
||||
aDetails->setEnabled(true);
|
||||
aChat->setEnabled(anotherUser && online);
|
||||
aShowGames->setEnabled(online);
|
||||
|
|
@ -480,6 +491,60 @@ void UserContextMenu::execChat(const QString &userName)
|
|||
emit openMessageDialog(userName, true);
|
||||
}
|
||||
|
||||
QList<GameInviteOption> UserContextMenu::inviteOptionsForUser(const QString &userName) const
|
||||
{
|
||||
if (!gameInviteLinkProvider) {
|
||||
return {};
|
||||
}
|
||||
const QList<GameInviteOption> options = gameInviteLinkProvider();
|
||||
QList<GameInviteOption> result;
|
||||
for (const GameInviteOption &option : options) {
|
||||
// Buddy-only games accept invites only from their creator, and only to
|
||||
// users on the creator's buddy list.
|
||||
if (option.onlyBuddies &&
|
||||
(option.creatorName != userListProxy->getOwnUsername() || !userListProxy->isUserBuddy(userName))) {
|
||||
continue;
|
||||
}
|
||||
result.append(option);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void UserContextMenu::execInvite(const QString &userName)
|
||||
{
|
||||
const QList<GameInviteOption> options = inviteOptionsForUser(userName);
|
||||
if (options.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.size() == 1) {
|
||||
execInvite(userName, options.first());
|
||||
return;
|
||||
}
|
||||
|
||||
// More than one game in the room — let the user pick which one to invite to.
|
||||
auto *menu = new QMenu(static_cast<QWidget *>(parent()));
|
||||
for (const GameInviteOption &option : options) {
|
||||
QAction *action = menu->addAction(option.label);
|
||||
connect(action, &QAction::triggered, this, [this, userName, option] { execInvite(userName, option); });
|
||||
}
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
menu->popup(QCursor::pos());
|
||||
}
|
||||
|
||||
void UserContextMenu::execInvite(const QString &userName, const GameInviteOption &option)
|
||||
{
|
||||
// Name the game by description first, then its id — "Join my game 'Magic'
|
||||
// (#123)" — so a description-less fallback still identifies the game.
|
||||
// The multi-arg .arg() overloads replace in a single pass, so a description
|
||||
// containing "%…" cannot corrupt later placeholders.
|
||||
const QString prefix =
|
||||
option.description.isEmpty()
|
||||
? tr("Join my game (#%1):").arg(option.gameId)
|
||||
: tr("Join my game \"%1\" (#%2):").arg(option.description, QString::number(option.gameId));
|
||||
tabSupervisor->sendInviteToUser(userName, prefix + " " + option.url);
|
||||
}
|
||||
|
||||
void UserContextMenu::execDetails(const QString &userName)
|
||||
{
|
||||
auto *w = new UserInfoBox(client, false, static_cast<QWidget *>(parent()),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue