mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-18 02:05:01 +01:00
Merge pull request #4327 from nextcloud/deck_card_is_shown_as_object
show deck card in messages
This commit is contained in:
commit
5bee52d182
@ -410,6 +410,15 @@ class ConversationItem(
|
|||||||
chatMessage?.getNullsafeActorDisplayName()
|
chatMessage?.getNullsafeActorDisplayName()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else if (MessageType.DECK_CARD == chatMessage?.getCalculateMessageType()) {
|
||||||
|
return if (chatMessage?.actorId == chatMessage?.activeUser!!.userId) {
|
||||||
|
sharedApplication!!.getString(R.string.nc_sent_deck_card_you)
|
||||||
|
} else {
|
||||||
|
String.format(
|
||||||
|
sharedApplication!!.resources.getString(R.string.nc_sent_deck_card),
|
||||||
|
chatMessage?.getNullsafeActorDisplayName()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
|
@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk - Android Client
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.adapters.messages
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import autodagger.AutoInjector
|
||||||
|
import coil.load
|
||||||
|
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
||||||
|
import com.nextcloud.talk.R
|
||||||
|
import com.nextcloud.talk.api.NcApi
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||||
|
import com.nextcloud.talk.chat.ChatActivity
|
||||||
|
import com.nextcloud.talk.chat.data.model.ChatMessage
|
||||||
|
import com.nextcloud.talk.databinding.ItemCustomIncomingDeckCardMessageBinding
|
||||||
|
import com.nextcloud.talk.extensions.loadBotsAvatar
|
||||||
|
import com.nextcloud.talk.extensions.loadChangelogBotAvatar
|
||||||
|
import com.nextcloud.talk.extensions.loadFederatedUserAvatar
|
||||||
|
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||||
|
import com.nextcloud.talk.utils.ApiUtils
|
||||||
|
import com.nextcloud.talk.utils.DateUtils
|
||||||
|
import com.nextcloud.talk.utils.message.MessageUtils
|
||||||
|
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||||
|
import com.stfalcon.chatkit.messages.MessageHolders
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication::class)
|
||||||
|
class IncomingDeckCardViewHolder(incomingView: View, payload: Any) : MessageHolders
|
||||||
|
.IncomingTextMessageViewHolder<ChatMessage>(incomingView, payload) {
|
||||||
|
|
||||||
|
private val binding: ItemCustomIncomingDeckCardMessageBinding =
|
||||||
|
ItemCustomIncomingDeckCardMessageBinding.bind(itemView)
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var context: Context
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var appPreferences: AppPreferences
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var viewThemeUtils: ViewThemeUtils
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var messageUtils: MessageUtils
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var dateUtils: DateUtils
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var ncApi: NcApi
|
||||||
|
|
||||||
|
lateinit var message: ChatMessage
|
||||||
|
|
||||||
|
lateinit var commonMessageInterface: CommonMessageInterface
|
||||||
|
|
||||||
|
var stackName: String? = null
|
||||||
|
var cardName: String? = null
|
||||||
|
var boardName: String? = null
|
||||||
|
var cardLink: String? = null
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun onBind(message: ChatMessage) {
|
||||||
|
super.onBind(message)
|
||||||
|
this.message = message
|
||||||
|
sharedApplication!!.componentApplication.inject(this)
|
||||||
|
binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
|
||||||
|
|
||||||
|
setAvatarAndAuthorOnMessageItem(message)
|
||||||
|
showDeckCard(message)
|
||||||
|
|
||||||
|
colorizeMessageBubble(message)
|
||||||
|
|
||||||
|
binding.cardView.findViewById<ImageView>(R.id.deckCardImage)?.let {
|
||||||
|
viewThemeUtils.platform.colorImageView(it, ColorRole.SECONDARY)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemView.isSelected = false
|
||||||
|
|
||||||
|
// parent message handling
|
||||||
|
setParentMessageDataOnMessageItem(message)
|
||||||
|
|
||||||
|
binding.cardView.setOnLongClickListener { l: View? ->
|
||||||
|
commonMessageInterface.onOpenMessageActionsDialog(message)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.cardView.setOnClickListener {
|
||||||
|
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(cardLink))
|
||||||
|
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
context.startActivity(browserIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemView.setTag(R.string.replyable_message_view_tag, message.replyable)
|
||||||
|
|
||||||
|
Reaction().showReactions(
|
||||||
|
message,
|
||||||
|
::clickOnReaction,
|
||||||
|
::longClickOnReaction,
|
||||||
|
binding.reactions,
|
||||||
|
binding.messageTime.context,
|
||||||
|
false,
|
||||||
|
viewThemeUtils
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showDeckCard(message: ChatMessage) {
|
||||||
|
if (message.messageParameters != null && message.messageParameters!!.size > 0) {
|
||||||
|
for (key in message.messageParameters!!.keys) {
|
||||||
|
val individualHashMap: Map<String?, String?> = message.messageParameters!![key]!!
|
||||||
|
if (individualHashMap["type"] == "deck-card") {
|
||||||
|
cardName = individualHashMap["name"]
|
||||||
|
stackName = individualHashMap["stackname"]
|
||||||
|
boardName = individualHashMap["boardname"]
|
||||||
|
cardLink = individualHashMap["link"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardName?.isNotEmpty() == true) {
|
||||||
|
val cardDescription = String.format(
|
||||||
|
context.resources.getString(R.string.deck_card_description),
|
||||||
|
stackName,
|
||||||
|
boardName
|
||||||
|
)
|
||||||
|
binding.cardName.visibility = View.VISIBLE
|
||||||
|
binding.cardDescription.visibility = View.VISIBLE
|
||||||
|
binding.cardName.text = cardName
|
||||||
|
binding.cardDescription.text = cardDescription
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun longClickOnReaction(chatMessage: ChatMessage) {
|
||||||
|
commonMessageInterface.onLongClickReactions(chatMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clickOnReaction(chatMessage: ChatMessage, emoji: String) {
|
||||||
|
commonMessageInterface.onClickReaction(chatMessage, emoji)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAvatarAndAuthorOnMessageItem(message: ChatMessage) {
|
||||||
|
val author: String = message.actorDisplayName!!
|
||||||
|
if (!TextUtils.isEmpty(author)) {
|
||||||
|
binding.messageAuthor.visibility = View.VISIBLE
|
||||||
|
binding.messageAuthor.text = author
|
||||||
|
binding.messageUserAvatar.setOnClickListener {
|
||||||
|
(payload as? MessagePayload)?.profileBottomSheet?.showFor(message, itemView.context)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.messageAuthor.setText(R.string.nc_nick_guest)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.isGrouped && !message.isOneToOneConversation && !message.isFormerOneToOneConversation) {
|
||||||
|
setAvatarOnMessage(message)
|
||||||
|
} else {
|
||||||
|
if (message.isOneToOneConversation || message.isFormerOneToOneConversation) {
|
||||||
|
binding.messageUserAvatar.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
binding.messageUserAvatar.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
binding.messageAuthor.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAvatarOnMessage(message: ChatMessage) {
|
||||||
|
binding.messageUserAvatar.visibility = View.VISIBLE
|
||||||
|
if (message.actorType == "guests") {
|
||||||
|
// do nothing, avatar is set
|
||||||
|
} else if (message.actorType == "bots" && message.actorId == "changelog") {
|
||||||
|
binding.messageUserAvatar.loadChangelogBotAvatar()
|
||||||
|
} else if (message.actorType == "bots") {
|
||||||
|
binding.messageUserAvatar.loadBotsAvatar()
|
||||||
|
} else if (message.actorType == "federated_users") {
|
||||||
|
binding.messageUserAvatar.loadFederatedUserAvatar(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun colorizeMessageBubble(message: ChatMessage) {
|
||||||
|
viewThemeUtils.talk.themeIncomingMessageBubble(bubble, message.isGrouped, message.isDeleted)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setParentMessageDataOnMessageItem(message: ChatMessage) {
|
||||||
|
if (message.parentMessageId != null && !message.isDeleted) {
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
try {
|
||||||
|
val chatActivity = commonMessageInterface as ChatActivity
|
||||||
|
val urlForChatting = ApiUtils.getUrlForChat(
|
||||||
|
chatActivity.chatApiVersion,
|
||||||
|
chatActivity.conversationUser?.baseUrl,
|
||||||
|
chatActivity.roomToken
|
||||||
|
)
|
||||||
|
|
||||||
|
val parentChatMessage = withContext(Dispatchers.IO) {
|
||||||
|
chatActivity.chatViewModel.getMessageById(
|
||||||
|
urlForChatting,
|
||||||
|
chatActivity.currentConversation!!,
|
||||||
|
message.parentMessageId!!
|
||||||
|
).first()
|
||||||
|
}
|
||||||
|
parentChatMessage.activeUser = message.activeUser
|
||||||
|
parentChatMessage.imageUrl?.let {
|
||||||
|
binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
|
||||||
|
binding.messageQuote.quotedMessageImage.load(it) {
|
||||||
|
addHeader(
|
||||||
|
"Authorization",
|
||||||
|
ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!!
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
binding.messageQuote.quotedMessageImage.visibility = View.GONE
|
||||||
|
}
|
||||||
|
binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
|
||||||
|
?: context.getText(R.string.nc_nick_guest)
|
||||||
|
binding.messageQuote.quotedMessage.text = messageUtils
|
||||||
|
.enrichChatReplyMessageText(
|
||||||
|
binding.messageQuote.quotedMessage.context,
|
||||||
|
parentChatMessage,
|
||||||
|
true,
|
||||||
|
viewThemeUtils
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.messageQuote.quotedMessageAuthor
|
||||||
|
.setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast))
|
||||||
|
|
||||||
|
if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) {
|
||||||
|
viewThemeUtils.platform.colorViewBackground(
|
||||||
|
binding.messageQuote.quoteColoredView,
|
||||||
|
ColorRole.PRIMARY
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.d(TAG, "Error when processing parent message in view holder", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.messageQuote.quotedChatMessageView.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignCommonMessageInterface(commonMessageInterface: CommonMessageInterface) {
|
||||||
|
this.commonMessageInterface = commonMessageInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = IncomingDeckCardViewHolder::class.java.simpleName
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk - Android Client
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sowjanya Kota<sowjanya.kch@gmail.com>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.adapters.messages
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import autodagger.AutoInjector
|
||||||
|
import coil.load
|
||||||
|
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
||||||
|
import com.nextcloud.talk.R
|
||||||
|
import com.nextcloud.talk.api.NcApi
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||||
|
import com.nextcloud.talk.chat.ChatActivity
|
||||||
|
import com.nextcloud.talk.chat.data.model.ChatMessage
|
||||||
|
import com.nextcloud.talk.databinding.ItemCustomOutcomingDeckCardMessageBinding
|
||||||
|
import com.nextcloud.talk.models.json.chat.ReadStatus
|
||||||
|
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||||
|
import com.nextcloud.talk.utils.ApiUtils
|
||||||
|
import com.nextcloud.talk.utils.DateUtils
|
||||||
|
import com.nextcloud.talk.utils.message.MessageUtils
|
||||||
|
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||||
|
import com.stfalcon.chatkit.messages.MessageHolders
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication::class)
|
||||||
|
class OutcomingDeckCardViewHolder(
|
||||||
|
outcomingView: View
|
||||||
|
) : MessageHolders.OutcomingTextMessageViewHolder<ChatMessage>(outcomingView) {
|
||||||
|
|
||||||
|
private val binding: ItemCustomOutcomingDeckCardMessageBinding = ItemCustomOutcomingDeckCardMessageBinding.bind(
|
||||||
|
itemView
|
||||||
|
)
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var context: Context
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var viewThemeUtils: ViewThemeUtils
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var messageUtils: MessageUtils
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var appPreferences: AppPreferences
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var ncApi: NcApi
|
||||||
|
|
||||||
|
lateinit var message: ChatMessage
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var dateUtils: DateUtils
|
||||||
|
|
||||||
|
lateinit var commonMessageInterface: CommonMessageInterface
|
||||||
|
|
||||||
|
var stackName: String? = null
|
||||||
|
var cardName: String? = null
|
||||||
|
var boardName: String? = null
|
||||||
|
var cardLink: String? = null
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun onBind(message: ChatMessage) {
|
||||||
|
super.onBind(message)
|
||||||
|
this.message = message
|
||||||
|
sharedApplication!!.componentApplication.inject(this)
|
||||||
|
viewThemeUtils.platform.colorTextView(binding.messageTime, ColorRole.ON_SURFACE_VARIANT)
|
||||||
|
binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
|
||||||
|
|
||||||
|
colorizeMessageBubble(message)
|
||||||
|
|
||||||
|
binding.cardView.findViewById<ImageView>(R.id.deckCardImage)?.let {
|
||||||
|
viewThemeUtils.platform.colorImageView(it, ColorRole.SECONDARY)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemView.isSelected = false
|
||||||
|
|
||||||
|
showDeckCard(message)
|
||||||
|
|
||||||
|
// parent message handling
|
||||||
|
setParentMessageDataOnMessageItem(message)
|
||||||
|
|
||||||
|
val readStatusDrawableInt = when (message.readStatus) {
|
||||||
|
ReadStatus.READ -> R.drawable.ic_check_all
|
||||||
|
ReadStatus.SENT -> R.drawable.ic_check
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
val readStatusContentDescriptionString = when (message.readStatus) {
|
||||||
|
ReadStatus.READ -> context.resources?.getString(R.string.nc_message_read)
|
||||||
|
ReadStatus.SENT -> context.resources?.getString(R.string.nc_message_sent)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
readStatusDrawableInt?.let { drawableInt ->
|
||||||
|
AppCompatResources.getDrawable(context, drawableInt)?.let {
|
||||||
|
binding.checkMark.setImageDrawable(it)
|
||||||
|
viewThemeUtils.talk.themeMessageCheckMark(binding.checkMark)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.checkMark.contentDescription = readStatusContentDescriptionString
|
||||||
|
|
||||||
|
binding.cardView.setOnClickListener {
|
||||||
|
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(cardLink))
|
||||||
|
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
context.startActivity(browserIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemView.setTag(R.string.replyable_message_view_tag, message.replyable)
|
||||||
|
|
||||||
|
Reaction().showReactions(
|
||||||
|
message,
|
||||||
|
::clickOnReaction,
|
||||||
|
::longClickOnReaction,
|
||||||
|
binding.reactions,
|
||||||
|
binding.messageTime.context,
|
||||||
|
true,
|
||||||
|
viewThemeUtils
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showDeckCard(message: ChatMessage) {
|
||||||
|
if (message.messageParameters != null && message.messageParameters!!.size > 0) {
|
||||||
|
for (key in message.messageParameters!!.keys) {
|
||||||
|
val individualHashMap: Map<String?, String?> = message.messageParameters!![key]!!
|
||||||
|
if (individualHashMap["type"] == "deck-card") {
|
||||||
|
cardName = individualHashMap["name"]
|
||||||
|
stackName = individualHashMap["stackname"]
|
||||||
|
boardName = individualHashMap["boardname"]
|
||||||
|
cardLink = individualHashMap["link"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val cardDescription = String.format(
|
||||||
|
context.resources.getString(R.string.deck_card_description),
|
||||||
|
stackName,
|
||||||
|
boardName
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.cardName.visibility = View.VISIBLE
|
||||||
|
binding.cardDescription.visibility = View.VISIBLE
|
||||||
|
binding.cardName.text = cardName
|
||||||
|
binding.cardDescription.text = cardDescription
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun longClickOnReaction(chatMessage: ChatMessage) {
|
||||||
|
commonMessageInterface.onLongClickReactions(chatMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clickOnReaction(chatMessage: ChatMessage, emoji: String) {
|
||||||
|
commonMessageInterface.onClickReaction(chatMessage, emoji)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setParentMessageDataOnMessageItem(message: ChatMessage) {
|
||||||
|
if (message.parentMessageId != null && !message.isDeleted) {
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
try {
|
||||||
|
val chatActivity = commonMessageInterface as ChatActivity
|
||||||
|
val urlForChatting = ApiUtils.getUrlForChat(
|
||||||
|
chatActivity.chatApiVersion,
|
||||||
|
chatActivity.conversationUser?.baseUrl,
|
||||||
|
chatActivity.roomToken
|
||||||
|
)
|
||||||
|
|
||||||
|
val parentChatMessage = withContext(Dispatchers.IO) {
|
||||||
|
chatActivity.chatViewModel.getMessageById(
|
||||||
|
urlForChatting,
|
||||||
|
chatActivity.currentConversation!!,
|
||||||
|
message.parentMessageId!!
|
||||||
|
).first()
|
||||||
|
}
|
||||||
|
parentChatMessage.activeUser = message.activeUser
|
||||||
|
parentChatMessage.imageUrl?.let {
|
||||||
|
binding.messageQuote.quotedMessageImage.visibility = View.VISIBLE
|
||||||
|
binding.messageQuote.quotedMessageImage.load(it) {
|
||||||
|
addHeader(
|
||||||
|
"Authorization",
|
||||||
|
ApiUtils.getCredentials(message.activeUser!!.username, message.activeUser!!.token)!!
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
binding.messageQuote.quotedMessageImage.visibility = View.GONE
|
||||||
|
}
|
||||||
|
binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
|
||||||
|
?: context.getText(R.string.nc_nick_guest)
|
||||||
|
binding.messageQuote.quotedMessage.text = messageUtils
|
||||||
|
.enrichChatReplyMessageText(
|
||||||
|
binding.messageQuote.quotedMessage.context,
|
||||||
|
parentChatMessage,
|
||||||
|
true,
|
||||||
|
viewThemeUtils
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.messageQuote.quotedMessageAuthor
|
||||||
|
.setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast))
|
||||||
|
|
||||||
|
if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) {
|
||||||
|
viewThemeUtils.platform.colorViewBackground(
|
||||||
|
binding.messageQuote.quoteColoredView,
|
||||||
|
ColorRole.PRIMARY
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.messageQuote.quoteColoredView.setBackgroundResource(R.color.textColorMaxContrast)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.messageQuote.quotedChatMessageView.visibility = View.VISIBLE
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.d(TAG, "Error when processing parent message in view holder", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.messageQuote.quotedChatMessageView.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun colorizeMessageBubble(message: ChatMessage) {
|
||||||
|
viewThemeUtils.talk.themeOutgoingMessageBubble(bubble, message.isGrouped, message.isDeleted)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assignCommonMessageInterface(commonMessageInterface: CommonMessageInterface) {
|
||||||
|
this.commonMessageInterface = commonMessageInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = OutcomingDeckCardViewHolder::class.java.simpleName
|
||||||
|
}
|
||||||
|
}
|
@ -67,6 +67,10 @@ public class TalkMessagesListAdapter<M extends IMessage> extends MessagesListAda
|
|||||||
((CallStartedViewHolder) holder).assignCallStartedMessageInterface(chatActivity);
|
((CallStartedViewHolder) holder).assignCallStartedMessageInterface(chatActivity);
|
||||||
} else if (holder instanceof TemporaryMessageViewHolder) {
|
} else if (holder instanceof TemporaryMessageViewHolder) {
|
||||||
((TemporaryMessageViewHolder) holder).assignTemporaryMessageInterface(chatActivity);
|
((TemporaryMessageViewHolder) holder).assignTemporaryMessageInterface(chatActivity);
|
||||||
|
}else if (holder instanceof IncomingDeckCardViewHolder){
|
||||||
|
((IncomingDeckCardViewHolder) holder).assignCommonMessageInterface(chatActivity);
|
||||||
|
} else if(holder instanceof OutcomingDeckCardViewHolder){
|
||||||
|
((OutcomingDeckCardViewHolder) holder).assignCommonMessageInterface(chatActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onBindViewHolder(holder, position);
|
super.onBindViewHolder(holder, position);
|
||||||
|
@ -83,6 +83,7 @@ import com.nextcloud.talk.activities.TakePhotoActivity
|
|||||||
import com.nextcloud.talk.adapters.messages.CallStartedMessageInterface
|
import com.nextcloud.talk.adapters.messages.CallStartedMessageInterface
|
||||||
import com.nextcloud.talk.adapters.messages.CallStartedViewHolder
|
import com.nextcloud.talk.adapters.messages.CallStartedViewHolder
|
||||||
import com.nextcloud.talk.adapters.messages.CommonMessageInterface
|
import com.nextcloud.talk.adapters.messages.CommonMessageInterface
|
||||||
|
import com.nextcloud.talk.adapters.messages.IncomingDeckCardViewHolder
|
||||||
import com.nextcloud.talk.adapters.messages.IncomingLinkPreviewMessageViewHolder
|
import com.nextcloud.talk.adapters.messages.IncomingLinkPreviewMessageViewHolder
|
||||||
import com.nextcloud.talk.adapters.messages.IncomingLocationMessageViewHolder
|
import com.nextcloud.talk.adapters.messages.IncomingLocationMessageViewHolder
|
||||||
import com.nextcloud.talk.adapters.messages.IncomingPollMessageViewHolder
|
import com.nextcloud.talk.adapters.messages.IncomingPollMessageViewHolder
|
||||||
@ -96,6 +97,7 @@ import com.nextcloud.talk.adapters.messages.OutcomingPollMessageViewHolder
|
|||||||
import com.nextcloud.talk.adapters.messages.OutcomingPreviewMessageViewHolder
|
import com.nextcloud.talk.adapters.messages.OutcomingPreviewMessageViewHolder
|
||||||
import com.nextcloud.talk.adapters.messages.OutcomingTextMessageViewHolder
|
import com.nextcloud.talk.adapters.messages.OutcomingTextMessageViewHolder
|
||||||
import com.nextcloud.talk.adapters.messages.OutcomingVoiceMessageViewHolder
|
import com.nextcloud.talk.adapters.messages.OutcomingVoiceMessageViewHolder
|
||||||
|
import com.nextcloud.talk.adapters.messages.OutcomingDeckCardViewHolder
|
||||||
import com.nextcloud.talk.adapters.messages.PreviewMessageInterface
|
import com.nextcloud.talk.adapters.messages.PreviewMessageInterface
|
||||||
import com.nextcloud.talk.adapters.messages.PreviewMessageViewHolder
|
import com.nextcloud.talk.adapters.messages.PreviewMessageViewHolder
|
||||||
import com.nextcloud.talk.adapters.messages.SystemMessageInterface
|
import com.nextcloud.talk.adapters.messages.SystemMessageInterface
|
||||||
@ -1291,6 +1293,18 @@ class ChatActivity :
|
|||||||
R.layout.item_custom_outcoming_link_preview_message,
|
R.layout.item_custom_outcoming_link_preview_message,
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
|
|
||||||
|
messageHolders.registerContentType(
|
||||||
|
CONTENT_TYPE_DECK_CARD,
|
||||||
|
IncomingDeckCardViewHolder::class.java,
|
||||||
|
payload,
|
||||||
|
R.layout.item_custom_incoming_deck_card_message,
|
||||||
|
OutcomingDeckCardViewHolder::class.java,
|
||||||
|
payload,
|
||||||
|
R.layout.item_custom_outcoming_deck_card_message,
|
||||||
|
this
|
||||||
|
)
|
||||||
|
|
||||||
return messageHolders
|
return messageHolders
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3517,6 +3531,7 @@ class ChatActivity :
|
|||||||
CONTENT_TYPE_UNREAD_NOTICE_MESSAGE -> message.id == "-1"
|
CONTENT_TYPE_UNREAD_NOTICE_MESSAGE -> message.id == "-1"
|
||||||
CONTENT_TYPE_CALL_STARTED -> message.id == "-2"
|
CONTENT_TYPE_CALL_STARTED -> message.id == "-2"
|
||||||
CONTENT_TYPE_TEMP -> message.id == "-3"
|
CONTENT_TYPE_TEMP -> message.id == "-3"
|
||||||
|
CONTENT_TYPE_DECK_CARD -> message.isDeckCard()
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
@ -3721,7 +3736,8 @@ class ChatActivity :
|
|||||||
private const val CONTENT_TYPE_VOICE_MESSAGE: Byte = 5
|
private const val CONTENT_TYPE_VOICE_MESSAGE: Byte = 5
|
||||||
private const val CONTENT_TYPE_POLL: Byte = 6
|
private const val CONTENT_TYPE_POLL: Byte = 6
|
||||||
private const val CONTENT_TYPE_LINK_PREVIEW: Byte = 7
|
private const val CONTENT_TYPE_LINK_PREVIEW: Byte = 7
|
||||||
private const val CONTENT_TYPE_TEMP: Byte = 8
|
private const val CONTENT_TYPE_DECK_CARD: Byte = 8
|
||||||
|
private const val CONTENT_TYPE_TEMP: Byte = 9
|
||||||
private const val NEW_MESSAGES_POPUP_BUBBLE_DELAY: Long = 200
|
private const val NEW_MESSAGES_POPUP_BUBBLE_DELAY: Long = 200
|
||||||
private const val GET_ROOM_INFO_DELAY_NORMAL: Long = 30000
|
private const val GET_ROOM_INFO_DELAY_NORMAL: Long = 30000
|
||||||
private const val GET_ROOM_INFO_DELAY_LOBBY: Long = 5000
|
private const val GET_ROOM_INFO_DELAY_LOBBY: Long = 5000
|
||||||
|
@ -131,9 +131,21 @@ data class ChatMessage(
|
|||||||
MessageType.SINGLE_LINK_MESSAGE,
|
MessageType.SINGLE_LINK_MESSAGE,
|
||||||
MessageType.SINGLE_NC_GEOLOCATION_MESSAGE,
|
MessageType.SINGLE_NC_GEOLOCATION_MESSAGE,
|
||||||
MessageType.VOICE_MESSAGE,
|
MessageType.VOICE_MESSAGE,
|
||||||
MessageType.POLL_MESSAGE
|
MessageType.POLL_MESSAGE,
|
||||||
|
MessageType.DECK_CARD
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun isDeckCard(): Boolean {
|
||||||
|
if (messageParameters != null && messageParameters!!.size > 0) {
|
||||||
|
for ((_, individualHashMap) in messageParameters!!) {
|
||||||
|
if (isHashMapEntryEqualTo(individualHashMap, "type", "deck-card")) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fun hasFileAttachment(): Boolean {
|
fun hasFileAttachment(): Boolean {
|
||||||
if (messageParameters != null && messageParameters!!.size > 0) {
|
if (messageParameters != null && messageParameters!!.size > 0) {
|
||||||
for ((_, individualHashMap) in messageParameters!!) {
|
for ((_, individualHashMap) in messageParameters!!) {
|
||||||
@ -237,6 +249,8 @@ data class ChatMessage(
|
|||||||
MessageType.SINGLE_NC_GEOLOCATION_MESSAGE
|
MessageType.SINGLE_NC_GEOLOCATION_MESSAGE
|
||||||
} else if (isPoll()) {
|
} else if (isPoll()) {
|
||||||
MessageType.POLL_MESSAGE
|
MessageType.POLL_MESSAGE
|
||||||
|
} else if (isDeckCard()) {
|
||||||
|
MessageType.DECK_CARD
|
||||||
} else {
|
} else {
|
||||||
MessageType.REGULAR_TEXT_MESSAGE
|
MessageType.REGULAR_TEXT_MESSAGE
|
||||||
}
|
}
|
||||||
@ -345,7 +359,8 @@ data class ChatMessage(
|
|||||||
SINGLE_NC_ATTACHMENT_MESSAGE,
|
SINGLE_NC_ATTACHMENT_MESSAGE,
|
||||||
SINGLE_NC_GEOLOCATION_MESSAGE,
|
SINGLE_NC_GEOLOCATION_MESSAGE,
|
||||||
POLL_MESSAGE,
|
POLL_MESSAGE,
|
||||||
VOICE_MESSAGE
|
VOICE_MESSAGE,
|
||||||
|
DECK_CARD
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
25
app/src/main/res/drawable/deck.xml
Normal file
25
app/src/main/res/drawable/deck.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<!--
|
||||||
|
~ Nextcloud Talk - Android Client
|
||||||
|
~
|
||||||
|
~ SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
|
||||||
|
~ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:pathData="M2,7L14,7A1,1 0,0 1,15 8L15,14A1,1 0,0 1,14 15L2,15A1,1 0,0 1,1 14L1,8A1,1 0,0 1,2 7z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M2.5,5L13.5,5A0.5,0.5 0,0 1,14 5.5L14,5.5A0.5,0.5 0,0 1,13.5 6L2.5,6A0.5,0.5 0,0 1,2 5.5L2,5.5A0.5,0.5 0,0 1,2.5 5z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M3.5,3L12.5,3A0.5,0.5 0,0 1,13 3.5L13,3.5A0.5,0.5 0,0 1,12.5 4L3.5,4A0.5,0.5 0,0 1,3 3.5L3,3.5A0.5,0.5 0,0 1,3.5 3z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M4.5,1L11.5,1A0.5,0.5 0,0 1,12 1.5L12,1.5A0.5,0.5 0,0 1,11.5 2L4.5,2A0.5,0.5 0,0 1,4 1.5L4,1.5A0.5,0.5 0,0 1,4.5 1z"
|
||||||
|
android:fillColor="#fff"/>
|
||||||
|
</vector>
|
@ -0,0 +1,119 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Nextcloud Talk - Android Client
|
||||||
|
~
|
||||||
|
~ SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
|
||||||
|
~ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<RelativeLayout 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/cardView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginBottom="2dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@id/messageUserAvatar"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginTop ="2dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:contentDescription="@string/avatar" />
|
||||||
|
|
||||||
|
<com.google.android.flexbox.FlexboxLayout
|
||||||
|
android:id="@id/bubble"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="@dimen/message_incoming_bubble_margin_right"
|
||||||
|
android:layout_toEndOf="@id/messageUserAvatar"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:alignContent="stretch"
|
||||||
|
app:alignItems="stretch"
|
||||||
|
app:flexWrap="wrap">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/message_quote"
|
||||||
|
layout="@layout/item_message_quote"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<androidx.emoji2.widget.EmojiTextView
|
||||||
|
android:id="@+id/messageAuthor"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:alpha="0.6"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textColor="@color/no_emphasis_text"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
android:textSize="12sp"
|
||||||
|
tools:text="Jane Doe" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/deckCardImage"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/deck" />
|
||||||
|
|
||||||
|
<androidx.emoji2.widget.EmojiTextView
|
||||||
|
android:id="@+id/cardName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="Card Name"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.emoji2.widget.EmojiTextView
|
||||||
|
android:id="@+id/cardDescription"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
tools:text="Card Description"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@id/messageTime"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:alpha="0.6"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:textColor="@color/no_emphasis_text"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
tools:text="12:38" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/reactions"
|
||||||
|
layout="@layout/reactions_inside_message" />
|
||||||
|
|
||||||
|
</com.google.android.flexbox.FlexboxLayout>
|
||||||
|
</RelativeLayout>
|
@ -0,0 +1,113 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Nextcloud Talk - Android Client
|
||||||
|
~
|
||||||
|
~ SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
|
||||||
|
~ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<RelativeLayout 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/cardView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginBottom="2dp">
|
||||||
|
|
||||||
|
<com.google.android.flexbox.FlexboxLayout
|
||||||
|
android:id="@id/bubble"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_marginStart="@dimen/message_outcoming_bubble_margin_left"
|
||||||
|
app:alignContent="stretch"
|
||||||
|
app:alignItems="stretch"
|
||||||
|
app:flexWrap="wrap"
|
||||||
|
app:justifyContent="flex_end">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/message_quote"
|
||||||
|
layout="@layout/item_message_quote"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/deckCardImage"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/deck" />
|
||||||
|
|
||||||
|
<androidx.emoji2.widget.EmojiTextView
|
||||||
|
android:id="@+id/cardName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="Card Name"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.emoji2.widget.EmojiTextView
|
||||||
|
android:id="@+id/cardDescription"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="Card Description"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@id/messageTime"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:alpha="0.6"
|
||||||
|
android:textColor="@color/no_emphasis_text"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
tools:text="12:38" />
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/checkMark"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/message_bubble_checkmark_height"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
app:tint="@color/high_emphasis_text" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/reactions"
|
||||||
|
layout="@layout/reactions_inside_message" />
|
||||||
|
|
||||||
|
</com.google.android.flexbox.FlexboxLayout>
|
||||||
|
</RelativeLayout>
|
@ -407,6 +407,7 @@ How to translate with transifex:
|
|||||||
<string name="nc_sent_poll" formatted="true">%1$s sent a poll.</string>
|
<string name="nc_sent_poll" formatted="true">%1$s sent a poll.</string>
|
||||||
<string name="nc_sent_location" formatted="true">%1$s sent a location.</string>
|
<string name="nc_sent_location" formatted="true">%1$s sent a location.</string>
|
||||||
<string name="nc_sent_voice" formatted="true">%1$s sent a voice message.</string>
|
<string name="nc_sent_voice" formatted="true">%1$s sent a voice message.</string>
|
||||||
|
<string name="nc_sent_deck_card" formatted="true">%1$s sent a deck card</string>
|
||||||
<string name="nc_sent_a_gif_you">You sent a GIF.</string>
|
<string name="nc_sent_a_gif_you">You sent a GIF.</string>
|
||||||
<string name="nc_sent_an_attachment_you">You sent an attachment.</string>
|
<string name="nc_sent_an_attachment_you">You sent an attachment.</string>
|
||||||
<string name="nc_sent_an_audio_you">You sent an audio.</string>
|
<string name="nc_sent_an_audio_you">You sent an audio.</string>
|
||||||
@ -415,6 +416,7 @@ How to translate with transifex:
|
|||||||
<string name="nc_sent_poll_you">You sent a poll.</string>
|
<string name="nc_sent_poll_you">You sent a poll.</string>
|
||||||
<string name="nc_sent_location_you">You sent a location.</string>
|
<string name="nc_sent_location_you">You sent a location.</string>
|
||||||
<string name="nc_sent_voice_you">You sent a voice message.</string>
|
<string name="nc_sent_voice_you">You sent a voice message.</string>
|
||||||
|
<string name="nc_sent_deck_card_you">You sent a deck card</string>
|
||||||
<string name="nc_formatted_message" translatable="false">%1$s: %2$s</string>
|
<string name="nc_formatted_message" translatable="false">%1$s: %2$s</string>
|
||||||
<string name="nc_message_quote_cancel_reply">Cancel reply</string>
|
<string name="nc_message_quote_cancel_reply">Cancel reply</string>
|
||||||
<!-- When translating to German, please use non-formal variant -->
|
<!-- When translating to German, please use non-formal variant -->
|
||||||
@ -515,7 +517,7 @@ How to translate with transifex:
|
|||||||
<string name="typing_are_typing">are typing …</string>
|
<string name="typing_are_typing">are typing …</string>
|
||||||
<string name="typing_1_other">and 1 other is typing …</string>
|
<string name="typing_1_other">and 1 other is typing …</string>
|
||||||
<string name="typing_x_others">and %1$s others are typing …</string>
|
<string name="typing_x_others">and %1$s others are typing …</string>
|
||||||
|
<string name="deck_card_description">%1$s in %2$s</string>
|
||||||
<!-- Upload -->
|
<!-- Upload -->
|
||||||
<string name="nc_add_file">Add to conversation</string>
|
<string name="nc_add_file">Add to conversation</string>
|
||||||
<string name="nc_upload_picture_from_cam">Take photo</string>
|
<string name="nc_upload_picture_from_cam">Take photo</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user