git » sdk » commit 05d7379

addReaction using an object not a string

author Stephen Paul Weber
2024-11-14 04:42:52 UTC
committer Stephen Paul Weber
2024-11-14 04:42:52 UTC
parent 7adcfb336543271f3cc848cd07acb44b0a78dd27

addReaction using an object not a string

So that custom emoji reactions can be added as well
Normalized emoji a bit wrt variant selectors

snikket/Chat.hx +12 -2
snikket/Hash.hx +5 -0
snikket/Reaction.hx +4 -2
snikket/Stanza.hx +1 -2
snikket/Util.hx +5 -0

diff --git a/snikket/Chat.hx b/snikket/Chat.hx
index 8e87428..12a8590 100644
--- a/snikket/Chat.hx
+++ b/snikket/Chat.hx
@@ -15,6 +15,7 @@ import snikket.jingle.Session;
 import snikket.queries.DiscoInfoGet;
 import snikket.queries.MAMQuery;
 using Lambda;
+using StringTools;
 
 #if cpp
 import HaxeCBridge;
@@ -192,9 +193,18 @@ abstract class Chat {
 		@param m ChatMessage to react to
 		@param reaction emoji of the reaction
 	**/
-	public function addReaction(m:ChatMessage, reaction:String) {
+	public function addReaction(m:ChatMessage, reaction:Reaction) {
 		final toSend = m.reply();
-		toSend.text = reaction;
+		reaction.render(
+			(text) -> {
+				toSend.text = text.replace("\u{fe0f}", "");
+				return;
+			},
+			(text, uri) -> {
+				final hash = Hash.fromUri(uri);
+				toSend.setHtml('<img alt="' + Util.xmlEscape(text) + '" src="' + Util.xmlEscape(hash == null ? uri : hash.bobUri()) + '" />');
+			}
+		);
 		sendMessage(toSend);
 	}
 
diff --git a/snikket/Hash.hx b/snikket/Hash.hx
index 71c1f1a..dbcc0e0 100644
--- a/snikket/Hash.hx
+++ b/snikket/Hash.hx
@@ -60,6 +60,11 @@ class Hash {
 		}
 	}
 
+	@:allow(snikket)
+	private function bobUri() {
+		return "cid:" + (algorithm == "sha-1" ? "sha1" : algorithm.urlEncode()) + "+" + toHex() + "@bob.xmpp.org";
+	}
+
 	@:allow(snikket)
 	private function serializeUri() {
 		return "ni:///" + algorithm.urlEncode() + ";" + toBase64Url();
diff --git a/snikket/Reaction.hx b/snikket/Reaction.hx
index be6947a..281be21 100644
--- a/snikket/Reaction.hx
+++ b/snikket/Reaction.hx
@@ -1,5 +1,7 @@
 package snikket;
 
+using StringTools;
+
 @:nullSafety(Strict)
 @:expose
 class Reaction {
@@ -11,8 +13,8 @@ class Reaction {
 	public function new(senderId: String, timestamp: String, text: String, key: Null<String> = null) {
 		this.senderId = senderId;
 		this.timestamp = timestamp;
-		this.text = text;
-		this.key = key ?? text;
+		this.text = text.replace("\u{fe0f}", "");
+		this.key = key ?? this.text;
 	}
 
 	public function render<T>(forText: (String) -> T, forImage: (String, String) -> T) {
diff --git a/snikket/Stanza.hx b/snikket/Stanza.hx
index ba95bf6..e7c33ae 100644
--- a/snikket/Stanza.hx
+++ b/snikket/Stanza.hx
@@ -26,8 +26,7 @@ class TextNode implements NodeInterface {
 	}
 
 	public function serialize():String {
-		// NOTE: using STringTools.htmlEscape breaks things if this is one half of a surrogate pair in an adjacent cdata
-		return StringTools.replace(StringTools.replace(StringTools.replace(content, "&", "&amp;"), "<", "&lt;"), ">", "&gt;");
+		return Util.xmlEscape(content);
 	}
 
 	public function clone():TextNode {
diff --git a/snikket/Util.hx b/snikket/Util.hx
index 0f76785..15b54ba 100644
--- a/snikket/Util.hx
+++ b/snikket/Util.hx
@@ -21,6 +21,11 @@ function downcast<T, S>(value: T, c: Class<S>): Null<S> {
 	return cast Std.downcast(cast value, cast c);
 }
 
+function xmlEscape(s: String) {
+	// NOTE: using STringTools.htmlEscape breaks things if this is one half of a surrogate pair in an adjacent cdata
+	return StringTools.replace(StringTools.replace(StringTools.replace(s, "&", "&amp;"), "<", "&lt;"), ">", "&gt;");
+}
+
 macro function getGitVersion():haxe.macro.Expr.ExprOf<String> {
 	#if !display
 	var process = new sys.io.Process('git', ['describe', '--always']);