From c0d5d26a77d09d2a7e339cf67b60dd319d3f34e8 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 28 Oct 2016 16:59:57 +0900 Subject: Implemented unread messages indication on the lib side The implementation allows further extension to actually counting unread messages (in their Room::isEventNotable() sense - see the code) but so far just replicates what Quaternion previously provided. The only difference from the Quaternion implementation is that last own message is not marked as read immediately - so that we can allow the local user to send messages while staying with the read marker well above. This implies, though, that the read marker won't reset to the timeline bottom at any movement of the user - rather that it resets to the bottom of the current view (which is the ultimately correct behaviour, anyway). --- room.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------ room.h | 5 ++++- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/room.cpp b/room.cpp index c2a1ce70..fa919f61 100644 --- a/room.cpp +++ b/room.cpp @@ -49,7 +49,7 @@ class Room::Private Private(Connection* c, const QString& id_) : q(nullptr), connection(c), id(id_), joinState(JoinState::Join) - , roomMessagesJob(nullptr) + , unreadMessages(false), roomMessagesJob(nullptr) { } Room* q; @@ -68,6 +68,7 @@ class Room::Private QString displayname; QString topic; JoinState joinState; + bool unreadMessages; int highlightCount; int notificationCount; members_map_t membersMap; @@ -90,6 +91,7 @@ class Room::Private void getPreviousContent(); + bool isEventNotable(const Event* e) const; private: QString calculateDisplayname() const; QString roomNameFromMemberNames(const QList& userlist) const; @@ -169,30 +171,46 @@ void Room::setLastReadEvent(User* user, QString eventId) emit lastReadEventChanged(user); } -bool Room::promoteReadMarker(User* user, QString eventId) +bool Room::promoteReadMarker(QString newLastReadEventId) { - // Check that the new read event is not before the previously set - only - // allow the read marker to move down the timeline, not up. - QString prevLastReadId = lastReadEvent(user); + User* localUser = connection()->user(); + QString prevLastReadId = lastReadEvent(localUser); + int stillUnreadMessagesCount = 0; // Older Qt doesn't provide rbegin()/rend() for Qt containers for (auto it = messageEvents().end(); it != messageEvents().begin();) { --it; + // Check that the new read event is not before the previously set - only + // allow the read marker to move down the timeline, not up. if (prevLastReadId == (*it)->id()) - return false; - if (eventId == (*it)->id()) + break; + + // Found the message to mark as read; for the local user, + // if we don't have other notable events below this one, reset unreadMessages + if (newLastReadEventId == (*it)->id()) { - setLastReadEvent(user, eventId); - return true; + setLastReadEvent(localUser, newLastReadEventId); + break; } + + // Detect events "notable" for the local user so that we can properly + // set unreadMessages + stillUnreadMessagesCount += d->isEventNotable(*it); } - return false; + if( d->unreadMessages && stillUnreadMessagesCount == 0) + { + d->unreadMessages = false; + emit unreadMessagesChanged(this); + } + qDebug() << "Room" << displayName() + << ": still" << stillUnreadMessagesCount << "unread message(s)"; + return newLastReadEventId.isEmpty() || lastReadEvent(localUser) == newLastReadEventId; } void Room::markMessagesAsRead(Timeline::const_iterator last) { QString prevLastReadId = lastReadEvent(connection()->user()); - if ( !promoteReadMarker(connection()->user(), (*last)->id()) ) + if ( !promoteReadMarker( (*last)->id()) ) return; // We shouldn't send read receipts for messages from the local user - so @@ -216,6 +234,11 @@ void Room::markMessagesAsRead() markMessagesAsRead(messageEvents().end() - 1); } +bool Room::hasUnreadMessages() +{ + return d->unreadMessages; +} + QString Room::lastReadEvent(User* user) { return d->lastReadEvent.value(user); @@ -441,10 +464,29 @@ void Room::addNewMessageEvents(const Events& events) emit addedMessages(); } +bool Room::Private::isEventNotable(const Event* e) const +{ + return e->senderId() != connection->userId() && + e->type() == EventType::RoomMessage; +} + void Room::doAddNewMessageEvents(const Events& events) { d->messageEvents.reserve(d->messageEvents.size() + events.size()); - std::copy(events.begin(), events.end(), std::back_inserter(d->messageEvents)); + int newMessages = 0; + + for (auto e: events) + { + d->messageEvents.push_back(e); + newMessages += d->isEventNotable(e); + } + + if( !d->unreadMessages && newMessages > 0) + { + d->unreadMessages = true; + emit unreadMessagesChanged(this); + qDebug() << "Room" << displayName() << ": unread messages"; + } } void Room::addHistoricalMessageEvents(const Events& events) @@ -537,7 +579,12 @@ void Room::processEphemeralEvent(Event* event) for( const Receipt& r: receipts ) { if (auto m = d->member(r.userId)) - promoteReadMarker(m, eventId); + { + if (m == connection()->user()) + promoteReadMarker(eventId); + else + setLastReadEvent(m, eventId); + } } } } diff --git a/room.h b/room.h index fb3212e9..38435e95 100644 --- a/room.h +++ b/room.h @@ -85,6 +85,8 @@ namespace QMatrixClient */ Q_INVOKABLE void markMessagesAsRead(); + Q_INVOKABLE bool hasUnreadMessages(); + Q_INVOKABLE int notificationCount() const; Q_INVOKABLE void resetNotificationCount(); Q_INVOKABLE int highlightCount() const; @@ -116,6 +118,7 @@ namespace QMatrixClient void highlightCountChanged(Room* room); void notificationCountChanged(Room* room); void lastReadEventChanged(User* user); + void unreadMessagesChanged(Room* room); protected: Connection* connection() const; @@ -124,7 +127,7 @@ namespace QMatrixClient virtual void processStateEvents(const Events& events); virtual void processEphemeralEvent(Event* event); - bool promoteReadMarker(User* user, QString eventId); + bool promoteReadMarker(QString newLastReadEventId); private: class Private; -- cgit v1.2.3 From 17135e362a3c7b5355934837b548ceab40af9a9f Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 28 Oct 2016 22:32:50 +0900 Subject: Relax logging a bit Kicking markMessagesAsRead() at each mouse move is still a bad idea - I'm looking at you Quaternion. --- room.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/room.cpp b/room.cpp index fa919f61..6fad463b 100644 --- a/room.cpp +++ b/room.cpp @@ -200,10 +200,12 @@ bool Room::promoteReadMarker(QString newLastReadEventId) if( d->unreadMessages && stillUnreadMessagesCount == 0) { d->unreadMessages = false; + qDebug() << "Room" << displayName() << ": no more unread messages"; emit unreadMessagesChanged(this); } - qDebug() << "Room" << displayName() - << ": still" << stillUnreadMessagesCount << "unread message(s)"; + if (stillUnreadMessagesCount > 0) + qDebug() << "Room" << displayName() + << ": still" << stillUnreadMessagesCount << "unread message(s)"; return newLastReadEventId.isEmpty() || lastReadEvent(localUser) == newLastReadEventId; } -- cgit v1.2.3 From 416460b8da337bca3f12fb8bdc00371b2c56481d Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Tue, 1 Nov 2016 14:03:54 +0900 Subject: Moved MemberNameSorter from Quaternion to lib This code is useful for any client that uses the Room class and needs to display the list of room members. Also removed an unused #include. --- room.cpp | 17 ++++++++++++++++- room.h | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/room.cpp b/room.cpp index 6fad463b..85ab1720 100644 --- a/room.cpp +++ b/room.cpp @@ -28,7 +28,6 @@ #include "connection.h" #include "state.h" #include "user.h" -#include "events/event.h" #include "events/roommessageevent.h" #include "events/roomnameevent.h" #include "events/roomaliasesevent.h" @@ -677,3 +676,19 @@ void Room::Private::updateDisplayname() if (old_name != displayname) emit q->displaynameChanged(q); } + +MemberSorter Room::memberSorter() const +{ + return MemberSorter(this); +} + +bool MemberSorter::operator()(User *u1, User *u2) const +{ + auto n1 = room->roomMembername(u1); + auto n2 = room->roomMembername(u2); + if (n1[0] == '@') + n1.remove(0, 1); + if (n2[0] == '@') + n2.remove(0, 1); + return n1 < n2; +} diff --git a/room.h b/room.h index 38435e95..79c765ba 100644 --- a/room.h +++ b/room.h @@ -32,6 +32,7 @@ namespace QMatrixClient class Event; class Connection; class User; + class MemberSorter; class Room: public QObject { @@ -92,6 +93,8 @@ namespace QMatrixClient Q_INVOKABLE int highlightCount() const; Q_INVOKABLE void resetHighlightCount(); + MemberSorter memberSorter() const; + public slots: void getPreviousContent(); void userRenamed(User* user, QString oldName); @@ -138,6 +141,24 @@ namespace QMatrixClient void setLastReadEvent(User* user, QString eventId); }; + + class MemberSorter + { + public: + MemberSorter(const Room* r) : room(r) { } + + bool operator()(User* u1, User* u2) const; + + template + typename ContT::size_type lowerBoundIndex(const ContT& c, + typename ContT::value_type v) const + { + return std::lower_bound(c.begin(), c.end(), v, *this) - c.begin(); + } + + private: + const Room* room; + }; } #endif // QMATRIXCLIENT_ROOM_H -- cgit v1.2.3 From 66be8322379b9821ae624ad07d2ecf478a34384c Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Wed, 2 Nov 2016 17:09:43 +0900 Subject: Room: make read marker a Q_PROPERTY; markMessagesAsRead now uses eventId again The first change allows to use the read marker from QML (hint to Tensor). The second change is actually a fix for a case when markMessagesAsRead() is called with an iterator behind the last read event (in that case markMessagesAsRead() would post a receipt for that older event, which is not quite right). --- room.cpp | 31 ++++++++++++++++++++----------- room.h | 22 ++++++++++++---------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/room.cpp b/room.cpp index 85ab1720..366073c7 100644 --- a/room.cpp +++ b/room.cpp @@ -170,13 +170,14 @@ void Room::setLastReadEvent(User* user, QString eventId) emit lastReadEventChanged(user); } -bool Room::promoteReadMarker(QString newLastReadEventId) +Room::Timeline::const_iterator Room::promoteReadMarker(QString eventId) { User* localUser = connection()->user(); QString prevLastReadId = lastReadEvent(localUser); int stillUnreadMessagesCount = 0; + auto it = d->messageEvents.end(); // Older Qt doesn't provide rbegin()/rend() for Qt containers - for (auto it = messageEvents().end(); it != messageEvents().begin();) + while (it != d->messageEvents.begin()) { --it; // Check that the new read event is not before the previously set - only @@ -186,9 +187,10 @@ bool Room::promoteReadMarker(QString newLastReadEventId) // Found the message to mark as read; for the local user, // if we don't have other notable events below this one, reset unreadMessages - if (newLastReadEventId == (*it)->id()) + if (eventId == (*it)->id()) { - setLastReadEvent(localUser, newLastReadEventId); + setLastReadEvent(localUser, eventId); + emit readMarkerPromoted(); break; } @@ -205,15 +207,17 @@ bool Room::promoteReadMarker(QString newLastReadEventId) if (stillUnreadMessagesCount > 0) qDebug() << "Room" << displayName() << ": still" << stillUnreadMessagesCount << "unread message(s)"; - return newLastReadEventId.isEmpty() || lastReadEvent(localUser) == newLastReadEventId; + return it; } -void Room::markMessagesAsRead(Timeline::const_iterator last) +void Room::markMessagesAsRead(QString uptoEventId) { - QString prevLastReadId = lastReadEvent(connection()->user()); - if ( !promoteReadMarker( (*last)->id()) ) + if (d->messageEvents.empty()) return; + QString prevLastReadId = lastReadEvent(connection()->user()); + auto last = promoteReadMarker(uptoEventId); + // We shouldn't send read receipts for messages from the local user - so // shift back (if necessary) to the nearest message not from the local user // or the so far last read message, whichever comes first. @@ -221,7 +225,7 @@ void Room::markMessagesAsRead(Timeline::const_iterator last) { if ((*last)->senderId() != connection()->userId()) { - d->connection->postReceipt(this, (*last)); + d->connection->postReceipt(this, *last); break; } if (last == messageEvents().begin()) @@ -232,7 +236,7 @@ void Room::markMessagesAsRead(Timeline::const_iterator last) void Room::markMessagesAsRead() { if (!messageEvents().empty()) - markMessagesAsRead(messageEvents().end() - 1); + markMessagesAsRead(messageEvents().back()->id()); } bool Room::hasUnreadMessages() @@ -240,11 +244,16 @@ bool Room::hasUnreadMessages() return d->unreadMessages; } -QString Room::lastReadEvent(User* user) +QString Room::lastReadEvent(User* user) const { return d->lastReadEvent.value(user); } +QString Room::readMarkerEventId() const +{ + return lastReadEvent(d->connection->user()); +} + int Room::notificationCount() const { return d->notificationCount; diff --git a/room.h b/room.h index 79c765ba..a518ae42 100644 --- a/room.h +++ b/room.h @@ -37,6 +37,7 @@ namespace QMatrixClient class Room: public QObject { Q_OBJECT + Q_PROPERTY(QString readMarkerEventId READ readMarkerEventId WRITE markMessagesAsRead NOTIFY readMarkerPromoted) public: using Timeline = Owning; @@ -70,19 +71,19 @@ namespace QMatrixClient Q_INVOKABLE void updateData(SyncRoomData& data ); Q_INVOKABLE void setJoinState( JoinState state ); - Q_INVOKABLE QString lastReadEvent(User* user); + Q_INVOKABLE QString lastReadEvent(User* user) const; + QString readMarkerEventId() const; /** - * @brief Mark the message at the iterator as read + * @brief Mark the event with uptoEventId as read * - * Marks the message at the iterator as read; also posts a read - * receipt to the server either for this message or, if it's from - * the local user, for the nearest non-local message before. + * Finds in the timeline and marks as read the event with + * the specified id; also posts a read receipt to the server either + * for this message or, if it's from the local user, for + * the nearest non-local message before. */ - Q_INVOKABLE void markMessagesAsRead(Timeline::const_iterator last); + Q_INVOKABLE void markMessagesAsRead(QString uptoEventId); /** - * @brief Mark the most recent message in the timeline as read - * - * This effectively marks everything in the room as read. + * @brief Mark the whole room timeline as read */ Q_INVOKABLE void markMessagesAsRead(); @@ -121,6 +122,7 @@ namespace QMatrixClient void highlightCountChanged(Room* room); void notificationCountChanged(Room* room); void lastReadEventChanged(User* user); + void readMarkerPromoted(); void unreadMessagesChanged(Room* room); protected: @@ -130,7 +132,7 @@ namespace QMatrixClient virtual void processStateEvents(const Events& events); virtual void processEphemeralEvent(Event* event); - bool promoteReadMarker(QString newLastReadEventId); + Timeline::const_iterator promoteReadMarker(QString eventId); private: class Private; -- cgit v1.2.3 From b3bae976ed17b238e965a51dc35721fb68aab65f Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Thu, 3 Nov 2016 21:52:10 +0900 Subject: Auto-promote the read marker over locally-originated messages --- room.cpp | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/room.cpp b/room.cpp index 366073c7..a4980261 100644 --- a/room.cpp +++ b/room.cpp @@ -168,6 +168,8 @@ void Room::setLastReadEvent(User* user, QString eventId) { d->lastReadEvent.insert(user, eventId); emit lastReadEventChanged(user); + if (user == d->connection->user()) + emit readMarkerPromoted(); } Room::Timeline::const_iterator Room::promoteReadMarker(QString eventId) @@ -176,6 +178,7 @@ Room::Timeline::const_iterator Room::promoteReadMarker(QString eventId) QString prevLastReadId = lastReadEvent(localUser); int stillUnreadMessagesCount = 0; auto it = d->messageEvents.end(); + Event* targetEvent = nullptr; // Older Qt doesn't provide rbegin()/rend() for Qt containers while (it != d->messageEvents.begin()) { @@ -185,15 +188,28 @@ Room::Timeline::const_iterator Room::promoteReadMarker(QString eventId) if (prevLastReadId == (*it)->id()) break; - // Found the message to mark as read; for the local user, - // if we don't have other notable events below this one, reset unreadMessages + // Found the message to mark as read; if there are messages from + // the local user right below this one, automatically promote the marker + // to them instead of this one; still return this one to save + // markMessagesAsRead() from going through local messages over again. if (eventId == (*it)->id()) { - setLastReadEvent(localUser, eventId); - emit readMarkerPromoted(); + setLastReadEvent(localUser, + (targetEvent ? targetEvent : *it)->id()); break; } + // If we are on a local message (or a series thereof), remember it + // (or the end of the sequence) so that we could use it in case when + // the event to promote the marker to is immediately above the local ones. + if ((*it)->senderId() == localUser->id()) + { + if (!targetEvent) + targetEvent = *it; + } + else + targetEvent = nullptr; + // Detect events "notable" for the local user so that we can properly // set unreadMessages stillUnreadMessagesCount += d->isEventNotable(*it); @@ -483,13 +499,18 @@ bool Room::Private::isEventNotable(const Event* e) const void Room::doAddNewMessageEvents(const Events& events) { d->messageEvents.reserve(d->messageEvents.size() + events.size()); - int newMessages = 0; + int newMessages = 0; + Event* latestLocalEventBeforeUnread = nullptr; for (auto e: events) { d->messageEvents.push_back(e); newMessages += d->isEventNotable(e); + if (!newMessages && e->senderId() == connection()->userId()) + latestLocalEventBeforeUnread = e; } + if (latestLocalEventBeforeUnread) + setLastReadEvent(d->connection->user(), latestLocalEventBeforeUnread->id()); if( !d->unreadMessages && newMessages > 0) { -- cgit v1.2.3 From 0b507b3683e6f4c6429c21f7dd71197dbec07a3d Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sun, 6 Nov 2016 09:57:16 +0900 Subject: Room: extend promoteReadMarker over non-local users (again) --- room.cpp | 54 ++++++++++++++++++++++++++---------------------------- room.h | 2 +- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/room.cpp b/room.cpp index a4980261..3d2e88c9 100644 --- a/room.cpp +++ b/room.cpp @@ -172,10 +172,9 @@ void Room::setLastReadEvent(User* user, QString eventId) emit readMarkerPromoted(); } -Room::Timeline::const_iterator Room::promoteReadMarker(QString eventId) +Room::Timeline::const_iterator Room::promoteReadMarker(User* u, QString eventId) { - User* localUser = connection()->user(); - QString prevLastReadId = lastReadEvent(localUser); + QString prevLastReadId = lastReadEvent(u); int stillUnreadMessagesCount = 0; auto it = d->messageEvents.end(); Event* targetEvent = nullptr; @@ -189,20 +188,20 @@ Room::Timeline::const_iterator Room::promoteReadMarker(QString eventId) break; // Found the message to mark as read; if there are messages from - // the local user right below this one, automatically promote the marker + // that user right below this one, automatically promote the marker // to them instead of this one; still return this one to save // markMessagesAsRead() from going through local messages over again. if (eventId == (*it)->id()) { - setLastReadEvent(localUser, - (targetEvent ? targetEvent : *it)->id()); + setLastReadEvent(u, (targetEvent ? targetEvent : *it)->id()); break; } - // If we are on a local message (or a series thereof), remember it - // (or the end of the sequence) so that we could use it in case when - // the event to promote the marker to is immediately above the local ones. - if ((*it)->senderId() == localUser->id()) + // If we are on a message from that user (or a series thereof), + // remember it (or the end of the sequence) so that we could use it + // in case when the event to promote the marker to is immediately + // above the ones from that user. + if ((*it)->senderId() == u->id()) { if (!targetEvent) targetEvent = *it; @@ -212,17 +211,22 @@ Room::Timeline::const_iterator Room::promoteReadMarker(QString eventId) // Detect events "notable" for the local user so that we can properly // set unreadMessages - stillUnreadMessagesCount += d->isEventNotable(*it); + if (u == connection()->user()) + stillUnreadMessagesCount += d->isEventNotable(*it); } - if( d->unreadMessages && stillUnreadMessagesCount == 0) + + if( u == connection()->user() ) { - d->unreadMessages = false; - qDebug() << "Room" << displayName() << ": no more unread messages"; - emit unreadMessagesChanged(this); + if (d->unreadMessages && stillUnreadMessagesCount == 0) + { + d->unreadMessages = false; + qDebug() << "Room" << displayName() << ": no more unread messages"; + emit unreadMessagesChanged(this); + } + if (stillUnreadMessagesCount > 0) + qDebug() << "Room" << displayName() + << ": still" << stillUnreadMessagesCount << "unread message(s)"; } - if (stillUnreadMessagesCount > 0) - qDebug() << "Room" << displayName() - << ": still" << stillUnreadMessagesCount << "unread message(s)"; return it; } @@ -231,8 +235,9 @@ void Room::markMessagesAsRead(QString uptoEventId) if (d->messageEvents.empty()) return; - QString prevLastReadId = lastReadEvent(connection()->user()); - auto last = promoteReadMarker(uptoEventId); + User* localUser = connection()->user(); + QString prevLastReadId = lastReadEvent(localUser); + auto last = promoteReadMarker(localUser, uptoEventId); // We shouldn't send read receipts for messages from the local user - so // shift back (if necessary) to the nearest message not from the local user @@ -608,15 +613,8 @@ void Room::processEphemeralEvent(Event* event) { const auto receipts = receiptEvent->receiptsForEvent(eventId); for( const Receipt& r: receipts ) - { if (auto m = d->member(r.userId)) - { - if (m == connection()->user()) - promoteReadMarker(eventId); - else - setLastReadEvent(m, eventId); - } - } + promoteReadMarker(m, eventId); } } } diff --git a/room.h b/room.h index a518ae42..57acf3aa 100644 --- a/room.h +++ b/room.h @@ -132,7 +132,7 @@ namespace QMatrixClient virtual void processStateEvents(const Events& events); virtual void processEphemeralEvent(Event* event); - Timeline::const_iterator promoteReadMarker(QString eventId); + Timeline::const_iterator promoteReadMarker(User* u, QString eventId); private: class Private; -- cgit v1.2.3 From cb108696e62ffd54410297423b3aea0549ddcc84 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Mon, 7 Nov 2016 13:08:13 +0900 Subject: Room::doAddNewMessages: Extend auto-promotion to all users, not only local Thanks to @maralorn for pointing out. --- room.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/room.cpp b/room.cpp index 3d2e88c9..6c33cc58 100644 --- a/room.cpp +++ b/room.cpp @@ -505,19 +505,35 @@ void Room::doAddNewMessageEvents(const Events& events) { d->messageEvents.reserve(d->messageEvents.size() + events.size()); - int newMessages = 0; - Event* latestLocalEventBeforeUnread = nullptr; + Timeline::size_type newUnreadMessages = 0; + + // The first message in the batch defines whose read marker we can + // automatically promote any further. Others will need explicit read receipts + // from the server (or, for the local user, markMessagesAsRead() invocation) + // to promote their read markers over the new message events. + User* firstWriter = d->member(events.front()->senderId()); + bool canAutoPromote = d->messageEvents.empty() || + lastReadEvent(firstWriter) == d->messageEvents.back()->id(); + Event* firstWriterSeriesEnd = canAutoPromote ? events.front() : nullptr; + for (auto e: events) { d->messageEvents.push_back(e); - newMessages += d->isEventNotable(e); - if (!newMessages && e->senderId() == connection()->userId()) - latestLocalEventBeforeUnread = e; + + newUnreadMessages += d->isEventNotable(e); + if (firstWriterSeriesEnd) + { + if (e->senderId() != firstWriter->id()) + firstWriterSeriesEnd = e; + else + { + setLastReadEvent(firstWriter, firstWriterSeriesEnd->id()); + firstWriterSeriesEnd = nullptr; + } + } } - if (latestLocalEventBeforeUnread) - setLastReadEvent(d->connection->user(), latestLocalEventBeforeUnread->id()); - if( !d->unreadMessages && newMessages > 0) + if( !d->unreadMessages && newUnreadMessages > 0) { d->unreadMessages = true; emit unreadMessagesChanged(this); -- cgit v1.2.3 From 8b69437b14021b23c208b27857d139bd2c2bb186 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Mon, 7 Nov 2016 19:53:50 +0900 Subject: Fixed a crasher that slipped in the previous commit Room::Private::member() filters out non-members of the room, which is not the right thing when adding messages from a person that left the room, e.g. --- room.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/room.cpp b/room.cpp index 6c33cc58..2d32c430 100644 --- a/room.cpp +++ b/room.cpp @@ -511,7 +511,7 @@ void Room::doAddNewMessageEvents(const Events& events) // automatically promote any further. Others will need explicit read receipts // from the server (or, for the local user, markMessagesAsRead() invocation) // to promote their read markers over the new message events. - User* firstWriter = d->member(events.front()->senderId()); + User* firstWriter = connection()->user(events.front()->senderId()); bool canAutoPromote = d->messageEvents.empty() || lastReadEvent(firstWriter) == d->messageEvents.back()->id(); Event* firstWriterSeriesEnd = canAutoPromote ? events.front() : nullptr; -- cgit v1.2.3