diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index a601ded29..28dc19f16 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -6,13 +6,11 @@ import android.content.res.Resources import android.database.Cursor import android.graphics.Rect import android.os.Bundle -import android.util.Log import android.view.ActionMode import android.view.Menu import android.view.MenuItem import android.view.MotionEvent import android.widget.RelativeLayout -import androidx.core.view.marginBottom import androidx.loader.app.LoaderManager import androidx.loader.content.Loader import androidx.recyclerview.widget.LinearLayoutManager @@ -23,15 +21,17 @@ import kotlinx.android.synthetic.main.view_input_bar.view.* import kotlinx.android.synthetic.main.view_input_bar_recording.* import kotlinx.android.synthetic.main.view_input_bar_recording.view.* import network.loki.messenger.R +import org.session.libsession.messaging.mentions.MentionsManager +import org.session.libsession.messaging.mentions.MentionsManager.getMentionCandidates import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarDelegate import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarRecordingViewDelegate +import org.thoughtcrime.securesms.conversation.v2.input_bar.mentions.MentionCandidatesView import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallback import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.model.MessageRecord -import org.thoughtcrime.securesms.loki.utilities.toDp import org.thoughtcrime.securesms.loki.utilities.toPx import org.thoughtcrime.securesms.mms.GlideApp import kotlin.math.abs @@ -152,9 +152,15 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe // region Updating override fun inputBarHeightChanged(newValue: Int) { + // Recycler view val recyclerViewLayoutParams = conversationRecyclerView.layoutParams as RelativeLayout.LayoutParams - recyclerViewLayoutParams.bottomMargin = newValue + recyclerViewLayoutParams.bottomMargin = newValue + inputBarAdditionalContentContainer.height conversationRecyclerView.layoutParams = recyclerViewLayoutParams + // Input bar additional content container + val inputBarAdditionalContentContainerLayoutParams = inputBarAdditionalContentContainer.layoutParams as RelativeLayout.LayoutParams + inputBarAdditionalContentContainerLayoutParams.bottomMargin = newValue + inputBarAdditionalContentContainer.layoutParams = inputBarAdditionalContentContainerLayoutParams + // Attachment options val attachmentButtonHeight = inputBar.attachmentsButtonContainer.height val bottomMargin = (newValue - attachmentButtonHeight) / 2 val margin = toPx(8, resources) @@ -163,6 +169,22 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe attachmentOptionsContainer.layoutParams = attachmentOptionsContainerLayoutParams } + override fun inputBarEditTextContentChanged(newContent: CharSequence) { + // TODO: Work this out further + if (newContent.contains("@")) { + showMentionCandidates() + } + } + + private fun showMentionCandidates() { + inputBarAdditionalContentContainer.removeAllViews() + val mentionCandidatesView = MentionCandidatesView(this) + mentionCandidatesView.glide = glide + inputBarAdditionalContentContainer.addView(mentionCandidatesView) + val mentionCandidates = MentionsManager.getMentionCandidates("", threadID, thread.isOpenGroupRecipient) + mentionCandidatesView.show(mentionCandidates, threadID) + } + override fun toggleAttachmentOptions() { val targetAlpha = if (isShowingAttachmentOptions) 0.0f else 1.0f val allButtons = listOf( cameraButtonContainer, libraryButtonContainer, documentButtonContainer, gifButtonContainer) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt index 1db4a5c2a..596f5cf6c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt @@ -52,6 +52,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate { override fun inputBarEditTextContentChanged(text: CharSequence) { sendButton.isVisible = text.isNotEmpty() microphoneButton.isVisible = text.isEmpty() + delegate?.inputBarEditTextContentChanged(text) } override fun inputBarEditTextHeightChanged(newValue: Int) { @@ -76,6 +77,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate { interface InputBarDelegate { fun inputBarHeightChanged(newValue: Int) + fun inputBarEditTextContentChanged(newContent: CharSequence) fun toggleAttachmentOptions() fun showVoiceMessageUI() fun onMicrophoneButtonMove(event: MotionEvent) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt new file mode 100644 index 000000000..2159a5dac --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidateView.kt @@ -0,0 +1,47 @@ +package org.thoughtcrime.securesms.conversation.v2.input_bar.mentions + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.RelativeLayout +import kotlinx.android.synthetic.main.view_mention_candidate.view.* +import network.loki.messenger.R +import org.session.libsession.messaging.mentions.Mention +import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 +import org.thoughtcrime.securesms.mms.GlideRequests + +class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : RelativeLayout(context, attrs, defStyleAttr) { + var candidate = Mention("", "") + set(newValue) { field = newValue; update() } + var glide: GlideRequests? = null + var openGroupServer: String? = null + var openGroupRoom: String? = null + + constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) + constructor(context: Context) : this(context, null) + + companion object { + + fun inflate(layoutInflater: LayoutInflater, parent: ViewGroup): MentionCandidateView { + return layoutInflater.inflate(R.layout.view_mention_candidate_v2, parent, false) as MentionCandidateView + } + } + + private fun update() { + mentionCandidateNameTextView.text = candidate.displayName + profilePictureView.publicKey = candidate.publicKey + profilePictureView.displayName = candidate.displayName + profilePictureView.additionalPublicKey = null + profilePictureView.glide = glide!! + profilePictureView.update() + if (openGroupServer != null && openGroupRoom != null) { + val isUserModerator = OpenGroupAPIV2.isUserModerator(candidate.publicKey, openGroupRoom!!, openGroupServer!!) + moderatorIconImageView.visibility = if (isUserModerator) View.VISIBLE else View.GONE + } else { + moderatorIconImageView.visibility = View.GONE + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidatesView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidatesView.kt new file mode 100644 index 000000000..01aa0c06a --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/mentions/MentionCandidatesView.kt @@ -0,0 +1,79 @@ +package org.thoughtcrime.securesms.conversation.v2.input_bar.mentions + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.ListView +import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.loki.utilities.toPx +import org.thoughtcrime.securesms.mms.GlideRequests +import org.session.libsession.messaging.mentions.Mention + +class MentionCandidatesView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ListView(context, attrs, defStyleAttr) { + private var candidates = listOf() + set(newValue) { field = newValue; snAdapter.mentionCandidates = newValue } + var glide: GlideRequests? = null + set(newValue) { field = newValue; snAdapter.glide = newValue } + var openGroupServer: String? = null + set(newValue) { field = newValue; snAdapter.openGroupServer = openGroupServer } + var openGroupRoom: String? = null + set(newValue) { field = newValue; snAdapter.openGroupRoom = openGroupRoom } + var onCandidateSelected: ((Mention) -> Unit)? = null + + private val snAdapter by lazy { Adapter(context) } + + private class Adapter(private val context: Context) : BaseAdapter() { + var mentionCandidates = listOf() + set(newValue) { field = newValue; notifyDataSetChanged() } + var glide: GlideRequests? = null + var openGroupServer: String? = null + var openGroupRoom: String? = null + + override fun getCount(): Int { return mentionCandidates.count() } + override fun getItemId(position: Int): Long { return position.toLong() } + override fun getItem(position: Int): Mention { return mentionCandidates[position] } + + override fun getView(position: Int, cellToBeReused: View?, parent: ViewGroup): View { + val cell = cellToBeReused as MentionCandidateView? ?: MentionCandidateView.inflate(LayoutInflater.from(context), parent) + val mentionCandidate = getItem(position) + cell.glide = glide + cell.candidate = mentionCandidate + cell.openGroupServer = openGroupServer + cell.openGroupRoom = openGroupRoom + return cell + } + } + + constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) + constructor(context: Context) : this(context, null) + + init { + clipToOutline = true + adapter = snAdapter + snAdapter.mentionCandidates = candidates + setOnItemClickListener { _, _, position, _ -> + onCandidateSelected?.invoke(candidates[position]) + } + } + + fun show(mentionCandidates: List, threadID: Long) { + val openGroup = DatabaseFactory.getLokiThreadDatabase(context).getOpenGroupChat(threadID) + if (openGroup != null) { + openGroupServer = openGroup.server + openGroupRoom = openGroup.room + } + this.candidates = mentionCandidates + val layoutParams = this.layoutParams as ViewGroup.LayoutParams + layoutParams.height = toPx(Math.min(mentionCandidates.count(), 4) * 44, 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 diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt index d355597bf..e8e1c4f9a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt @@ -30,7 +30,7 @@ class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: } private fun update() { - btnGroupNameDisplay.text = mentionCandidate.displayName + mentionCandidateNameTextView.text = mentionCandidate.displayName profilePictureView.publicKey = mentionCandidate.publicKey profilePictureView.displayName = mentionCandidate.displayName profilePictureView.additionalPublicKey = null diff --git a/app/src/main/res/drawable/mention_candidate_view_background.xml b/app/src/main/res/drawable/mention_candidate_view_background.xml index af9549d11..1b30b3e72 100644 --- a/app/src/main/res/drawable/mention_candidate_view_background.xml +++ b/app/src/main/res/drawable/mention_candidate_view_background.xml @@ -1,9 +1,9 @@ + android:color="@color/mention_candidates_view_background_ripple"> - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_conversation_v2.xml b/app/src/main/res/layout/activity_conversation_v2.xml index 240044d57..99493b6be 100644 --- a/app/src/main/res/layout/activity_conversation_v2.xml +++ b/app/src/main/res/layout/activity_conversation_v2.xml @@ -18,6 +18,13 @@ android:layout_height="wrap_content" android:layout_alignParentBottom="true" /> + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_visible_message.xml b/app/src/main/res/layout/view_visible_message.xml index 661c72d6f..c94fd2318 100644 --- a/app/src/main/res/layout/view_visible_message.xml +++ b/app/src/main/res/layout/view_visible_message.xml @@ -10,7 +10,7 @@ android:layout_width="match_parent" android:layout_height="40dp" android:textColor="@color/text" - android:textSize="@dimen/small_font_size" + android:textSize="@dimen/very_small_font_size" android:textStyle="bold" android:gravity="center" /> diff --git a/app/src/main/res/values-notnight-v21/colors.xml b/app/src/main/res/values-notnight-v21/colors.xml index 29ccfd231..02e903de9 100644 --- a/app/src/main/res/values-notnight-v21/colors.xml +++ b/app/src/main/res/values-notnight-v21/colors.xml @@ -26,6 +26,8 @@ #33000000 #FCFCFC #66000000 + #FCFCFC + #DFDFDF #ffffff #fcfcfc diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 57d076c8e..5ab72d4a4 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -33,6 +33,8 @@ #33FFFFFF #171717 #66FFFFFF + #171717 + #0C0C0C #5ff8b0