[Client] Keep the message draft and notify when the recipient is offline (#7142)

* [Client] Keep the message draft and notify when the recipient is offline

* Don't blindly assume a user is online.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-08-17 00:16:55 +02:00 • committed by GitHub
parent 6c8fcf7d19
commit f466a25893
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 35 additions and 7 deletions

View file

@ -23,9 +23,10 @@
TabMessage::TabMessage(TabSupervisor *_tabSupervisor, TabMessage::TabMessage(TabSupervisor *_tabSupervisor,
AbstractClient *_client, AbstractClient *_client,
const ServerInfo_User &_ownUserInfo, const ServerInfo_User &_ownUserInfo,
const ServerInfo_User &_otherUserInfo) const ServerInfo_User &_otherUserInfo,
bool _userOnline)
: Tab(_tabSupervisor), client(_client), ownUserInfo(new ServerInfo_User(_ownUserInfo)), : Tab(_tabSupervisor), client(_client), ownUserInfo(new ServerInfo_User(_ownUserInfo)),
otherUserInfo(new ServerInfo_User(_otherUserInfo)), userOnline(true) otherUserInfo(new ServerInfo_User(_otherUserInfo)), userOnline(_userOnline)
{ {
chatView = new ChatView(tabSupervisor, 0, true); chatView = new ChatView(tabSupervisor, 0, true);
connect(chatView, &ChatView::showCardInfoPopup, this, &TabMessage::showCardInfoPopup); connect(chatView, &ChatView::showCardInfoPopup, this, &TabMessage::showCardInfoPopup);
@ -96,7 +97,14 @@ void TabMessage::closeEvent(QCloseEvent *event)
void TabMessage::sendMessage() void TabMessage::sendMessage()
{ {
if (sayEdit->text().isEmpty() || !userOnline) { if (sayEdit->text().isEmpty()) {
return;
}
if (!userOnline) {
// Keep the draft: the user may be back momentarily, and the typed text
// should not be lost to a transient offline spell.
notifyUserOffline();
return; return;
} }
@ -105,17 +113,27 @@ void TabMessage::sendMessage()
cmd.set_message(sayEdit->text().toStdString()); cmd.set_message(sayEdit->text().toStdString());
PendingCommand *pend = client->prepareSessionCommand(cmd); PendingCommand *pend = client->prepareSessionCommand(cmd);
pend->setExtraData(sayEdit->text());
connect(pend, &PendingCommand::finished, this, &TabMessage::messageSent); connect(pend, &PendingCommand::finished, this, &TabMessage::messageSent);
client->sendCommand(pend); client->sendCommand(pend);
sayEdit->clear(); sayEdit->clear();
} }
void TabMessage::messageSent(const Response &response) void TabMessage::messageSent(const Response &response,
const CommandContainer & /*commandContainer*/,
const QVariant &extraData)
{ {
if (response.response_code() == Response::RespInIgnoreList) { if (response.response_code() == Response::RespInIgnoreList) {
chatView->appendMessage(tr( chatView->appendMessage(tr(
"This user is ignoring you, they cannot see your messages in main chat and you cannot join their games.")); "This user is ignoring you, they cannot see your messages in main chat and you cannot join their games."));
} else if (response.response_code() == Response::RespNameNotFound) {
// The recipient went offline before the command reached the server: restore the draft.
userOnline = false;
if (sayEdit->text().isEmpty()) {
sayEdit->setText(extraData.toString());
}
notifyUserOffline();
} }
} }
@ -175,3 +193,8 @@ void TabMessage::processUserJoined(const ServerInfo_User &_userInfo)
userOnline = true; userOnline = true;
*otherUserInfo = _userInfo; *otherUserInfo = _userInfo;
} }
void TabMessage::notifyUserOffline()
{
chatView->appendMessage(tr("Message not sent — %1 is offline.").arg(QString::fromStdString(otherUserInfo->name())));
}

View file

@ -19,6 +19,7 @@ class LineEditUnfocusable;
class Event_UserMessage; class Event_UserMessage;
class Response; class Response;
class ServerInfo_User; class ServerInfo_User;
class CommandContainer;
class TabMessage : public Tab class TabMessage : public Tab
{ {
@ -39,7 +40,7 @@ signals:
void maximizeClient(); void maximizeClient();
private slots: private slots:
void sendMessage(); void sendMessage();
void messageSent(const Response &response); void messageSent(const Response &response, const CommandContainer &commandContainer, const QVariant &extraData);
void addMentionTag(QString mentionTag); void addMentionTag(QString mentionTag);
void messageClicked(); void messageClicked();
@ -50,7 +51,8 @@ public:
TabMessage(TabSupervisor *_tabSupervisor, TabMessage(TabSupervisor *_tabSupervisor,
AbstractClient *_client, AbstractClient *_client,
const ServerInfo_User &_ownUserInfo, const ServerInfo_User &_ownUserInfo,
const ServerInfo_User &_otherUserInfo); const ServerInfo_User &_otherUserInfo,
bool _userOnline);
~TabMessage() override; ~TabMessage() override;
void retranslateUi() override; void retranslateUi() override;
void tabActivated() override; void tabActivated() override;
@ -65,6 +67,7 @@ public:
private: private:
bool shouldShowSystemPopup(const Event_UserMessage &event); bool shouldShowSystemPopup(const Event_UserMessage &event);
void showSystemPopup(const Event_UserMessage &event); void showSystemPopup(const Event_UserMessage &event);
void notifyUserOffline();
}; };
#endif #endif

View file

@ -904,8 +904,10 @@ TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus
} }
ServerInfo_User otherUser; ServerInfo_User otherUser;
bool userOnline = false;
if (auto user = userListManager->getOnlineUser(receiverName)) { if (auto user = userListManager->getOnlineUser(receiverName)) {
otherUser = ServerInfo_User(*user); otherUser = ServerInfo_User(*user);
userOnline = true;
} else { } else {
otherUser.set_name(receiverName.toStdString()); otherUser.set_name(receiverName.toStdString());
} }
@ -919,7 +921,7 @@ TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus
return tab; return tab;
} }
tab = new TabMessage(this, client, *userInfo, otherUser); tab = new TabMessage(this, client, *userInfo, otherUser, userOnline);
connect(tab, &TabMessage::talkClosing, this, &TabSupervisor::talkLeft); connect(tab, &TabMessage::talkClosing, this, &TabSupervisor::talkLeft);
connect(tab, &TabMessage::maximizeClient, this, &TabSupervisor::maximizeMainWindow); connect(tab, &TabMessage::maximizeClient, this, &TabSupervisor::maximizeMainWindow);
myAddTab(tab); myAddTab(tab);