From 2728a96ab9178e30b3edee46a2fff678d582bd06 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 12 Feb 2023 17:25:26 +0100 Subject: [PATCH] add helper method to count reactions --- .../android/xmpp/TransformationTest.java | 42 +++++++++++++++++++ .../eu/siacs/conversations/xml/Element.java | 15 +++---- .../model/MessageWithContentReactions.java | 15 +++++++ .../android/xmpp/model/jabber/Body.java | 5 +++ .../xmpp/model/reactions/Reaction.java | 5 +++ .../xmpp/model/reactions/Reactions.java | 6 +++ .../android/xmpp/model/stanza/Message.java | 13 ++++++ 7 files changed, 94 insertions(+), 7 deletions(-) diff --git a/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java b/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java index e0d70aea8..7d8b778cd 100644 --- a/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java +++ b/src/androidTest/java/im/conversations/android/xmpp/TransformationTest.java @@ -80,6 +80,48 @@ public class TransformationTest { Assert.assertEquals(REMOTE, onlyReaction.reactionBy); } + @Test + public void multipleReactions() { + final var group = Jid.ofEscaped("a@group.example.com"); + final var message = new Message(Message.Type.GROUPCHAT); + message.addExtension(new Body("Please give me a thumbs up")); + message.setFrom(group.withResource("user-a")); + this.transformer.transform( + Transformation.of(message, Instant.now(), REMOTE, "stanza-a", "id-user-a")); + + final var reactionA = new Message(Message.Type.GROUPCHAT); + reactionA.setFrom(group.withResource("user-b")); + reactionA.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y")); + this.transformer.transform( + Transformation.of(reactionA, Instant.now(), REMOTE, "stanza-b", "id-user-b")); + + final var reactionB = new Message(Message.Type.GROUPCHAT); + reactionB.setFrom(group.withResource("user-c")); + reactionB.addExtension(Reactions.to("stanza-a")).addExtension(new Reaction("Y")); + this.transformer.transform( + Transformation.of(reactionB, Instant.now(), REMOTE, "stanza-c", "id-user-c")); + + final var reactionC = new Message(Message.Type.GROUPCHAT); + reactionC.setFrom(group.withResource("user-d")); + final var reactions = reactionC.addExtension(Reactions.to("stanza-a")); + reactions.addExtension(new Reaction("Y")); + reactions.addExtension(new Reaction("Z")); + this.transformer.transform( + Transformation.of(reactionC, Instant.now(), REMOTE, "stanza-d", "id-user-d")); + + final var messages = database.messageDao().getMessages(1L); + Assert.assertEquals(1, messages.size()); + final var dbMessage = Iterables.getOnlyElement(messages); + Assert.assertEquals(4, dbMessage.reactions.size()); + final var aggregated = dbMessage.getAggregatedReactions(); + final var mostFrequentReaction = Iterables.get(aggregated, 0); + Assert.assertEquals("Y", mostFrequentReaction.getKey()); + Assert.assertEquals(3L, (long) mostFrequentReaction.getValue()); + final var secondReaction = Iterables.get(aggregated, 1); + Assert.assertEquals("Z", secondReaction.getKey()); + Assert.assertEquals(1L, (long) secondReaction.getValue()); + } + @Test public void correctionBeforeOriginal() { diff --git a/src/main/java/eu/siacs/conversations/xml/Element.java b/src/main/java/eu/siacs/conversations/xml/Element.java index b43ea4f25..3210841f4 100644 --- a/src/main/java/eu/siacs/conversations/xml/Element.java +++ b/src/main/java/eu/siacs/conversations/xml/Element.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.xml; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; @@ -159,18 +160,18 @@ public class Element { return content; } - public Element setAttribute(String name, String value) { - if (name != null && value != null) { + public Element setAttribute(final String name, final String value) { + Preconditions.checkArgument(name != null, "The attribute must have a name"); + if (value == null) { + this.attributes.remove(name); + } else { this.attributes.put(name, value); } return this; } - public Element setAttribute(String name, Jid value) { - if (name != null && value != null) { - this.attributes.put(name, value.toEscapedString()); - } - return this; + public Element setAttribute(final String name, final Jid value) { + return this.setAttribute(name, value == null ? null : value.toEscapedString()); } public void removeAttribute(final String name) { diff --git a/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java b/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java index 8ac2f832e..cb237738c 100644 --- a/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java +++ b/src/main/java/im/conversations/android/database/model/MessageWithContentReactions.java @@ -1,11 +1,17 @@ package im.conversations.android.database.model; import androidx.room.Relation; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimaps; import eu.siacs.conversations.xmpp.Jid; import im.conversations.android.database.entity.MessageContentEntity; import im.conversations.android.database.entity.MessageReactionEntity; import java.time.Instant; +import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Set; public class MessageWithContentReactions { @@ -34,4 +40,13 @@ public class MessageWithContentReactions { parentColumn = "id", entityColumn = "messageEntityId") public List reactions; + + public Set> getAggregatedReactions() { + final Map aggregatedReactions = + Maps.transformValues( + Multimaps.index(reactions, r -> r.reaction).asMap(), Collection::size); + return ImmutableSortedSet.copyOf( + (a, b) -> Integer.compare(b.getValue(), a.getValue()), + aggregatedReactions.entrySet()); + } } diff --git a/src/main/java/im/conversations/android/xmpp/model/jabber/Body.java b/src/main/java/im/conversations/android/xmpp/model/jabber/Body.java index 71b49f2e3..5857f0585 100644 --- a/src/main/java/im/conversations/android/xmpp/model/jabber/Body.java +++ b/src/main/java/im/conversations/android/xmpp/model/jabber/Body.java @@ -10,6 +10,11 @@ public class Body extends Extension { super(Body.class); } + public Body(final String content) { + this(); + setContent(content); + } + public String getLang() { return this.getAttribute("xml:lang"); } diff --git a/src/main/java/im/conversations/android/xmpp/model/reactions/Reaction.java b/src/main/java/im/conversations/android/xmpp/model/reactions/Reaction.java index de9bd7f2a..1d854a83a 100644 --- a/src/main/java/im/conversations/android/xmpp/model/reactions/Reaction.java +++ b/src/main/java/im/conversations/android/xmpp/model/reactions/Reaction.java @@ -9,4 +9,9 @@ public class Reaction extends Extension { public Reaction() { super(Reaction.class); } + + public Reaction(final String reaction) { + this(); + setContent(reaction); + } } diff --git a/src/main/java/im/conversations/android/xmpp/model/reactions/Reactions.java b/src/main/java/im/conversations/android/xmpp/model/reactions/Reactions.java index 0ea2972e2..ec3ae9891 100644 --- a/src/main/java/im/conversations/android/xmpp/model/reactions/Reactions.java +++ b/src/main/java/im/conversations/android/xmpp/model/reactions/Reactions.java @@ -27,4 +27,10 @@ public class Reactions extends Extension { public void setId(String id) { this.setAttribute("id", id); } + + public static Reactions to(final String id) { + final var reactions = new Reactions(); + reactions.setId(id); + return reactions; + } } diff --git a/src/main/java/im/conversations/android/xmpp/model/stanza/Message.java b/src/main/java/im/conversations/android/xmpp/model/stanza/Message.java index e00318b9f..4a12c92ee 100644 --- a/src/main/java/im/conversations/android/xmpp/model/stanza/Message.java +++ b/src/main/java/im/conversations/android/xmpp/model/stanza/Message.java @@ -10,6 +10,11 @@ public class Message extends Stanza { super(Message.class); } + public Message(Type type) { + this(); + this.setType(type); + } + public String getBody() { return this.findChildContent("body"); } @@ -27,6 +32,14 @@ public class Message extends Stanza { } } + public void setType(final Type type) { + if (type == null || type == Type.NORMAL) { + this.removeAttribute("type"); + } else { + this.setAttribute("type", type.toString().toLowerCase(Locale.ROOT)); + } + } + public enum Type { ERROR, NORMAL,