Remind the user if they're trying to reply to someone who has left

This happens semi-frequently to me and others - we reply to a user who
has left the room. Sometimes this is useful (for example, bringing up a
previous topic) but in most cases this is accidental, and almost
guaranteed to happen if you turned off join/leave events.

So I added a reminder when replying - which manifests as a small label
in the chatbar - that the user has left and can't be notified of your
reply.
This commit is contained in:
Joshua Goins
2025-08-04 16:38:38 -04:00
parent 6822a1ef08
commit 93b6c53c82
5 changed files with 91 additions and 0 deletions

View File

@@ -6,6 +6,7 @@
#include <QObject>
#include <QTest>
#include <QSignalSpy>
#include <Quotient/roommember.h>
#include <Quotient/syncdata.h>
#include <qtestcase.h>
@@ -32,6 +33,7 @@ private Q_SLOTS:
void noRoom();
void badParent();
void reply();
void replyMissingUser();
void edit();
void attachment();
};
@@ -102,6 +104,33 @@ void ChatBarCacheTest::reply()
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
QCOMPARE(chatBarCache->attachmentPath(), QString());
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
}
void ChatBarCacheTest::replyMissingUser()
{
QScopedPointer<ChatBarCache> chatBarCache(new ChatBarCache(room));
chatBarCache->setText(u"some text"_s);
chatBarCache->setAttachmentPath(u"some/path"_s);
chatBarCache->setReplyId(u"$153456789:example.org"_s);
QCOMPARE(chatBarCache->text(), u"some text"_s);
QCOMPARE(chatBarCache->isReplying(), true);
QCOMPARE(chatBarCache->replyId(), u"$153456789:example.org"_s);
QCOMPARE(chatBarCache->isEditing(), false);
QCOMPARE(chatBarCache->editId(), QString());
QCOMPARE(chatBarCache->relationAuthor(), room->member(u"@example:example.org"_s));
QCOMPARE(chatBarCache->relationMessage(), u"This is an example\ntext message"_s);
QCOMPARE(chatBarCache->attachmentPath(), QString());
QCOMPARE(chatBarCache->relationAuthorIsPresent(), true);
QSignalSpy relationAuthorIsPresentSpy(chatBarCache.get(), &ChatBarCache::relationAuthorIsPresentChanged);
// sync again, which will simulate the reply user leaving the room
room->syncNewEvents(u"test-min-sync-extra-sync.json"_s);
QTRY_COMPARE(relationAuthorIsPresentSpy.count(), 1);
QCOMPARE(chatBarCache->relationAuthorIsPresent(), false);
}
void ChatBarCacheTest::edit()

View File

@@ -0,0 +1,20 @@
{
"state": {
"events": [
{
"content": {
"membership": "leave"
},
"event_id": "$1432735824666PhrSA:example.org",
"origin_server_ts": 1432735824666,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "@example:example.org",
"type": "m.room.member",
"unsigned": {
"replaces_state": "$143273582443PhrSn:example.org"
}
}
]
}
}

View File

@@ -197,6 +197,22 @@ QQC2.Control {
visible: root.currentRoom.mainCache.replyId.length > 0
sourceComponent: replyPane
}
RowLayout {
visible: replyLoader.visible && !root.currentRoom.mainCache.relationAuthorIsPresent
spacing: Kirigami.Units.smallSpacing
Kirigami.Icon {
source: "help-hint-symbolic"
color: Kirigami.Theme.disabledTextColor
Layout.preferredWidth: Kirigami.Units.iconSizes.small
Layout.preferredHeight: Kirigami.Units.iconSizes.small
}
QQC2.Label {
text: i18nc("@info", "The user you're replying to has left the room, and can't be notified.")
color: Kirigami.Theme.disabledTextColor
}
}
Loader {
id: attachLoader

View File

@@ -15,6 +15,18 @@ using namespace Qt::StringLiterals;
ChatBarCache::ChatBarCache(QObject *parent)
: QObject(parent)
{
if (parent == nullptr) {
qWarning() << "ChatBarCache created with no parent, a NeoChatRoom must be set as the parent on creation.";
return;
}
auto room = dynamic_cast<NeoChatRoom *>(parent);
if (room == nullptr) {
qWarning() << "ChatBarCache created with incorrect parent, a NeoChatRoom must be set as the parent on creation.";
return;
}
connect(room, &NeoChatRoom::memberLeft, this, &ChatBarCache::relationAuthorIsPresentChanged);
connect(room, &NeoChatRoom::memberJoined, this, &ChatBarCache::relationAuthorIsPresentChanged);
connect(this, &ChatBarCache::relationIdChanged, this, &ChatBarCache::relationAuthorIsPresentChanged);
}
QString ChatBarCache::text() const
@@ -137,6 +149,11 @@ Quotient::RoomMember ChatBarCache::relationAuthor() const
return room->member((*room->findInTimeline(m_relationId))->senderId());
}
bool ChatBarCache::relationAuthorIsPresent() const
{
return relationAuthor().membershipState() == Quotient::Membership::Join;
}
QString ChatBarCache::relationMessage() const
{
if (parent() == nullptr) {

View File

@@ -99,6 +99,13 @@ class ChatBarCache : public QObject
*/
Q_PROPERTY(Quotient::RoomMember relationAuthor READ relationAuthor NOTIFY relationIdChanged)
/**
* @brief If the author for the message being replied to is still present in the room.
*
* @sa Quotient::RoomMember
*/
Q_PROPERTY(bool relationAuthorIsPresent READ relationAuthorIsPresent NOTIFY relationAuthorIsPresentChanged)
/**
* @brief The content of the related message.
*
@@ -153,6 +160,7 @@ public:
void setEditId(const QString &editId);
Quotient::RoomMember relationAuthor() const;
bool relationAuthorIsPresent() const;
QString relationMessage() const;
@@ -196,6 +204,7 @@ Q_SIGNALS:
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
void attachmentPathChanged();
void mentionAdded(const QString &mention);
void relationAuthorIsPresentChanged();
private:
QString m_text = QString();