aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--room.cpp54
-rw-r--r--room.h20
2 files changed, 70 insertions, 4 deletions
diff --git a/room.cpp b/room.cpp
index e07426a7..c2a1ce70 100644
--- a/room.cpp
+++ b/room.cpp
@@ -163,9 +163,57 @@ void Room::setJoinState(JoinState state)
emit joinStateChanged(oldState, state);
}
-void Room::markMessageAsRead(Event* event)
+void Room::setLastReadEvent(User* user, QString eventId)
{
- d->connection->postReceipt(this, event);
+ d->lastReadEvent.insert(user, eventId);
+ emit lastReadEventChanged(user);
+}
+
+bool Room::promoteReadMarker(User* user, QString eventId)
+{
+ // 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);
+ // Older Qt doesn't provide rbegin()/rend() for Qt containers
+ for (auto it = messageEvents().end(); it != messageEvents().begin();)
+ {
+ --it;
+ if (prevLastReadId == (*it)->id())
+ return false;
+ if (eventId == (*it)->id())
+ {
+ setLastReadEvent(user, eventId);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Room::markMessagesAsRead(Timeline::const_iterator last)
+{
+ QString prevLastReadId = lastReadEvent(connection()->user());
+ if ( !promoteReadMarker(connection()->user(), (*last)->id()) )
+ return;
+
+ // 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.
+ for (; (*last)->id() != prevLastReadId; --last)
+ {
+ if ((*last)->senderId() != connection()->userId())
+ {
+ d->connection->postReceipt(this, (*last));
+ break;
+ }
+ if (last == messageEvents().begin())
+ break;
+ }
+}
+
+void Room::markMessagesAsRead()
+{
+ if (!messageEvents().empty())
+ markMessagesAsRead(messageEvents().end() - 1);
}
QString Room::lastReadEvent(User* user)
@@ -489,7 +537,7 @@ void Room::processEphemeralEvent(Event* event)
for( const Receipt& r: receipts )
{
if (auto m = d->member(r.userId))
- d->lastReadEvent.insert(m, eventId);
+ promoteReadMarker(m, eventId);
}
}
}
diff --git a/room.h b/room.h
index 7266ae70..fb3212e9 100644
--- a/room.h
+++ b/room.h
@@ -69,8 +69,21 @@ namespace QMatrixClient
Q_INVOKABLE void updateData(SyncRoomData& data );
Q_INVOKABLE void setJoinState( JoinState state );
- Q_INVOKABLE void markMessageAsRead( Event* event );
Q_INVOKABLE QString lastReadEvent(User* user);
+ /**
+ * @brief Mark the message at the iterator 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.
+ */
+ Q_INVOKABLE void markMessagesAsRead(Timeline::const_iterator last);
+ /**
+ * @brief Mark the most recent message in the timeline as read
+ *
+ * This effectively marks everything in the room as read.
+ */
+ Q_INVOKABLE void markMessagesAsRead();
Q_INVOKABLE int notificationCount() const;
Q_INVOKABLE void resetNotificationCount();
@@ -102,6 +115,7 @@ namespace QMatrixClient
void typingChanged();
void highlightCountChanged(Room* room);
void notificationCountChanged(Room* room);
+ void lastReadEventChanged(User* user);
protected:
Connection* connection() const;
@@ -110,12 +124,16 @@ namespace QMatrixClient
virtual void processStateEvents(const Events& events);
virtual void processEphemeralEvent(Event* event);
+ bool promoteReadMarker(User* user, QString eventId);
+
private:
class Private;
Private* d;
void addNewMessageEvents(const Events& events);
void addHistoricalMessageEvents(const Events& events);
+
+ void setLastReadEvent(User* user, QString eventId);
};
}