support reactions for TextMessages (in+out) and VoiceMessages (in+out)

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2022-04-07 12:41:35 +02:00
parent f17e892acd
commit 36b786616a
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
11 changed files with 136 additions and 67 deletions

View File

@ -74,6 +74,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
lateinit var message: ChatMessage
lateinit var voiceMessageInterface: VoiceMessageInterface
lateinit var reactionsInterface: ReactionsInterface
@SuppressLint("SetTextI18n")
override fun onBind(message: ChatMessage) {
@ -140,6 +141,12 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
}
}
})
Reaction().showReactions(message, binding.reactions, context!!)
binding.reactions.reactionsEmojiWrapper.setOnClickListener {
reactionsInterface.onClickReactions(message)
}
}
private fun updateDownloadState(message: ChatMessage) {
@ -306,6 +313,10 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
this.voiceMessageInterface = voiceMessageInterface
}
fun assignReactionInterface(reactionsInterface: ReactionsInterface) {
this.reactionsInterface = reactionsInterface
}
companion object {
private const val TAG = "VoiceInMessageView"
private const val SEEKBAR_START: Int = 0

View File

@ -36,9 +36,6 @@ import android.text.SpannableString
import android.text.TextUtils
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.ViewCompat
@ -57,7 +54,6 @@ import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.TextMatchers
import com.nextcloud.talk.utils.preferences.AppPreferences
import com.stfalcon.chatkit.messages.MessageHolders
import com.vanniktech.emoji.EmojiTextView
import java.util.HashMap
import javax.inject.Inject
@ -126,44 +122,10 @@ class MagicIncomingTextMessageViewHolder(itemView: View, payload: Any) : Message
itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
binding.reactionsEmojiWrapper.removeAllViews()
if (message.reactions != null && message.reactions.isNotEmpty()) {
Reaction().showReactions(message, binding.reactions, context!!)
var remainingEmojisToDisplay = MAX_EMOJIS_TO_DISPLAY
val showInfoAboutMoreEmojis = message.reactions.size > MAX_EMOJIS_TO_DISPLAY
for ((emoji, amount) in message.reactions) {
val reactionEmoji = EmojiTextView(context)
reactionEmoji.text = emoji
val reactionAmount = TextView(context)
reactionAmount.text = amount.toString()
val params = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
params.setMargins(
DisplayUtils.convertDpToPixel(EMOJI_START_MARGIN, context).toInt(),
0,
DisplayUtils.convertDpToPixel(EMOJI_END_MARGIN, context).toInt(),
0
)
reactionAmount.layoutParams = params
binding.reactionsEmojiWrapper.addView(reactionEmoji)
binding.reactionsEmojiWrapper.addView(reactionAmount)
remainingEmojisToDisplay--
if (remainingEmojisToDisplay == 0 && showInfoAboutMoreEmojis) {
val infoAboutMoreEmojis = TextView(context)
infoAboutMoreEmojis.text = "..."
binding.reactionsEmojiWrapper.addView(infoAboutMoreEmojis)
break
}
}
binding.reactionsEmojiWrapper.setOnClickListener {
reactionsInterface.onClickReactions(message)
}
binding.reactions.reactionsEmojiWrapper.setOnClickListener {
reactionsInterface.onClickReactions(message)
}
}
@ -306,14 +268,11 @@ class MagicIncomingTextMessageViewHolder(itemView: View, payload: Any) : Message
return messageStringInternal
}
fun assignAdapter(reactionsInterface: ReactionsInterface) {
fun assignReactionInterface(reactionsInterface: ReactionsInterface) {
this.reactionsInterface = reactionsInterface
}
companion object {
const val TEXT_SIZE_MULTIPLIER = 2.5
const val MAX_EMOJIS_TO_DISPLAY = 4
const val EMOJI_START_MARGIN: Float = 2F
const val EMOJI_END_MARGIN: Float = 8F
}
}

View File

@ -61,6 +61,8 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
@Inject
var context: Context? = null
lateinit var reactionsInterface: ReactionsInterface
override fun onBind(message: ChatMessage) {
super.onBind(message)
sharedApplication!!.componentApplication.inject(this)
@ -118,6 +120,12 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
binding.checkMark.setContentDescription(readStatusContentDescriptionString)
itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
Reaction().showReactions(message, binding.reactions, context!!)
binding.reactions.reactionsEmojiWrapper.setOnClickListener {
reactionsInterface.onClickReactions(message)
}
}
private fun processParentMessage(message: ChatMessage) {
@ -204,6 +212,10 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
return messageString1
}
fun assignReactionInterface(reactionsInterface: ReactionsInterface) {
this.reactionsInterface = reactionsInterface
}
companion object {
const val TEXT_SIZE_MULTIPLIER = 2.5
}

View File

