git » sdk » commit 182ae09

Guard against marking read in the past

author Stephen Paul Weber
2025-03-04 16:11:12 UTC
committer Stephen Paul Weber
2025-03-04 16:11:12 UTC
parent 9b45031e597fe11120ca120f05ff4d3b2e4b68ec

Guard against marking read in the past

So a UI can just mark read whatever you are reading and if it is in the
past of something you already read we won't mess stuff up.

snikket/Chat.hx +32 -27

diff --git a/snikket/Chat.hx b/snikket/Chat.hx
index 44742a6..c9c0827 100644
--- a/snikket/Chat.hx
+++ b/snikket/Chat.hx
@@ -586,6 +586,7 @@ abstract class Chat {
 	@:allow(snikket)
 	private function markReadUpToId(upTo: String, upToBy: String, ?callback: ()->Void) {
 		if (upTo == null) return;
+		if (readUpTo() == upTo) return;
 
 		readUpToId = upTo;
 		readUpToBy = upToBy;
@@ -593,13 +594,24 @@ abstract class Chat {
 		persistence.getMessagesBefore(client.accountId(), chatId, null, null, (messages) -> {
 			var i = messages.length;
 			while (--i >= 0) {
-				if (messages[i].serverId == readUpToId) break;
+				if (messages[i].serverId == readUpToId || !messages[i].isIncoming()) break;
 			}
 			setUnreadCount(messages.length - (i + 1));
 			if (callback != null) callback();
 		});
 	}
 
+	private function markReadUpToMessage(message: ChatMessage, ?callback: ()->Void) {
+		if (message.serverId == null || message.chatId() != chatId) return;
+		if (readUpTo() == message.serverId) return;
+
+		persistence.getMessage(client.accountId(), chatId, readUpTo(), null, (readMessage) -> {
+			if (readMessage != null && Reflect.compare(message.timestamp, readMessage.timestamp) <= 0) return;
+
+			markReadUpToId(message.serverId, message.serverIdBy, callback);
+		});
+	}
+
 	private function publishMds() {
 		stream.sendIq(
 			new Stanza("iq", { type: "set" })
@@ -822,25 +834,21 @@ class DirectChat extends Chat {
 
 	@HaxeCBridge.noemit // on superclass as abstract
 	public function markReadUpTo(message: ChatMessage) {
-		if (readUpTo() == message.localId || readUpTo() == message.serverId) return;
-		final upTo = message.localId ?? message.serverId;
-		if (upTo == null) return; // Can't mark as read with no id
-
-		// Only send markers for others messages,
-		// it's obvious we've read our own
-		if (message.isIncoming()) {
-			for (recipient in getParticipants()) {
-				// TODO: extended addressing when relevant
-				final stanza = new Stanza("message", { to: recipient, id: ID.long() })
-					.tag("displayed", { xmlns: "urn:xmpp:chat-markers:0", id: upTo }).up();
-				if (message.threadId != null) {
-					stanza.textTag("thread", message.threadId);
+		markReadUpToMessage(message, () -> {
+			// Only send markers for others messages,
+			// it's obvious we've read our own
+			if (message.isIncoming() && message.localId != null) {
+				for (recipient in getParticipants()) {
+					// TODO: extended addressing when relevant
+					final stanza = new Stanza("message", { to: recipient, id: ID.long() })
+						.tag("displayed", { xmlns: "urn:xmpp:chat-markers:0", id: message.localId }).up();
+					if (message.threadId != null) {
+						stanza.textTag("thread", message.threadId);
+					}
+					client.sendStanza(stanza);
 				}
-				client.sendStanza(stanza);
 			}
-		}
 
-		markReadUpToId(message.serverId, message.serverIdBy, () -> {
 			publishMds();
 			client.trigger("chats/update", [this]);
 		});
@@ -1317,17 +1325,14 @@ class Channel extends Chat {
 
 	@HaxeCBridge.noemit // on superclass as abstract
 	public function markReadUpTo(message: ChatMessage) {
-		if (readUpTo() == message.serverId) return;
-		final upTo = message.serverId;
-		if (upTo == null) return; // Can't mark as read with no id
-		final stanza = new Stanza("message", { to: chatId, id: ID.long(), type: "groupchat" })
-			.tag("displayed", { xmlns: "urn:xmpp:chat-markers:0", id: upTo }).up();
-		if (message.threadId != null) {
-			stanza.textTag("thread", message.threadId);
-		}
-		client.sendStanza(stanza);
+		markReadUpToMessage(message, () -> {
+			final stanza = new Stanza("message", { to: chatId, id: ID.long(), type: "groupchat" })
+				.tag("displayed", { xmlns: "urn:xmpp:chat-markers:0", id: message.serverId }).up();
+			if (message.threadId != null) {
+				stanza.textTag("thread", message.threadId);
+			}
+			client.sendStanza(stanza);
 
-		markReadUpToId(upTo, message.serverIdBy, () -> {
 			publishMds();
 			client.trigger("chats/update", [this]);
 		});