be more careful with corner cases when mentioning multiple people

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/entities/Conversation.java     | 11 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java   | 16 
src/main/java/eu/siacs/conversations/utils/NickValidityChecker.java | 33 
3 files changed, 55 insertions(+), 5 deletions(-)

Detailed changes

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

@@ -289,6 +289,17 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
 		return null;
 	}
 
+	public boolean hasMessageWithCounterpart(Jid counterpart) {
+		synchronized (this.messages) {
+			for(Message message : this.messages) {
+				if (counterpart.equals(message.getCounterpart())) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
 	public void populateWithMessages(final List<Message> messages) {
 		synchronized (this.messages) {
 			messages.clear();

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

@@ -43,8 +43,11 @@ import android.widget.Toast;
 import net.java.otr4j.session.SessionStatus;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -71,6 +74,7 @@ import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
 import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked;
 import eu.siacs.conversations.ui.widget.ListSelectionManager;
 import eu.siacs.conversations.utils.GeoHelper;
+import eu.siacs.conversations.utils.NickValidityChecker;
 import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.xmpp.XmppConnection;
 import eu.siacs.conversations.xmpp.chatstate.ChatState;
@@ -845,13 +849,15 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
 				editable.insert(pos, nick + ": ");
 			} else {
 				if (pos > 2 && editable.subSequence(pos-2,pos).toString().equals(": ")) {
-					editable.insert(pos-2,", "+nick);
-				} else {
-					editable.insert(pos, (Character.isWhitespace(before) ? "" : " ") + nick + (Character.isWhitespace(after) ? "" : " "));
-					if (Character.isWhitespace(after)) {
-						mEditMessage.setSelection(mEditMessage.getSelectionStart() + 1);
+					if (NickValidityChecker.check(conversation,Arrays.asList(editable.subSequence(0,pos-2).toString().split(", ")))) {
+						editable.insert(pos - 2, ", " + nick);
+						return;
 					}
 				}
+				editable.insert(pos, (Character.isWhitespace(before) ? "" : " ") + nick + (Character.isWhitespace(after) ? "" : " "));
+				if (Character.isWhitespace(after)) {
+					mEditMessage.setSelection(mEditMessage.getSelectionStart() + 1);
+				}
 			}
 		}
 	}

src/main/java/eu/siacs/conversations/utils/NickValidityChecker.java 🔗

@@ -0,0 +1,33 @@
+package eu.siacs.conversations.utils;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.xmpp.jid.InvalidJidException;
+import eu.siacs.conversations.xmpp.jid.Jid;
+
+public class NickValidityChecker {
+
+    private static boolean check(final Conversation conversation, final String nick) {
+        Jid room = conversation.getJid();
+        try {
+            Jid full = Jid.fromParts(room.getLocalpart(), room.getDomainpart(), nick);
+            return conversation.hasMessageWithCounterpart(full)
+                    || conversation.getMucOptions().findUserByFullJid(full) != null;
+        } catch (InvalidJidException e) {
+            return false;
+        }
+    }
+
+    public static boolean check(final Conversation conversation, final List<String> nicks) {
+        Set<String> previousNicks = new HashSet<>(nicks);
+        for(String previousNick : previousNicks) {
+            if (!NickValidityChecker.check(conversation,previousNick)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}