|  |  |  | @ -244,6 +244,7 @@ import java.util.concurrent.atomic.AtomicBoolean; | 
		
	
		
			
				|  |  |  |  | import java.util.concurrent.atomic.AtomicInteger; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | import network.loki.messenger.R; | 
		
	
		
			
				|  |  |  |  | import nl.komponents.kovenant.combine.Tuple2; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | import static org.thoughtcrime.securesms.TransportOption.Type; | 
		
	
		
			
				|  |  |  |  | import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; | 
		
	
	
		
			
				
					|  |  |  | @ -296,23 +297,24 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  |   private static final int SMS_DEFAULT         = 11; | 
		
	
		
			
				|  |  |  |  |   private static final int MEDIA_SENDER        = 12; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   private   GlideRequests              glideRequests; | 
		
	
		
			
				|  |  |  |  |   protected ComposeText                composeText; | 
		
	
		
			
				|  |  |  |  |   private   AnimatingToggle            buttonToggle; | 
		
	
		
			
				|  |  |  |  |   private   SendButton                 sendButton; | 
		
	
		
			
				|  |  |  |  |   private   ImageButton                attachButton; | 
		
	
		
			
				|  |  |  |  |   protected ConversationTitleView      titleView; | 
		
	
		
			
				|  |  |  |  |   private   TextView                   charactersLeft; | 
		
	
		
			
				|  |  |  |  |   private   ConversationFragment       fragment; | 
		
	
		
			
				|  |  |  |  |   private   Button                     unblockButton; | 
		
	
		
			
				|  |  |  |  |   private   Button                     makeDefaultSmsButton; | 
		
	
		
			
				|  |  |  |  |   private   Button                     registerButton; | 
		
	
		
			
				|  |  |  |  |   private   InputAwareLayout           container; | 
		
	
		
			
				|  |  |  |  |   private   View                       composePanel; | 
		
	
		
			
				|  |  |  |  |   protected Stub<ReminderView>         reminderView; | 
		
	
		
			
				|  |  |  |  |   private   Stub<UnverifiedBannerView> unverifiedBannerView; | 
		
	
		
			
				|  |  |  |  |   private   GlideRequests               glideRequests; | 
		
	
		
			
				|  |  |  |  |   protected ComposeText                 composeText; | 
		
	
		
			
				|  |  |  |  |   private   AnimatingToggle             buttonToggle; | 
		
	
		
			
				|  |  |  |  |   private   SendButton                  sendButton; | 
		
	
		
			
				|  |  |  |  |   private   ImageButton                 attachButton; | 
		
	
		
			
				|  |  |  |  |   protected ConversationTitleView       titleView; | 
		
	
		
			
				|  |  |  |  |   private   TextView                    charactersLeft; | 
		
	
		
			
				|  |  |  |  |   private   ConversationFragment        fragment; | 
		
	
		
			
				|  |  |  |  |   private   Button                      unblockButton; | 
		
	
		
			
				|  |  |  |  |   private   Button                      makeDefaultSmsButton; | 
		
	
		
			
				|  |  |  |  |   private   Button                      registerButton; | 
		
	
		
			
				|  |  |  |  |   private   InputAwareLayout            container; | 
		
	
		
			
				|  |  |  |  |   private   View                        composePanel; | 
		
	
		
			
				|  |  |  |  |   protected Stub<ReminderView>          reminderView; | 
		
	
		
			
				|  |  |  |  |   private   Stub<UnverifiedBannerView>  unverifiedBannerView; | 
		
	
		
			
				|  |  |  |  |   private   Stub<GroupShareProfileView> groupShareProfileView; | 
		
	
		
			
				|  |  |  |  |   private   TypingStatusTextWatcher     typingTextWatcher; | 
		
	
		
			
				|  |  |  |  |   private   MentionTextWatcher          mentionTextWatcher; | 
		
	
		
			
				|  |  |  |  |   private   ConversationSearchBottomBar searchNav; | 
		
	
		
			
				|  |  |  |  |   private   MenuItem                    searchViewItem; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -342,6 +344,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  |   private final DynamicNoActionBarTheme dynamicTheme    = new DynamicNoActionBarTheme(); | 
		
	
		
			
				|  |  |  |  |   private final DynamicLanguage         dynamicLanguage = new DynamicLanguage(); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   private UserSelectionView userSelectionView; | 
		
	
		
			
				|  |  |  |  |   private int               mentionStartIndex = -1; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   @Override | 
		
	
		
			
				|  |  |  |  |   protected void onPreCreate() { | 
		
	
	
		
			
				
					|  |  |  | @ -393,16 +397,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  |               composeText.addTextChangedListener(typingTextWatcher); | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |             composeText.setSelection(composeText.length(), composeText.length()); | 
		
	
		
			
				|  |  |  |  |             composeText.addTextChangedListener(mentionTextWatcher); | 
		
	
		
			
				|  |  |  |  |           } | 
		
	
		
			
				|  |  |  |  |         }); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     }); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     LokiAPIUtilities.INSTANCE.populateUserIDCacheIfNeeded(threadId, this); | 
		
	
		
			
				|  |  |  |  |     UserSelectionView userSelectionView = findViewById(R.id.userSelectionView); | 
		
	
		
			
				|  |  |  |  |     LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(this); | 
		
	
		
			
				|  |  |  |  |     userSelectionView.setHasGroupContext(true); | 
		
	
		
			
				|  |  |  |  |     userSelectionView.setUsers(LokiAPI.Companion.getUserIDs("", threadId, userDatabase)); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (this.recipient.isGroupRecipient()) { | 
		
	
		
			
				|  |  |  |  |       if (this.recipient.getName().equals("Loki Public Chat")) { | 
		
	
	
		
			
				
					|  |  |  | @ -1562,6 +1563,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  |     inlineAttachmentToggle = ViewUtil.findById(this, R.id.inline_attachment_container); | 
		
	
		
			
				|  |  |  |  |     inputPanel             = ViewUtil.findById(this, R.id.bottom_panel); | 
		
	
		
			
				|  |  |  |  |     searchNav              = ViewUtil.findById(this, R.id.conversation_search_nav); | 
		
	
		
			
				|  |  |  |  |     userSelectionView      = ViewUtil.findById(this, R.id.userSelectionView); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     ImageButton quickCameraToggle      = ViewUtil.findById(this, R.id.quick_camera_toggle); | 
		
	
		
			
				|  |  |  |  |     ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button); | 
		
	
	
		
			
				
					|  |  |  | @ -1574,6 +1576,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  |     attachmentManager      = new AttachmentManager(this, this); | 
		
	
		
			
				|  |  |  |  |     audioRecorder          = new AudioRecorder(this); | 
		
	
		
			
				|  |  |  |  |     typingTextWatcher      = new TypingStatusTextWatcher(); | 
		
	
		
			
				|  |  |  |  |     mentionTextWatcher     = new MentionTextWatcher(); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     SendButtonListener        sendButtonListener        = new SendButtonListener(); | 
		
	
		
			
				|  |  |  |  |     ComposeKeyPressedListener composeKeyPressedListener = new ComposeKeyPressedListener(); | 
		
	
	
		
			
				
					|  |  |  | @ -2601,7 +2604,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   private void silentlySetComposeText(String text) { | 
		
	
		
			
				|  |  |  |  |     typingTextWatcher.setEnabled(false); | 
		
	
		
			
				|  |  |  |  |     mentionTextWatcher.setEnabled(false); | 
		
	
		
			
				|  |  |  |  |     composeText.setText(text); | 
		
	
		
			
				|  |  |  |  |     mentionTextWatcher.setEnabled(true); | 
		
	
		
			
				|  |  |  |  |     typingTextWatcher.setEnabled(true); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -2716,7 +2721,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   private class TypingStatusTextWatcher extends SimpleTextWatcher { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     private boolean enabled = true; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     @Override | 
		
	
	
		
			
				
					|  |  |  | @ -2731,6 +2735,36 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   private class MentionTextWatcher extends SimpleTextWatcher { | 
		
	
		
			
				|  |  |  |  |     private boolean enabled = true; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     @Override | 
		
	
		
			
				|  |  |  |  |     public void onTextChanged(String text) { | 
		
	
		
			
				|  |  |  |  |       if (!enabled) { return; } | 
		
	
		
			
				|  |  |  |  |       int currentEndIndex = (text.length() != 0) ? text.length() - 1 : 0; | 
		
	
		
			
				|  |  |  |  |       char lastCharacter = text.charAt(currentEndIndex); | 
		
	
		
			
				|  |  |  |  |       LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(ConversationActivity.this); | 
		
	
		
			
				|  |  |  |  |       if (lastCharacter == '@') { | 
		
	
		
			
				|  |  |  |  |         List<Tuple2<String, String>> users = LokiAPI.Companion.getUsers("", threadId, userDatabase); | 
		
	
		
			
				|  |  |  |  |         mentionStartIndex = currentEndIndex + 1; | 
		
	
		
			
				|  |  |  |  |         userSelectionView.show(users, threadId); | 
		
	
		
			
				|  |  |  |  |       } else if (!Character.isAlphabetic(lastCharacter) || !Character.isUpperCase(lastCharacter) || !Character.isLowerCase(lastCharacter)) { | 
		
	
		
			
				|  |  |  |  |         mentionStartIndex = -1; | 
		
	
		
			
				|  |  |  |  |         userSelectionView.hide(); | 
		
	
		
			
				|  |  |  |  |       } else { | 
		
	
		
			
				|  |  |  |  |         if (mentionStartIndex != -1) { | 
		
	
		
			
				|  |  |  |  |           String query = text.substring(mentionStartIndex); | 
		
	
		
			
				|  |  |  |  |           List<Tuple2<String, String>> users = LokiAPI.Companion.getUsers(query, threadId, userDatabase); | 
		
	
		
			
				|  |  |  |  |           userSelectionView.show(users, threadId); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     public void setEnabled(boolean enabled) { | 
		
	
		
			
				|  |  |  |  |       this.enabled = enabled; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   @Override | 
		
	
		
			
				|  |  |  |  |   public void setThreadId(long threadId) { | 
		
	
		
			
				|  |  |  |  |     this.threadId = threadId; | 
		
	
	
		
			
				
					|  |  |  | @ -2757,11 +2791,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       inputPanel.setQuote(GlideApp.with(this), | 
		
	
		
			
				|  |  |  |  |                           messageRecord.getDateSent(), | 
		
	
		
			
				|  |  |  |  |                           author, | 
		
	
		
			
				|  |  |  |  |                           body, | 
		
	
		
			
				|  |  |  |  |                           slideDeck, | 
		
	
		
			
				|  |  |  |  |                           recipient); | 
		
	
		
			
				|  |  |  |  |               messageRecord.getDateSent(), | 
		
	
		
			
				|  |  |  |  |               author, | 
		
	
		
			
				|  |  |  |  |               body, | 
		
	
		
			
				|  |  |  |  |               slideDeck, | 
		
	
		
			
				|  |  |  |  |               recipient); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     } else if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) { | 
		
	
		
			
				|  |  |  |  |       LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0); | 
		
	
	
		
			
				
					|  |  |  | @ -2772,18 +2806,18 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       inputPanel.setQuote(GlideApp.with(this), | 
		
	
		
			
				|  |  |  |  |                           messageRecord.getDateSent(), | 
		
	
		
			
				|  |  |  |  |                           author, | 
		
	
		
			
				|  |  |  |  |                           messageRecord.getBody(), | 
		
	
		
			
				|  |  |  |  |                           slideDeck, | 
		
	
		
			
				|  |  |  |  |                           recipient); | 
		
	
		
			
				|  |  |  |  |               messageRecord.getDateSent(), | 
		
	
		
			
				|  |  |  |  |               author, | 
		
	
		
			
				|  |  |  |  |               messageRecord.getBody(), | 
		
	
		
			
				|  |  |  |  |               slideDeck, | 
		
	
		
			
				|  |  |  |  |               recipient); | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |       inputPanel.setQuote(GlideApp.with(this), | 
		
	
		
			
				|  |  |  |  |                           messageRecord.getDateSent(), | 
		
	
		
			
				|  |  |  |  |                           author, | 
		
	
		
			
				|  |  |  |  |                           messageRecord.getBody(), | 
		
	
		
			
				|  |  |  |  |                           messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(), | 
		
	
		
			
				|  |  |  |  |                           recipient); | 
		
	
		
			
				|  |  |  |  |               messageRecord.getDateSent(), | 
		
	
		
			
				|  |  |  |  |               author, | 
		
	
		
			
				|  |  |  |  |               messageRecord.getBody(), | 
		
	
		
			
				|  |  |  |  |               messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(), | 
		
	
		
			
				|  |  |  |  |               recipient); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | 
 |