mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-20 20:19:42 +01:00
support reactions for TextMessages (in+out) and VoiceMessages (in+out)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
f17e892acd
commit
36b786616a
@ -74,6 +74,7 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
|
|||||||
lateinit var message: ChatMessage
|
lateinit var message: ChatMessage
|
||||||
|
|
||||||
lateinit var voiceMessageInterface: VoiceMessageInterface
|
lateinit var voiceMessageInterface: VoiceMessageInterface
|
||||||
|
lateinit var reactionsInterface: ReactionsInterface
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onBind(message: ChatMessage) {
|
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) {
|
private fun updateDownloadState(message: ChatMessage) {
|
||||||
@ -306,6 +313,10 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : Message
|
|||||||
this.voiceMessageInterface = voiceMessageInterface
|
this.voiceMessageInterface = voiceMessageInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun assignReactionInterface(reactionsInterface: ReactionsInterface) {
|
||||||
|
this.reactionsInterface = reactionsInterface
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "VoiceInMessageView"
|
private const val TAG = "VoiceInMessageView"
|
||||||
private const val SEEKBAR_START: Int = 0
|
private const val SEEKBAR_START: Int = 0
|
||||||
|
@ -36,9 +36,6 @@ import android.text.SpannableString
|
|||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
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.ContextCompat
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.view.ViewCompat
|
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.TextMatchers
|
||||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||||
import com.stfalcon.chatkit.messages.MessageHolders
|
import com.stfalcon.chatkit.messages.MessageHolders
|
||||||
import com.vanniktech.emoji.EmojiTextView
|
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -126,46 +122,12 @@ class MagicIncomingTextMessageViewHolder(itemView: View, payload: Any) : Message
|
|||||||
|
|
||||||
itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
|
itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
|
||||||
|
|
||||||
binding.reactionsEmojiWrapper.removeAllViews()
|
Reaction().showReactions(message, binding.reactions, context!!)
|
||||||
if (message.reactions != null && message.reactions.isNotEmpty()) {
|
|
||||||
|
|
||||||
var remainingEmojisToDisplay = MAX_EMOJIS_TO_DISPLAY
|
binding.reactions.reactionsEmojiWrapper.setOnClickListener {
|
||||||
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)
|
reactionsInterface.onClickReactions(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun processAuthor(message: ChatMessage) {
|
private fun processAuthor(message: ChatMessage) {
|
||||||
if (!TextUtils.isEmpty(message.actorDisplayName)) {
|
if (!TextUtils.isEmpty(message.actorDisplayName)) {
|
||||||
@ -306,14 +268,11 @@ class MagicIncomingTextMessageViewHolder(itemView: View, payload: Any) : Message
|
|||||||
return messageStringInternal
|
return messageStringInternal
|
||||||
}
|
}
|
||||||
|
|
||||||
fun assignAdapter(reactionsInterface: ReactionsInterface) {
|
fun assignReactionInterface(reactionsInterface: ReactionsInterface) {
|
||||||
this.reactionsInterface = reactionsInterface
|
this.reactionsInterface = reactionsInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TEXT_SIZE_MULTIPLIER = 2.5
|
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,8 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
|
|||||||
@Inject
|
@Inject
|
||||||
var context: Context? = null
|
var context: Context? = null
|
||||||
|
|
||||||
|
lateinit var reactionsInterface: ReactionsInterface
|
||||||
|
|
||||||
override fun onBind(message: ChatMessage) {
|
override fun onBind(message: ChatMessage) {
|
||||||
super.onBind(message)
|
super.onBind(message)
|
||||||
sharedApplication!!.componentApplication.inject(this)
|
sharedApplication!!.componentApplication.inject(this)
|
||||||
@ -118,6 +120,12 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
|
|||||||
binding.checkMark.setContentDescription(readStatusContentDescriptionString)
|
binding.checkMark.setContentDescription(readStatusContentDescriptionString)
|
||||||
|
|
||||||
itemView.setTag(MessageSwipeCallback.REPLYABLE_VIEW_TAG, message.isReplyable)
|
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) {
|
private fun processParentMessage(message: ChatMessage) {
|
||||||
@ -204,6 +212,10 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
|
|||||||
return messageString1
|
return messageString1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun assignReactionInterface(reactionsInterface: ReactionsInterface) {
|
||||||
|
this.reactionsInterface = reactionsInterface
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TEXT_SIZE_MULTIPLIER = 2.5
|
const val TEXT_SIZE_MULTIPLIER = 2.5
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders
|
|||||||
lateinit var handler: Handler
|
lateinit var handler: Handler
|
||||||
|
|
||||||
lateinit var voiceMessageInterface: VoiceMessageInterface
|
lateinit var voiceMessageInterface: VoiceMessageInterface
|
||||||
|
lateinit var reactionsInterface: ReactionsInterface
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onBind(message: ChatMessage) {
|
override fun onBind(message: ChatMessage) {
|
||||||
@ -129,6 +130,12 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.checkMark.setContentDescription(readStatusContentDescriptionString)
|
binding.checkMark.setContentDescription(readStatusContentDescriptionString)
|
||||||
|
|
||||||
|
Reaction().showReactions(message, binding.reactions, context!!)
|
||||||
|
|
||||||
|
binding.reactions.reactionsEmojiWrapper.setOnClickListener {
|
||||||
|
reactionsInterface.onClickReactions(message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleResetVoiceMessageState(message: ChatMessage) {
|
private fun handleResetVoiceMessageState(message: ChatMessage) {
|
||||||
@ -279,6 +286,10 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : MessageHolders
|
|||||||
this.voiceMessageInterface = voiceMessageInterface
|
this.voiceMessageInterface = voiceMessageInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun assignReactionInterface(reactionsInterface: ReactionsInterface) {
|
||||||
|
this.reactionsInterface = reactionsInterface
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "VoiceOutMessageView"
|
private const val TAG = "VoiceOutMessageView"
|
||||||
private const val SEEKBAR_START: Int = 0
|
private const val SEEKBAR_START: Int = 0
|
||||||
|
@ -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 = "..."
|
||||||
|
}
|
||||||
|
}
|
@ -49,14 +49,16 @@ public class TalkMessagesListAdapter<M extends IMessage> extends MessagesListAda
|
|||||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||||
super.onBindViewHolder(holder, 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).assignAdapter(chatController);
|
||||||
|
((IncomingVoiceMessageViewHolder) holder).assignReactionInterface(chatController);
|
||||||
} else if (holder instanceof OutcomingVoiceMessageViewHolder) {
|
} else if (holder instanceof OutcomingVoiceMessageViewHolder) {
|
||||||
((OutcomingVoiceMessageViewHolder) holder).assignAdapter(chatController);
|
((OutcomingVoiceMessageViewHolder) holder).assignAdapter(chatController);
|
||||||
}
|
((OutcomingVoiceMessageViewHolder) holder).assignReactionInterface(chatController);
|
||||||
|
|
||||||
if (holder instanceof MagicIncomingTextMessageViewHolder) {
|
|
||||||
((MagicIncomingTextMessageViewHolder) holder).assignAdapter(chatController);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,23 +86,9 @@
|
|||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
app:layout_alignSelf="center" />
|
app:layout_alignSelf="center" />
|
||||||
|
|
||||||
|
<include
|
||||||
<LinearLayout
|
android:id="@+id/reactions"
|
||||||
android:id="@+id/reactions_emoji_wrapper"
|
layout="@layout/reactions_inside_message" />
|
||||||
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>
|
|
||||||
|
|
||||||
</com.google.android.flexbox.FlexboxLayout>
|
</com.google.android.flexbox.FlexboxLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
@ -108,5 +108,9 @@
|
|||||||
app:layout_alignSelf="center"
|
app:layout_alignSelf="center"
|
||||||
tools:text="12:38"/>
|
tools:text="12:38"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/reactions"
|
||||||
|
layout="@layout/reactions_inside_message" />
|
||||||
|
|
||||||
</com.google.android.flexbox.FlexboxLayout>
|
</com.google.android.flexbox.FlexboxLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
@ -76,5 +76,9 @@
|
|||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
app:layout_alignSelf="center" />
|
app:layout_alignSelf="center" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/reactions"
|
||||||
|
layout="@layout/reactions_inside_message" />
|
||||||
|
|
||||||
</com.google.android.flexbox.FlexboxLayout>
|
</com.google.android.flexbox.FlexboxLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
@ -104,5 +104,9 @@
|
|||||||
app:layout_alignSelf="center"
|
app:layout_alignSelf="center"
|
||||||
android:contentDescription="@null" />
|
android:contentDescription="@null" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/reactions"
|
||||||
|
layout="@layout/reactions_inside_message" />
|
||||||
|
|
||||||
</com.google.android.flexbox.FlexboxLayout>
|
</com.google.android.flexbox.FlexboxLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
18
app/src/main/res/layout/reactions_inside_message.xml
Normal file
18
app/src/main/res/layout/reactions_inside_message.xml
Normal 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>
|
Loading…
Reference in New Issue
Block a user