mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-25 01:07:47 +00:00
Add back mentions business logic
This commit is contained in:
parent
40317d9834
commit
6140be6e56
@ -7,6 +7,7 @@ import android.database.Cursor
|
|||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
@ -27,6 +28,7 @@ import kotlinx.android.synthetic.main.view_input_bar_recording.view.*
|
|||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import nl.komponents.kovenant.ui.successUi
|
import nl.komponents.kovenant.ui.successUi
|
||||||
import org.session.libsession.messaging.contacts.Contact
|
import org.session.libsession.messaging.contacts.Contact
|
||||||
|
import org.session.libsession.messaging.mentions.Mention
|
||||||
import org.session.libsession.messaging.mentions.MentionsManager
|
import org.session.libsession.messaging.mentions.MentionsManager
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
|
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
@ -65,10 +67,16 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
private var linkPreviewViewModel: LinkPreviewViewModel? = null
|
private var linkPreviewViewModel: LinkPreviewViewModel? = null
|
||||||
private var threadID: Long = -1
|
private var threadID: Long = -1
|
||||||
private var actionMode: ActionMode? = null
|
private var actionMode: ActionMode? = null
|
||||||
|
private var unreadCount = 0
|
||||||
|
// Attachments
|
||||||
private var isLockViewExpanded = false
|
private var isLockViewExpanded = false
|
||||||
private var isShowingAttachmentOptions = false
|
private var isShowingAttachmentOptions = false
|
||||||
|
// Mentions
|
||||||
|
private val mentions = mutableListOf<Mention>()
|
||||||
private var mentionCandidatesView: MentionCandidatesView? = null
|
private var mentionCandidatesView: MentionCandidatesView? = null
|
||||||
private var unreadCount = 0
|
private var previousText: CharSequence = ""
|
||||||
|
private var currentMentionStartIndex = -1
|
||||||
|
private var isShowingMentionCandidatesView = false
|
||||||
|
|
||||||
private val layoutManager: LinearLayoutManager
|
private val layoutManager: LinearLayoutManager
|
||||||
get() { return conversationRecyclerView.layoutManager as LinearLayoutManager }
|
get() { return conversationRecyclerView.layoutManager as LinearLayoutManager }
|
||||||
@ -294,9 +302,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
// 36 DP is the exact height of the typing indicator view. It's also exactly 18 * 2, and 18 is the large message
|
// 36 DP is the exact height of the typing indicator view. It's also exactly 18 * 2, and 18 is the large message
|
||||||
// corner radius. This makes 36 DP look "correct" in the context of other messages on the screen.
|
// corner radius. This makes 36 DP look "correct" in the context of other messages on the screen.
|
||||||
val typingIndicatorHeight = if (typingIndicatorViewContainer.isVisible) toPx(36, resources) else 0
|
val typingIndicatorHeight = if (typingIndicatorViewContainer.isVisible) toPx(36, resources) else 0
|
||||||
|
// We * don't * want to move the recycler view up when showing the mention candidates view
|
||||||
|
val additionalContentContainerHeight = if (isShowingMentionCandidatesView) 0 else additionalContentContainer.height
|
||||||
// Recycler view
|
// Recycler view
|
||||||
val recyclerViewLayoutParams = conversationRecyclerView.layoutParams as RelativeLayout.LayoutParams
|
val recyclerViewLayoutParams = conversationRecyclerView.layoutParams as RelativeLayout.LayoutParams
|
||||||
recyclerViewLayoutParams.bottomMargin = newValue + additionalContentContainer.height + typingIndicatorHeight
|
recyclerViewLayoutParams.bottomMargin = newValue + additionalContentContainerHeight + typingIndicatorHeight
|
||||||
conversationRecyclerView.layoutParams = recyclerViewLayoutParams
|
conversationRecyclerView.layoutParams = recyclerViewLayoutParams
|
||||||
// Additional content container
|
// Additional content container
|
||||||
val additionalContentContainerLayoutParams = additionalContentContainer.layoutParams as RelativeLayout.LayoutParams
|
val additionalContentContainerLayoutParams = additionalContentContainer.layoutParams as RelativeLayout.LayoutParams
|
||||||
@ -317,32 +327,61 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
|
|
||||||
override fun inputBarEditTextContentChanged(newContent: CharSequence) {
|
override fun inputBarEditTextContentChanged(newContent: CharSequence) {
|
||||||
linkPreviewViewModel?.onTextChanged(this, inputBar.text, 0, 0)
|
linkPreviewViewModel?.onTextChanged(this, inputBar.text, 0, 0)
|
||||||
// TODO: Implement the full mention show/hide logic
|
showOrHideMentionCandidatesIfNeeded(newContent)
|
||||||
if (newContent.contains("@")) {
|
|
||||||
showMentionCandidates()
|
|
||||||
} else {
|
|
||||||
hideMentionCandidates()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showMentionCandidates() {
|
private fun showOrHideMentionCandidatesIfNeeded(text: CharSequence) {
|
||||||
|
val isBackspace = (text.length < previousText.length)
|
||||||
|
if (isBackspace) {
|
||||||
|
currentMentionStartIndex = -1
|
||||||
|
hideMentionCandidates()
|
||||||
|
val mentionsToRemove = mentions.filter { !text.contains(it.displayName) }
|
||||||
|
mentions.removeAll(mentionsToRemove)
|
||||||
|
}
|
||||||
|
if (text.isNotEmpty()) {
|
||||||
|
if (currentMentionStartIndex > text.length) { resetMentions() } // Should never occur
|
||||||
|
val lastCharIndex = text.lastIndex
|
||||||
|
val lastChar = text[lastCharIndex]
|
||||||
|
val secondToLastChar = if (lastCharIndex > 0) text[lastCharIndex - 1] else ' '
|
||||||
|
if (lastChar == '@' && Character.isWhitespace(secondToLastChar)) {
|
||||||
|
currentMentionStartIndex = lastCharIndex
|
||||||
|
showOrUpdateMentionCandidatesIfNeeded()
|
||||||
|
} else if (Character.isWhitespace(lastChar)) {
|
||||||
|
currentMentionStartIndex = -1
|
||||||
|
hideMentionCandidates()
|
||||||
|
} else if (currentMentionStartIndex != -1) {
|
||||||
|
val query = text.substring(currentMentionStartIndex + 1) // + 1 to get rid of the "@"
|
||||||
|
showOrUpdateMentionCandidatesIfNeeded(query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previousText = text
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showOrUpdateMentionCandidatesIfNeeded(query: String = "") {
|
||||||
|
if (!isShowingMentionCandidatesView) {
|
||||||
additionalContentContainer.removeAllViews()
|
additionalContentContainer.removeAllViews()
|
||||||
val mentionCandidatesView = MentionCandidatesView(this)
|
val view = MentionCandidatesView(this)
|
||||||
mentionCandidatesView.glide = glide
|
view.glide = glide
|
||||||
additionalContentContainer.addView(mentionCandidatesView)
|
additionalContentContainer.addView(view)
|
||||||
val mentionCandidates = MentionsManager.getMentionCandidates("", threadID, thread.isOpenGroupRecipient)
|
val candidates = MentionsManager.getMentionCandidates(query, threadID, thread.isOpenGroupRecipient)
|
||||||
this.mentionCandidatesView = mentionCandidatesView
|
this.mentionCandidatesView = view
|
||||||
mentionCandidatesView.show(mentionCandidates, threadID)
|
view.show(candidates, threadID)
|
||||||
mentionCandidatesView.alpha = 0.0f
|
view.alpha = 0.0f
|
||||||
val animation = ValueAnimator.ofObject(FloatEvaluator(), mentionCandidatesView.alpha, 1.0f)
|
val animation = ValueAnimator.ofObject(FloatEvaluator(), view.alpha, 1.0f)
|
||||||
animation.duration = 250L
|
animation.duration = 250L
|
||||||
animation.addUpdateListener { animator ->
|
animation.addUpdateListener { animator ->
|
||||||
mentionCandidatesView.alpha = animator.animatedValue as Float
|
view.alpha = animator.animatedValue as Float
|
||||||
}
|
}
|
||||||
animation.start()
|
animation.start()
|
||||||
|
} else {
|
||||||
|
val candidates = MentionsManager.getMentionCandidates(query, threadID, thread.isOpenGroupRecipient)
|
||||||
|
this.mentionCandidatesView!!.setMentionCandidates(candidates)
|
||||||
|
}
|
||||||
|
isShowingMentionCandidatesView = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideMentionCandidates() {
|
private fun hideMentionCandidates() {
|
||||||
|
if (isShowingMentionCandidatesView) {
|
||||||
val mentionCandidatesView = mentionCandidatesView ?: return
|
val mentionCandidatesView = mentionCandidatesView ?: return
|
||||||
val animation = ValueAnimator.ofObject(FloatEvaluator(), mentionCandidatesView.alpha, 0.0f)
|
val animation = ValueAnimator.ofObject(FloatEvaluator(), mentionCandidatesView.alpha, 0.0f)
|
||||||
animation.duration = 250L
|
animation.duration = 250L
|
||||||
@ -352,6 +391,14 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
}
|
}
|
||||||
animation.start()
|
animation.start()
|
||||||
}
|
}
|
||||||
|
isShowingMentionCandidatesView = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetMentions() {
|
||||||
|
previousText = ""
|
||||||
|
currentMentionStartIndex = -1
|
||||||
|
mentions.clear()
|
||||||
|
}
|
||||||
|
|
||||||
override fun toggleAttachmentOptions() {
|
override fun toggleAttachmentOptions() {
|
||||||
val targetAlpha = if (isShowingAttachmentOptions) 0.0f else 1.0f
|
val targetAlpha = if (isShowingAttachmentOptions) 0.0f else 1.0f
|
||||||
@ -569,9 +616,27 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
private fun unblock() {
|
private fun unblock() {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun send() {
|
||||||
|
|
||||||
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region General
|
// region General
|
||||||
|
private fun getMessageBody(): CharSequence {
|
||||||
|
var result = inputBar.inputBarEditText.text?.trim() ?: ""
|
||||||
|
for (mention in mentions) {
|
||||||
|
try {
|
||||||
|
val startIndex = result.indexOf("@" + mention.displayName)
|
||||||
|
val endIndex = startIndex + mention.displayName.count() + 1 // + 1 to include the "@"
|
||||||
|
result = result.substring(0, startIndex) + "@" + mention.publicKey + result.substring(endIndex)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
Log.d("Loki", "Failed to process mention due to error: $exception")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
private fun saveDraft() {
|
private fun saveDraft() {
|
||||||
val text = inputBar.text.trim()
|
val text = inputBar.text.trim()
|
||||||
if (text.isEmpty()) { return }
|
if (text.isEmpty()) { return }
|
||||||
|
@ -61,6 +61,7 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
|
|||||||
microphoneOrSendButtonContainer.addView(sendButton)
|
microphoneOrSendButtonContainer.addView(sendButton)
|
||||||
sendButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
|
sendButton.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
|
||||||
sendButton.isVisible = false
|
sendButton.isVisible = false
|
||||||
|
sendButton.onUp = { delegate?.send() }
|
||||||
// Edit text
|
// Edit text
|
||||||
inputBarEditText.imeOptions = inputBarEditText.imeOptions or 16777216 // Always use incognito keyboard
|
inputBarEditText.imeOptions = inputBarEditText.imeOptions or 16777216 // Always use incognito keyboard
|
||||||
inputBarEditText.delegate = this
|
inputBarEditText.delegate = this
|
||||||
@ -162,4 +163,5 @@ interface InputBarDelegate {
|
|||||||
fun onMicrophoneButtonMove(event: MotionEvent)
|
fun onMicrophoneButtonMove(event: MotionEvent)
|
||||||
fun onMicrophoneButtonCancel(event: MotionEvent)
|
fun onMicrophoneButtonCancel(event: MotionEvent)
|
||||||
fun onMicrophoneButtonUp(event: MotionEvent)
|
fun onMicrophoneButtonUp(event: MotionEvent)
|
||||||
|
fun send()
|
||||||
}
|
}
|
@ -65,6 +65,10 @@ class MentionCandidatesView(context: Context, attrs: AttributeSet?, defStyleAttr
|
|||||||
openGroupServer = openGroup.server
|
openGroupServer = openGroup.server
|
||||||
openGroupRoom = openGroup.room
|
openGroupRoom = openGroup.room
|
||||||
}
|
}
|
||||||
|
setMentionCandidates(candidates)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMentionCandidates(candidates: List<Mention>) {
|
||||||
this.candidates = candidates
|
this.candidates = candidates
|
||||||
val layoutParams = this.layoutParams as ViewGroup.LayoutParams
|
val layoutParams = this.layoutParams as ViewGroup.LayoutParams
|
||||||
layoutParams.height = toPx(Math.min(candidates.count(), 4) * 44, resources)
|
layoutParams.height = toPx(Math.min(candidates.count(), 4) * 44, resources)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user