diff --git a/res/layout/view_user_selection.xml b/res/layout/view_user_selection.xml index 5a7ada38b5..85bfc15e3f 100644 --- a/res/layout/view_user_selection.xml +++ b/res/layout/view_user_selection.xml @@ -3,5 +3,5 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/userSelectionView" android:layout_width="match_parent" - android:layout_height="200dp" + android:layout_height="0dp" android:paddingTop="6dp" /> \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index e06bc9cb12..6bb119d1d1 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -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; - private Stub 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; + private Stub unverifiedBannerView; private Stub 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> 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> 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); } } diff --git a/src/org/thoughtcrime/securesms/loki/UserSelectionView.kt b/src/org/thoughtcrime/securesms/loki/UserSelectionView.kt index 9864e30594..3c56409012 100644 --- a/src/org/thoughtcrime/securesms/loki/UserSelectionView.kt +++ b/src/org/thoughtcrime/securesms/loki/UserSelectionView.kt @@ -8,11 +8,12 @@ import android.view.ViewGroup import android.widget.BaseAdapter import android.widget.ListView import nl.komponents.kovenant.combine.Tuple2 +import org.thoughtcrime.securesms.database.DatabaseFactory class UserSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ListView(context, attrs, defStyleAttr) { - var users = listOf>() + private var users = listOf>() set(newValue) { field = newValue; userSelectionViewAdapter.users = newValue } - var hasGroupContext = false + private var hasGroupContext = false private val userSelectionViewAdapter by lazy { Adapter(context) } @@ -49,4 +50,18 @@ class UserSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: In adapter = userSelectionViewAdapter userSelectionViewAdapter.users = users } + + fun show(users: List>, threadID: Long) { + hasGroupContext = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID)!!.isGroupRecipient + this.users = users + val layoutParams = this.layoutParams as ViewGroup.LayoutParams + layoutParams.height = toPx(6 + Math.min(users.count(), 4) * 52, resources) + this.layoutParams = layoutParams + } + + fun hide() { + val layoutParams = this.layoutParams as ViewGroup.LayoutParams + layoutParams.height = 0 + this.layoutParams = layoutParams + } } \ No newline at end of file