diff --git a/autotests/chatbarcachetest.cpp b/autotests/chatbarcachetest.cpp index 198ccc555..fee7270e9 100644 --- a/autotests/chatbarcachetest.cpp +++ b/autotests/chatbarcachetest.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -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(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() diff --git a/autotests/data/test-min-sync-extra-sync.json b/autotests/data/test-min-sync-extra-sync.json new file mode 100644 index 000000000..52453b21b --- /dev/null +++ b/autotests/data/test-min-sync-extra-sync.json @@ -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" + } + } + ] + } +} diff --git a/src/chatbar/ChatBar.qml b/src/chatbar/ChatBar.qml index 8503ac324..93e541895 100644 --- a/src/chatbar/ChatBar.qml +++ b/src/chatbar/ChatBar.qml @@ -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 diff --git a/src/libneochat/chatbarcache.cpp b/src/libneochat/chatbarcache.cpp index 234e64d28..12799b4c8 100644 --- a/src/libneochat/chatbarcache.cpp +++ b/src/libneochat/chatbarcache.cpp @@ -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(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) { diff --git a/src/libneochat/chatbarcache.h b/src/libneochat/chatbarcache.h index be89e36f1..2d19811a6 100644 --- a/src/libneochat/chatbarcache.h +++ b/src/libneochat/chatbarcache.h @@ -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();