From fa8fd7b2296ab51d154b5a654ec09a054099d7b1 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Fri, 7 Jul 2023 14:45:54 +0200 Subject: [PATCH] unify markdown rendering of chat messages Signed-off-by: Andy Scherzinger --- app/build.gradle | 5 +- .../IncomingLinkPreviewMessageViewHolder.kt | 29 +++- .../IncomingLocationMessageViewHolder.kt | 13 +- .../messages/IncomingPollMessageViewHolder.kt | 13 +- .../messages/IncomingTextMessageViewHolder.kt | 76 ++++----- .../IncomingVoiceMessageViewHolder.kt | 13 +- .../OutcomingLinkPreviewMessageViewHolder.kt | 21 ++- .../OutcomingLocationMessageViewHolder.kt | 11 +- .../OutcomingPollMessageViewHolder.kt | 11 +- .../OutcomingTextMessageViewHolder.kt | 76 +++------ .../OutcomingVoiceMessageViewHolder.kt | 11 +- .../talk/dagger/modules/UtilsModule.kt | 7 + .../nextcloud/talk/utils/DisplayUtils.java | 27 ---- .../talk/utils/message/MessageUtils.kt | 145 ++++++++++++++++++ 14 files changed, 321 insertions(+), 137 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt diff --git a/app/build.gradle b/app/build.gradle index ba8333413..b0a340a85 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -264,14 +264,15 @@ dependencies { implementation "com.afollestad.material-dialogs:lifecycle:${materialDialogsVersion}" implementation 'com.google.code.gson:gson:2.10.1' - implementation 'com.google.android.exoplayer:exoplayer:2.18.7' + implementation 'com.google.android.exoplayer:exoplayer:2.19.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.27' implementation "io.noties.markwon:core:$markwonVersion" implementation "io.noties.markwon:ext-strikethrough:$markwonVersion" - implementation "io.noties.markwon:syntax-highlight:$markwonVersion" + implementation "io.noties.markwon:ext-tables:$markwonVersion" + implementation "io.noties.markwon:ext-tasklist:$markwonVersion" implementation 'com.github.nextcloud-deps:ImagePicker:2.1.0.2' implementation 'com.elyeproj.libraries:loaderviewlibrary:2.0.0' diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt index 2f381e55d..34903ad7e 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLinkPreviewMessageViewHolder.kt @@ -40,6 +40,7 @@ import com.nextcloud.talk.models.json.chat.ChatMessage 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 javax.inject.Inject @@ -60,6 +61,9 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var dateUtils: DateUtils @@ -77,6 +81,22 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : sharedApplication!!.componentApplication.inject(this) binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) + var processedMessageText = messageUtils.enrichChatMessageText( + binding.messageText.context, + message, + binding.messageText.context.resources.getColor(R.color.nc_incoming_text_default) + ) + + processedMessageText = messageUtils.processMessageParameters( + binding.messageText.context, + viewThemeUtils, + processedMessageText!!, + message, + itemView + ) + + binding.messageText.text = processedMessageText + setAvatarAndAuthorOnMessageItem(message) colorizeMessageBubble(message) @@ -174,7 +194,14 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = parentChatMessage.text + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage.text, + binding.messageQuote.quotedMessage.context.resources.getColor( + R.color.nc_incoming_text_default + ) + ) binding.messageQuote.quotedMessageAuthor .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast)) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt index 4e19aac50..1941c1790 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingLocationMessageViewHolder.kt @@ -51,6 +51,7 @@ import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.UriUtils +import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.preferences.AppPreferences import com.stfalcon.chatkit.messages.MessageHolders import java.net.URLEncoder @@ -76,6 +77,9 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var dateUtils: DateUtils @@ -175,7 +179,14 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context!!.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = parentChatMessage.text + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage.text, + binding.messageQuote.quotedMessage.context.resources.getColor( + R.color.nc_incoming_text_default + ) + ) binding.messageQuote.quotedMessageAuthor .setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast, null)) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt index ea13b5718..dea850d3b 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingPollMessageViewHolder.kt @@ -40,6 +40,7 @@ import com.nextcloud.talk.polls.ui.PollMainDialogFragment 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 javax.inject.Inject @@ -59,6 +60,9 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var dateUtils: DateUtils @@ -198,7 +202,14 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = parentChatMessage.text + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage.text, + binding.messageQuote.quotedMessage.context.resources.getColor( + R.color.nc_incoming_text_default + ) + ) binding.messageQuote.quotedMessageAuthor .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast)) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt index 6d378e918..fbc3a6bb2 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt @@ -27,9 +27,6 @@ package com.nextcloud.talk.adapters.messages import android.content.Context -import android.content.Intent -import android.net.Uri -import android.text.Spanned import android.text.TextUtils import android.util.TypedValue import android.view.View @@ -49,6 +46,7 @@ import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.TextMatchers +import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.preferences.AppPreferences import com.stfalcon.chatkit.messages.MessageHolders import javax.inject.Inject @@ -65,6 +63,9 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var appPreferences: AppPreferences @@ -85,12 +86,25 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : var textSize = context.resources!!.getDimension(R.dimen.chat_text_size) - var processedMessageText = DisplayUtils.getRenderedMarkdownText(context, message.message) + var processedMessageText = messageUtils.enrichChatMessageText( + binding.messageText.context, + message, + binding.messageText.context.resources.getColor(R.color.nc_incoming_text_default) + ) + + processedMessageText = messageUtils.processMessageParameters( + binding.messageText.context, + viewThemeUtils, + processedMessageText!!, + message, + itemView + ) val messageParameters = message.messageParameters - if (messageParameters != null && messageParameters.size > 0) { - processedMessageText = processMessageParameters(messageParameters, message, processedMessageText) - } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) { + if ( + (messageParameters == null || messageParameters.size <= 0) && + TextMatchers.isMessageWithSingleEmoticonOnly(message.text) + ) { textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat() itemView.isSelected = true binding.messageAuthor.visibility = View.GONE @@ -188,7 +202,12 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } else { parentChatMessage.actorDisplayName } - binding.messageQuote.quotedMessage.text = DisplayUtils.ellipsize(parentChatMessage.text, MAX_REPLY_LENGTH) + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + DisplayUtils.ellipsize(parentChatMessage.text, MAX_REPLY_LENGTH), + binding.messageQuote.quotedMessage.context.resources.getColor(R.color.nc_incoming_text_default) + ) if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) { viewThemeUtils.platform.colorViewBackground(binding.messageQuote.quoteColoredView) @@ -215,47 +234,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : } } - private fun processMessageParameters( - messageParameters: HashMap>, - message: ChatMessage, - messageString: Spanned - ): Spanned { - var messageStringInternal = messageString - for (key in messageParameters.keys) { - val individualHashMap = message.messageParameters!![key] - if (individualHashMap != null) { - when (individualHashMap["type"]) { - "user", "guest", "call", "user-group" -> { - val chip = if (individualHashMap["id"] == message.activeUser!!.userId) { - R.xml.chip_you - } else { - R.xml.chip_others - } - messageStringInternal = DisplayUtils.searchAndReplaceWithMentionSpan( - key, - binding.messageText.context, - messageStringInternal, - individualHashMap["id"]!!, - individualHashMap["name"]!!, - individualHashMap["type"]!!, - message.activeUser!!, - chip, - viewThemeUtils - ) - } - "file" -> { - itemView.setOnClickListener { v -> - val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"])) - context.startActivity(browserIntent) - } - } - } - } - } - - return messageStringInternal - } - fun assignCommonMessageInterface(commonMessageInterface: CommonMessageInterface) { this.commonMessageInterface = commonMessageInterface } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt index 4f387b60d..9ee4752ae 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingVoiceMessageViewHolder.kt @@ -49,6 +49,7 @@ import com.nextcloud.talk.models.json.chat.ChatMessage 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 java.util.concurrent.ExecutionException @@ -67,6 +68,9 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var dateUtils: DateUtils @@ -285,7 +289,14 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context!!.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = parentChatMessage.text + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage.text, + binding.messageQuote.quotedMessage.context.resources.getColor( + R.color.nc_incoming_text_default + ) + ) binding.messageQuote.quotedMessageAuthor .setTextColor(ContextCompat.getColor(context!!, R.color.textColorMaxContrast)) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt index 3b7aef294..e8bd20696 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLinkPreviewMessageViewHolder.kt @@ -39,6 +39,7 @@ 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 javax.inject.Inject @@ -56,6 +57,9 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var dateUtils: DateUtils @@ -79,6 +83,16 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) : binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp) colorizeMessageBubble(message) + var processedMessageText = messageUtils.enrichChatMessageText(binding.messageText.context, message, textColor) + processedMessageText = messageUtils.processMessageParameters( + binding.messageText.context, + viewThemeUtils, + processedMessageText!!, + message, + itemView + ) + + binding.messageText.text = processedMessageText itemView.isSelected = false @@ -158,7 +172,12 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = parentChatMessage.text + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage.text, + viewThemeUtils.getScheme(binding.messageQuote.quotedMessage.context).onSurfaceVariant + ) viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage) viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor) viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt index 3b3b31dd0..dcc5d990a 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingLocationMessageViewHolder.kt @@ -48,6 +48,7 @@ import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.UriUtils +import com.nextcloud.talk.utils.message.MessageUtils import com.stfalcon.chatkit.messages.MessageHolders import java.net.URLEncoder import javax.inject.Inject @@ -71,6 +72,9 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var dateUtils: DateUtils @@ -221,7 +225,12 @@ class OutcomingLocationMessageViewHolder(incomingView: View) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context!!.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = parentChatMessage.text + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage.text, + viewThemeUtils.getScheme(binding.messageQuote.quotedMessage.context).onSurfaceVariant + ) viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage) viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor) viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt index 99d94330a..05571152f 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingPollMessageViewHolder.kt @@ -40,6 +40,7 @@ import com.nextcloud.talk.polls.ui.PollMainDialogFragment 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 javax.inject.Inject @@ -56,6 +57,9 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var dateUtils: DateUtils @@ -183,7 +187,12 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = parentChatMessage.text + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage.text, + viewThemeUtils.getScheme(binding.messageQuote.quotedMessage.context).onSurfaceVariant + ) viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage) viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor) viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt index 65a5da5a3..a0497d6aa 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt @@ -24,10 +24,7 @@ package com.nextcloud.talk.adapters.messages import android.content.Context -import android.content.Intent import android.graphics.PorterDuff -import android.net.Uri -import android.text.Spanned import android.util.TypedValue import android.view.View import androidx.core.content.res.ResourcesCompat @@ -46,6 +43,7 @@ import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.TextMatchers +import com.nextcloud.talk.utils.message.MessageUtils import com.stfalcon.chatkit.messages.MessageHolders.OutcomingTextMessageViewHolder import javax.inject.Inject @@ -60,6 +58,9 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var dateUtils: DateUtils @@ -68,19 +69,27 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH override fun onBind(message: ChatMessage) { super.onBind(message) sharedApplication!!.componentApplication.inject(this) - val messageParameters: HashMap>? = message.messageParameters realView.isSelected = false val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams layoutParams.isWrapBefore = false var textSize = context!!.resources.getDimension(R.dimen.chat_text_size) val textColor = viewThemeUtils.getScheme(binding.messageText.context).onSurfaceVariant - - var processedMessageText = DisplayUtils.getRenderedMarkdownText(context, message.message) - binding.messageTime.setTextColor(textColor) - if (messageParameters != null && messageParameters.size > 0) { - processedMessageText = processMessageParameters(messageParameters, message, processedMessageText) - } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) { + + var processedMessageText = messageUtils.enrichChatMessageText(binding.messageText.context, message, textColor) + processedMessageText = messageUtils.processMessageParameters( + binding.messageText.context, + viewThemeUtils, + processedMessageText!!, + message, + itemView + ) + + val messageParameters = message.messageParameters + if ( + (messageParameters == null || messageParameters.size <= 0) && + TextMatchers.isMessageWithSingleEmoticonOnly(message.text) + ) { textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat() layoutParams.isWrapBefore = true realView.isSelected = true @@ -165,7 +174,12 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context!!.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = DisplayUtils.ellipsize(parentChatMessage.text, MAX_REPLY_LENGTH) + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + DisplayUtils.ellipsize(parentChatMessage.text, MAX_REPLY_LENGTH), + textColor + ) binding.messageQuote.quotedMessageAuthor.setTextColor(textColor) binding.messageQuote.quotedMessage.setTextColor(textColor) @@ -181,46 +195,6 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH viewThemeUtils.talk.themeOutgoingMessageBubble(bubble, message.isGrouped, message.isDeleted) } - private fun processMessageParameters( - messageParameters: HashMap>, - message: ChatMessage, - messageString: Spanned - ): Spanned { - var messageStringInternal = messageString - for (key in messageParameters.keys) { - val individualHashMap: HashMap? = message.messageParameters!![key] - if (individualHashMap != null) { - when (individualHashMap["type"]) { - "user", "guest", "call", "user-group" -> { - val chip = if (individualHashMap["id"] == message.activeUser!!.userId) { - R.xml.chip_you - } else { - R.xml.chip_others - } - messageStringInternal = DisplayUtils.searchAndReplaceWithMentionSpan( - key, - binding.messageText.context, - messageStringInternal, - individualHashMap["id"]!!, - individualHashMap["name"]!!, - individualHashMap["type"]!!, - message.activeUser!!, - chip, - viewThemeUtils - ) - } - "file" -> { - itemView.setOnClickListener { v -> - val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"])) - context.startActivity(browserIntent) - } - } - } - } - } - return messageStringInternal - } - fun assignCommonMessageInterface(commonMessageInterface: CommonMessageInterface) { this.commonMessageInterface = commonMessageInterface } diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt index b754ab1e9..3aa7efa34 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingVoiceMessageViewHolder.kt @@ -45,6 +45,7 @@ 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 java.util.concurrent.ExecutionException @@ -63,6 +64,9 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : @Inject lateinit var viewThemeUtils: ViewThemeUtils + @Inject + lateinit var messageUtils: MessageUtils + @Inject lateinit var dateUtils: DateUtils @@ -271,7 +275,12 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) : } binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName ?: context!!.getText(R.string.nc_nick_guest) - binding.messageQuote.quotedMessage.text = parentChatMessage.text + binding.messageQuote.quotedMessage.text = messageUtils + .enrichChatMessageText( + binding.messageQuote.quotedMessage.context, + parentChatMessage.text, + viewThemeUtils.getScheme(binding.messageQuote.quotedMessage.context).onSurfaceVariant + ) viewThemeUtils.talk.colorOutgoingQuoteText(binding.messageQuote.quotedMessage) viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor) viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView) diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/UtilsModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/UtilsModule.kt index b3b8303dc..95b319644 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/UtilsModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/UtilsModule.kt @@ -23,6 +23,7 @@ package com.nextcloud.talk.dagger.modules import android.content.Context import com.nextcloud.talk.utils.DateUtils +import com.nextcloud.talk.utils.message.MessageUtils import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.permissions.PlatformPermissionUtilImpl import dagger.Module @@ -42,4 +43,10 @@ class UtilsModule { fun provideDateUtils(context: Context): DateUtils { return DateUtils(context) } + + @Provides + @Reusable + fun provideMessageUtils(context: Context): MessageUtils { + return MessageUtils(context) + } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java index dd4df7039..dc681d951 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java @@ -48,7 +48,6 @@ import android.text.style.AbsoluteSizeSpan; import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; -import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.Window; @@ -88,11 +87,6 @@ import coil.Coil; import coil.request.ImageRequest; import coil.target.Target; import coil.transform.CircleCropTransformation; -import io.noties.markwon.AbstractMarkwonPlugin; -import io.noties.markwon.Markwon; -import io.noties.markwon.MarkwonConfiguration; -import io.noties.markwon.core.MarkwonTheme; -import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import third.parties.fresco.BetterImageSpan; import static com.nextcloud.talk.utils.FileSortOrder.sort_a_to_z_id; @@ -253,27 +247,6 @@ public class DisplayUtils { return chip; } - public static Spanned getRenderedMarkdownText(Context context, String markdown) { - final Markwon markwon = Markwon.builder(context) - .usePlugin(new AbstractMarkwonPlugin() { - @Override - public void configureTheme(@NonNull MarkwonTheme.Builder builder) { - builder.headingBreakHeight(0); - } - - @Override - public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { - builder.linkResolver((view, link) -> { - Log.i(TAG, "Link action not implemented" ); - }); - } - }) - .usePlugin(StrikethroughPlugin.create()) - .build(); - - return markwon.toMarkdown(markdown); - } - public static Spannable searchAndReplaceWithMentionSpan(String key, Context context, Spanned text, String id, String label, String type, User conversationUser, diff --git a/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt new file mode 100644 index 000000000..dc542a418 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt @@ -0,0 +1,145 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * Copyright (C) 2023 Andy Scherzinger + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.talk.utils.message + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.text.Spanned +import android.util.Log +import android.view.View +import com.nextcloud.talk.R +import com.nextcloud.talk.models.json.chat.ChatMessage +import com.nextcloud.talk.ui.theme.ViewThemeUtils +import com.nextcloud.talk.utils.DisplayUtils +import io.noties.markwon.AbstractMarkwonPlugin +import io.noties.markwon.Markwon +import io.noties.markwon.MarkwonConfiguration +import io.noties.markwon.core.MarkwonTheme +import io.noties.markwon.ext.strikethrough.StrikethroughPlugin +import io.noties.markwon.ext.tables.TablePlugin +import io.noties.markwon.ext.tasklist.TaskListDrawable +import io.noties.markwon.ext.tasklist.TaskListPlugin + +class MessageUtils(val context: Context) { + + fun enrichChatMessageText(context: Context, message: ChatMessage, textColor: Int): Spanned? { + return if (message.message == null) { + null + } else { + enrichChatMessageText(context, message.message!!, textColor) + } + } + + fun enrichChatMessageText(context: Context, message: String, textColor: Int): Spanned { + return getRenderedMarkdownText(context, message, textColor) + } + + fun processMessageParameters( + themingContext: Context, + viewThemeUtils: ViewThemeUtils, + spannedText: Spanned, + message: ChatMessage, + itemView: View + ): Spanned { + var processedMessageText = spannedText + val messageParameters = message.messageParameters + if (messageParameters != null && messageParameters.size > 0) { + processedMessageText = processMessageParameters( + themingContext, + viewThemeUtils, + messageParameters, + message, + processedMessageText, + itemView + ) + } + return processedMessageText + } + + private fun processMessageParameters( + themingContext: Context, + viewThemeUtils: ViewThemeUtils, + messageParameters: HashMap>, + message: ChatMessage, + messageString: Spanned, + itemView: View + ): Spanned { + var messageStringInternal = messageString + for (key in messageParameters.keys) { + val individualHashMap = message.messageParameters!![key] + if (individualHashMap != null) { + when (individualHashMap["type"]) { + "user", "guest", "call", "user-group" -> { + val chip = if (individualHashMap["id"] == message.activeUser!!.userId) { + R.xml.chip_you + } else { + R.xml.chip_others + } + messageStringInternal = DisplayUtils.searchAndReplaceWithMentionSpan( + key, + themingContext, + messageStringInternal, + individualHashMap["id"]!!, + individualHashMap["name"]!!, + individualHashMap["type"]!!, + message.activeUser!!, + chip, + viewThemeUtils + ) + } + + "file" -> { + itemView.setOnClickListener { v -> + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"])) + context.startActivity(browserIntent) + } + } + } + } + } + + return messageStringInternal + } + + private fun getRenderedMarkdownText(context: Context, markdown: String, textColor: Int): Spanned { + val drawable = TaskListDrawable(textColor, textColor, context.getColor(R.color.bg_default)) + val markwon = Markwon.builder(context).usePlugin(object : AbstractMarkwonPlugin() { + override fun configureTheme(builder: MarkwonTheme.Builder) { + builder.isLinkUnderlined(true).headingBreakHeight(0) + } + + override fun configureConfiguration(builder: MarkwonConfiguration.Builder) { + builder.linkResolver { view: View?, link: String? -> + Log.i(TAG, "Link action not implemented $view / $link") + } + } + }) + .usePlugin(TablePlugin.create(context)) + .usePlugin(TaskListPlugin.create(drawable)) + .usePlugin(StrikethroughPlugin.create()).build() + return markwon.toMarkdown(markdown) + } + + companion object { + private const val TAG = "MessageUtils" + } +}