Add mention candidates view

This commit is contained in:
Niels Andriesse 2021-06-18 11:00:52 +10:00
parent 7c3b1b22d7
commit efc752e3a1
12 changed files with 224 additions and 9 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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
}
}
}

View File

@ -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<Mention>()
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<Mention>()
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<Mention>, 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
}
}

View File

@ -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

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/cell_selected">
android:color="@color/mention_candidates_view_background_ripple">
<item>
<color android:color="@color/compose_view_background" />
<color android:color="@color/mention_candidates_view_background" />
</item>
</ripple>

View File

@ -18,6 +18,13 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
<FrameLayout
android:id="@+id/inputBarAdditionalContentContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/input_bar_height" />
<LinearLayout
android:id="@+id/attachmentOptionsContainer"
android:layout_width="wrap_content"

View File

@ -30,7 +30,7 @@
</RelativeLayout>
<TextView
android:id="@+id/btnGroupNameDisplay"
android:id="@+id/mentionCandidateNameTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/medium_spacing"

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.conversation.v2.input_bar.mentions.MentionCandidateView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="@drawable/mention_candidate_view_background">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="@dimen/medium_spacing"
android:paddingEnd="@dimen/medium_spacing"
android:gravity="center_vertical"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="26dp"
android:layout_height="32dp">
<org.thoughtcrime.securesms.loki.views.ProfilePictureView
android:id="@+id/profilePictureView"
android:layout_width="@dimen/very_small_profile_picture_size"
android:layout_height="@dimen/very_small_profile_picture_size"
android:layout_marginTop="3dp" />
<ImageView
android:id="@+id/moderatorIconImageView"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/ic_crown"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true" />
</RelativeLayout>
<TextView
android:id="@+id/mentionCandidateNameTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/medium_spacing"
android:textSize="@dimen/small_font_size"
android:textColor="@color/text"
android:maxLines="1"
android:ellipsize="end" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_alignParentTop="true"
android:background="@color/separator" />
</org.thoughtcrime.securesms.conversation.v2.input_bar.mentions.MentionCandidateView>

View File

@ -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" />

View File

@ -26,6 +26,8 @@
<color name="input_bar_button_background_opaque_border">#33000000</color>
<color name="input_bar_lock_view_background">#FCFCFC</color>
<color name="input_bar_lock_view_border">#66000000</color>
<color name="mention_candidates_view_background">#FCFCFC</color>
<color name="mention_candidates_view_background_ripple">#DFDFDF</color>
<color name="default_background_start">#ffffff</color>
<color name="default_background_end">#fcfcfc</color>

View File

@ -33,6 +33,8 @@
<color name="input_bar_button_background_opaque_border">#33FFFFFF</color>
<color name="input_bar_lock_view_background">#171717</color>
<color name="input_bar_lock_view_border">#66FFFFFF</color>
<color name="mention_candidates_view_background">#171717</color>
<color name="mention_candidates_view_background_ripple">#0C0C0C</color>
<array name="profile_picture_placeholder_colors">
<item>#5ff8b0</item>