@ -69,6 +69,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders
lateinit var handler: Handler
lateinit var voiceMessageInterface: VoiceMessageInterface
lateinit var reactionsInterface: ReactionsInterface
@SuppressLint("SetTextI18n")
override fun onBind(message: ChatMessage) {
@ -129,6 +130,12 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders
}
binding.checkMark.setContentDescription(readStatusContentDescriptionString)
Reaction().showReactions(message, binding.reactions, context!!)
binding.reactions.reactionsEmojiWrapper.setOnClickListener {
reactionsInterface.onClickReactions(message)
}
}
private fun handleResetVoiceMessageState(message: ChatMessage) {
@ -279,6 +286,10 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders
this.voiceMessageInterface = voiceMessageInterface
}
fun assignReactionInterface(reactionsInterface: ReactionsInterface) {
this.reactionsInterface = reactionsInterface
}
companion object {
private const val TAG = "VoiceOutMessageView"
private const val SEEKBAR_START: Int = 0

View File

@ -0,0 +1,58 @@
package com.nextcloud.talk.adapters.messages
import android.content.Context
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.TextView
import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding
import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.utils.DisplayUtils
import com.vanniktech.emoji.EmojiTextView
class Reaction {
fun showReactions(message: ChatMessage, binding: ReactionsInsideMessageBinding, context: Context) {
binding.reactionsEmojiWrapper.removeAllViews()
if (message.reactions != null && message.reactions.isNotEmpty()) {
var remainingEmojisToDisplay = MAX_EMOJIS_TO_DISPLAY
val showInfoAboutMoreEmojis = message.reactions.size > MAX_EMOJIS_TO_DISPLAY
for ((emoji, amount) in message.reactions) {
val reactionEmoji = EmojiTextView(context)
reactionEmoji.text = emoji
val reactionAmount = TextView(context)
reactionAmount.text = amount.toString()
val params = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
params.setMargins(
DisplayUtils.convertDpToPixel(EMOJI_START_MARGIN, context).toInt(),
0,
DisplayUtils.convertDpToPixel(EMOJI_END_MARGIN, context).toInt(),
0
)
reactionAmount.layoutParams = params
binding.reactionsEmojiWrapper.addView(reactionEmoji)
binding.reactionsEmojiWrapper.addView(reactionAmount)
remainingEmojisToDisplay--
if (remainingEmojisToDisplay == 0 && showInfoAboutMoreEmojis) {
val infoAboutMoreEmojis = TextView(context)
infoAboutMoreEmojis.text = EMOJI_MORE
binding.reactionsEmojiWrapper.addView(infoAboutMoreEmojis)
break
}
}
}
}
companion object {
const val MAX_EMOJIS_TO_DISPLAY = 4
const val EMOJI_START_MARGIN: Float = 2F
const val EMOJI_END_MARGIN: Float = 8F
const val EMOJI_MORE = "..."
}
}

View File

@ -49,14 +49,16 @@ public class TalkMessagesListAdapter<M extends IMessage> extends MessagesListAda
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
if (holder instanceof IncomingVoiceMessageViewHolder) {
if (holder instanceof MagicIncomingTextMessageViewHolder) {
((MagicIncomingTextMessageViewHolder) holder).assignReactionInterface(chatController);
} else if (holder instanceof MagicOutcomingTextMessageViewHolder) {
((MagicOutcomingTextMessageViewHolder) holder).assignReactionInterface(chatController);
} else if (holder instanceof IncomingVoiceMessageViewHolder) {
((IncomingVoiceMessageViewHolder) holder).assignAdapter(chatController);
((IncomingVoiceMessageViewHolder) holder).assignReactionInterface(chatController);
} else if (holder instanceof OutcomingVoiceMessageViewHolder) {
((OutcomingVoiceMessageViewHolder) holder).assignAdapter(chatController);
}
if (holder instanceof MagicIncomingTextMessageViewHolder) {
((MagicIncomingTextMessageViewHolder) holder).assignAdapter(chatController);
((OutcomingVoiceMessageViewHolder) holder).assignReactionInterface(chatController);
}
}
}

View File

@ -86,23 +86,9 @@
android:textIsSelectable="false"
app:layout_alignSelf="center" />
<LinearLayout
android:id="@+id/reactions_emoji_wrapper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_wrapBefore="true"
android:orientation="horizontal"
android:layout_marginTop="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="emojis">
</TextView>
</LinearLayout>
<include
android:id="@+id/reactions"
layout="@layout/reactions_inside_message" />
</com.google.android.flexbox.FlexboxLayout>
</RelativeLayout>

View File

@ -108,5 +108,9 @@
app:layout_alignSelf="center"
tools:text="12:38"/>
<include
android:id="@+id/reactions"
layout="@layout/reactions_inside_message" />
</com.google.android.flexbox.FlexboxLayout>
</RelativeLayout>

View File

@ -76,5 +76,9 @@
android:contentDescription="@null"
app:layout_alignSelf="center" />
<include
android:id="@+id/reactions"
layout="@layout/reactions_inside_message" />
</com.google.android.flexbox.FlexboxLayout>
</RelativeLayout>

View File

@ -104,5 +104,9 @@
app:layout_alignSelf="center"
android:contentDescription="@null" />
<include
android:id="@+id/reactions"
layout="@layout/reactions_inside_message" />
</com.google.android.flexbox.FlexboxLayout>
</RelativeLayout>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/reactions_emoji_wrapper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
app:layout_alignSelf="flex_start"
app:layout_flexGrow="1"
app:layout_wrapBefore="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="emojis">
</TextView>
</LinearLayout>