show who has reacted when long pressing reaction

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/entities/MucOptions.java       | 45 
src/main/java/eu/siacs/conversations/ui/BindingAdapters.java        | 12 
src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java | 27 
3 files changed, 76 insertions(+), 8 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/MucOptions.java 🔗

@@ -5,6 +5,10 @@ import android.text.TextUtils;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.services.AvatarService;
@@ -20,6 +24,7 @@ import eu.siacs.conversations.xmpp.pep.Avatar;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -331,12 +336,19 @@ public class MucOptions {
         return null;
     }
 
+    public User findUserByOccupantId(final String occupantId) {
+        synchronized (this.users) {
+            return Strings.isNullOrEmpty(occupantId) ? null : Iterables.find(this.users, u -> occupantId.equals(u.occupantId),null);
+        }
+    }
+
     public User findOrCreateUserByRealJid(Jid jid, Jid fullJid) {
-        User user = findUserByRealJid(jid);
-        if (user == null) {
-            user = new User(this, fullJid);
-            user.setRealJid(jid);
+        final User existing = findUserByRealJid(jid);
+        if (existing != null) {
+            return existing;
         }
+        final var user = new User(this, fullJid);
+        user.setRealJid(jid);
         return user;
     }
 
@@ -350,6 +362,31 @@ public class MucOptions {
         }
     }
 
+    private User findUser(final Reaction reaction) {
+        if (reaction.trueJid != null) {
+            return findOrCreateUserByRealJid(reaction.trueJid.asBareJid(), reaction.from);
+        }
+        final var existing = findUserByOccupantId(reaction.occupantId);
+        if (existing != null) {
+            return existing;
+        } else if (reaction.from != null) {
+            return new User(this,reaction.from);
+        } else {
+            return null;
+        }
+    }
+
+    public List<User> findUsers(final Collection<Reaction> reactions) {
+        final ImmutableList.Builder<User> builder = new ImmutableList.Builder<>();
+        for(final Reaction reaction : reactions) {
+            final var user = findUser(reaction);
+            if (user != null) {
+                builder.add(user);
+            }
+        }
+        return builder.build();
+    }
+
     public boolean isContactInRoom(Contact contact) {
         return contact != null && findUserByRealJid(contact.getJid().asBareJid()) != null;
     }

src/main/java/eu/siacs/conversations/ui/BindingAdapters.java 🔗

@@ -16,6 +16,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 public class BindingAdapters {
 
@@ -23,15 +24,18 @@ public class BindingAdapters {
             final ChipGroup chipGroup,
             final Reaction.Aggregated reactions,
             final Consumer<Collection<String>> onModifiedReactions,
+            final Function<String, Boolean> onDetailsClicked,
             final Runnable addReaction) {
-        setReactions(chipGroup, reactions, true, onModifiedReactions, addReaction);
+        setReactions(
+                chipGroup, reactions, true, onModifiedReactions, onDetailsClicked, addReaction);
     }
 
     public static void setReactionsOnSent(
             final ChipGroup chipGroup,
             final Reaction.Aggregated reactions,
-            final Consumer<Collection<String>> onModifiedReactions) {
-        setReactions(chipGroup, reactions, false, onModifiedReactions, null);
+            final Consumer<Collection<String>> onModifiedReactions,
+            final Function<String, Boolean> onDetailsClicked) {
+        setReactions(chipGroup, reactions, false, onModifiedReactions, onDetailsClicked, null);
     }
 
     private static void setReactions(
@@ -39,6 +43,7 @@ public class BindingAdapters {
             final Reaction.Aggregated aggregated,
             final boolean onReceived,
             final Consumer<Collection<String>> onModifiedReactions,
+            final Function<String, Boolean> onDetailsClicked,
             final Runnable addReaction) {
         final var context = chipGroup.getContext();
         final List<Map.Entry<String, Integer>> reactions = aggregated.reactions;
@@ -89,6 +94,7 @@ public class BindingAdapters {
                                                 .build());
                             }
                         });
+                chip.setOnLongClickListener(v -> onDetailsClicked.apply(emoji));
                 chipGroup.addView(chip);
             }
             if (onReceived) {

src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java 🔗

@@ -45,8 +45,10 @@ import com.google.android.material.color.MaterialColors;
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.common.base.Joiner;
 import com.google.common.base.Strings;
+import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
 
 import eu.siacs.conversations.AppSettings;
 import eu.siacs.conversations.Config;
@@ -1077,18 +1079,41 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                     viewHolder.reactions,
                     message.getAggregatedReactions(),
                     reactions -> sendReactions(message, reactions),
+                    emoji -> showDetailedReaction(message, emoji),
                     () -> addReaction(message));
         } else if (type == SENT) {
             BindingAdapters.setReactionsOnSent(
                     viewHolder.reactions,
                     message.getAggregatedReactions(),
-                    reactions -> sendReactions(message, reactions));
+                    reactions -> sendReactions(message, reactions),
+                    emoji -> showDetailedReaction(message, emoji));
         }
 
         displayStatus(viewHolder, message, type, bubbleColor);
         return view;
     }
 
+    private boolean showDetailedReaction(final Message message, final String emoji) {
+        final var c = message.getConversation();
+        if (c instanceof Conversation conversation && c.getMode() == Conversational.MODE_MULTI) {
+            final var reactions =
+                    Collections2.filter(message.getReactions(), r -> r.reaction.equals(emoji));
+            final var mucOptions = conversation.getMucOptions();
+            final var users = mucOptions.findUsers(reactions);
+            if (users.isEmpty()) {
+                return true;
+            }
+            final MaterialAlertDialogBuilder dialogBuilder =
+                    new MaterialAlertDialogBuilder(activity);
+            dialogBuilder.setTitle(emoji);
+            dialogBuilder.setMessage(UIHelper.concatNames(users));
+            dialogBuilder.create().show();
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     private void sendReactions(final Message message, final Collection<String> reactions) {
         if (activity.xmppConnectionService.sendReactions(message, reactions)) {
             return;