瀏覽代碼

unify markdown rendering of chat messages

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Andy Scherzinger 2 年之前
父節點
當前提交
fa8fd7b229

+ 3 - 2
app/build.gradle

@@ -264,14 +264,15 @@ dependencies {
     implementation "com.afollestad.material-dialogs:lifecycle:${materialDialogsVersion}"
     implementation "com.afollestad.material-dialogs:lifecycle:${materialDialogsVersion}"
 
 
     implementation 'com.google.code.gson:gson:2.10.1'
     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 'com.github.chrisbanes:PhotoView:2.3.0'
     implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.27'
     implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.27'
 
 
     implementation "io.noties.markwon:core:$markwonVersion"
     implementation "io.noties.markwon:core:$markwonVersion"
     implementation "io.noties.markwon:ext-strikethrough:$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.github.nextcloud-deps:ImagePicker:2.1.0.2'
     implementation 'com.elyeproj.libraries:loaderviewlibrary:2.0.0'
     implementation 'com.elyeproj.libraries:loaderviewlibrary:2.0.0'

+ 28 - 1
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.ui.theme.ViewThemeUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.DateUtils
+import com.nextcloud.talk.utils.message.MessageUtils
 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 javax.inject.Inject
 import javax.inject.Inject
@@ -60,6 +61,9 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) :
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var dateUtils: DateUtils
     lateinit var dateUtils: DateUtils
 
 
@@ -77,6 +81,22 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) :
         sharedApplication!!.componentApplication.inject(this)
         sharedApplication!!.componentApplication.inject(this)
         binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
         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)
         setAvatarAndAuthorOnMessageItem(message)
 
 
         colorizeMessageBubble(message)
         colorizeMessageBubble(message)
@@ -174,7 +194,14 @@ class IncomingLinkPreviewMessageViewHolder(incomingView: View, payload: Any) :
             }
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
                 ?: context.getText(R.string.nc_nick_guest)
                 ?: 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
             binding.messageQuote.quotedMessageAuthor
                 .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast))
                 .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast))

+ 12 - 1
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.ApiUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.UriUtils
 import com.nextcloud.talk.utils.UriUtils
+import com.nextcloud.talk.utils.message.MessageUtils
 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 java.net.URLEncoder
 import java.net.URLEncoder
@@ -76,6 +77,9 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) :
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var dateUtils: DateUtils
     lateinit var dateUtils: DateUtils
 
 
@@ -175,7 +179,14 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) :
             }
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
                 ?: context!!.getText(R.string.nc_nick_guest)
                 ?: 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
             binding.messageQuote.quotedMessageAuthor
                 .setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast, null))
                 .setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast, null))

+ 12 - 1
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.ui.theme.ViewThemeUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.DateUtils
+import com.nextcloud.talk.utils.message.MessageUtils
 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 javax.inject.Inject
 import javax.inject.Inject
@@ -59,6 +60,9 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) :
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var dateUtils: DateUtils
     lateinit var dateUtils: DateUtils
 
 
@@ -198,7 +202,14 @@ class IncomingPollMessageViewHolder(incomingView: View, payload: Any) :
             }
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
                 ?: context.getText(R.string.nc_nick_guest)
                 ?: 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
             binding.messageQuote.quotedMessageAuthor
                 .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast))
                 .setTextColor(ContextCompat.getColor(context, R.color.textColorMaxContrast))

+ 27 - 49
app/src/main/java/com/nextcloud/talk/adapters/messages/IncomingTextMessageViewHolder.kt

@@ -27,9 +27,6 @@
 package com.nextcloud.talk.adapters.messages
 package com.nextcloud.talk.adapters.messages
 
 
 import android.content.Context
 import android.content.Context
-import android.content.Intent
-import android.net.Uri
-import android.text.Spanned
 import android.text.TextUtils
 import android.text.TextUtils
 import android.util.TypedValue
 import android.util.TypedValue
 import android.view.View
 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.DateUtils
 import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.TextMatchers
 import com.nextcloud.talk.utils.TextMatchers
+import com.nextcloud.talk.utils.message.MessageUtils
 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 javax.inject.Inject
 import javax.inject.Inject
@@ -65,6 +63,9 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var appPreferences: AppPreferences
     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 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
         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()
             textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat()
             itemView.isSelected = true
             itemView.isSelected = true
             binding.messageAuthor.visibility = View.GONE
             binding.messageAuthor.visibility = View.GONE
@@ -188,7 +202,12 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
         } else {
         } else {
             parentChatMessage.actorDisplayName
             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) {
         if (parentChatMessage.actorId?.equals(message.activeUser!!.userId) == true) {
             viewThemeUtils.platform.colorViewBackground(binding.messageQuote.quoteColoredView)
             viewThemeUtils.platform.colorViewBackground(binding.messageQuote.quoteColoredView)
@@ -215,47 +234,6 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
         }
         }
     }
     }
 
 
-    private fun processMessageParameters(
-        messageParameters: HashMap<String?, HashMap<String?, String?>>,
-        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) {
     fun assignCommonMessageInterface(commonMessageInterface: CommonMessageInterface) {
         this.commonMessageInterface = commonMessageInterface
         this.commonMessageInterface = commonMessageInterface
     }
     }

+ 12 - 1
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.ui.theme.ViewThemeUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.DateUtils
+import com.nextcloud.talk.utils.message.MessageUtils
 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 java.util.concurrent.ExecutionException
 import java.util.concurrent.ExecutionException
@@ -67,6 +68,9 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var dateUtils: DateUtils
     lateinit var dateUtils: DateUtils
 
 
@@ -285,7 +289,14 @@ class IncomingVoiceMessageViewHolder(incomingView: View, payload: Any) :
             }
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
                 ?: context!!.getText(R.string.nc_nick_guest)
                 ?: 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
             binding.messageQuote.quotedMessageAuthor
                 .setTextColor(ContextCompat.getColor(context!!, R.color.textColorMaxContrast))
                 .setTextColor(ContextCompat.getColor(context!!, R.color.textColorMaxContrast))

+ 20 - 1
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.ui.theme.ViewThemeUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.DateUtils
+import com.nextcloud.talk.utils.message.MessageUtils
 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 javax.inject.Inject
 import javax.inject.Inject
@@ -56,6 +57,9 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) :
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var dateUtils: DateUtils
     lateinit var dateUtils: DateUtils
 
 
@@ -79,6 +83,16 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) :
         binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
         binding.messageTime.text = dateUtils.getLocalTimeStringFromTimestamp(message.timestamp)
 
 
         colorizeMessageBubble(message)
         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
         itemView.isSelected = false
 
 
@@ -158,7 +172,12 @@ class OutcomingLinkPreviewMessageViewHolder(outcomingView: View, payload: Any) :
             }
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
                 ?: context.getText(R.string.nc_nick_guest)
                 ?: 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.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
             viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)
             viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)

+ 10 - 1
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.ApiUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.UriUtils
 import com.nextcloud.talk.utils.UriUtils
+import com.nextcloud.talk.utils.message.MessageUtils
 import com.stfalcon.chatkit.messages.MessageHolders
 import com.stfalcon.chatkit.messages.MessageHolders
 import java.net.URLEncoder
 import java.net.URLEncoder
 import javax.inject.Inject
 import javax.inject.Inject
@@ -71,6 +72,9 @@ class OutcomingLocationMessageViewHolder(incomingView: View) :
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var dateUtils: DateUtils
     lateinit var dateUtils: DateUtils
 
 
@@ -221,7 +225,12 @@ class OutcomingLocationMessageViewHolder(incomingView: View) :
             }
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
                 ?: context!!.getText(R.string.nc_nick_guest)
                 ?: 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.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
             viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)
             viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)

+ 10 - 1
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.ui.theme.ViewThemeUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.DateUtils
+import com.nextcloud.talk.utils.message.MessageUtils
 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 javax.inject.Inject
 import javax.inject.Inject
@@ -56,6 +57,9 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) :
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var dateUtils: DateUtils
     lateinit var dateUtils: DateUtils
 
 
@@ -183,7 +187,12 @@ class OutcomingPollMessageViewHolder(outcomingView: View, payload: Any) :
             }
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
                 ?: context.getText(R.string.nc_nick_guest)
                 ?: 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.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
             viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)
             viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)

+ 24 - 50
app/src/main/java/com/nextcloud/talk/adapters/messages/OutcomingTextMessageViewHolder.kt

@@ -24,10 +24,7 @@
 package com.nextcloud.talk.adapters.messages
 package com.nextcloud.talk.adapters.messages
 
 
 import android.content.Context
 import android.content.Context
-import android.content.Intent
 import android.graphics.PorterDuff
 import android.graphics.PorterDuff
-import android.net.Uri
-import android.text.Spanned
 import android.util.TypedValue
 import android.util.TypedValue
 import android.view.View
 import android.view.View
 import androidx.core.content.res.ResourcesCompat
 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.DateUtils
 import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.TextMatchers
 import com.nextcloud.talk.utils.TextMatchers
+import com.nextcloud.talk.utils.message.MessageUtils
 import com.stfalcon.chatkit.messages.MessageHolders.OutcomingTextMessageViewHolder
 import com.stfalcon.chatkit.messages.MessageHolders.OutcomingTextMessageViewHolder
 import javax.inject.Inject
 import javax.inject.Inject
 
 
@@ -60,6 +58,9 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var dateUtils: DateUtils
     lateinit var dateUtils: DateUtils
 
 
@@ -68,19 +69,27 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH
     override fun onBind(message: ChatMessage) {
     override fun onBind(message: ChatMessage) {
         super.onBind(message)
         super.onBind(message)
         sharedApplication!!.componentApplication.inject(this)
         sharedApplication!!.componentApplication.inject(this)
-        val messageParameters: HashMap<String?, HashMap<String?, String?>>? = message.messageParameters
         realView.isSelected = false
         realView.isSelected = false
         val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams
         val layoutParams = binding.messageTime.layoutParams as FlexboxLayout.LayoutParams
         layoutParams.isWrapBefore = false
         layoutParams.isWrapBefore = false
         var textSize = context!!.resources.getDimension(R.dimen.chat_text_size)
         var textSize = context!!.resources.getDimension(R.dimen.chat_text_size)
         val textColor = viewThemeUtils.getScheme(binding.messageText.context).onSurfaceVariant
         val textColor = viewThemeUtils.getScheme(binding.messageText.context).onSurfaceVariant
+        binding.messageTime.setTextColor(textColor)
 
 
-        var processedMessageText = DisplayUtils.getRenderedMarkdownText(context, message.message)
+        var processedMessageText = messageUtils.enrichChatMessageText(binding.messageText.context, message, textColor)
+        processedMessageText = messageUtils.processMessageParameters(
+            binding.messageText.context,
+            viewThemeUtils,
+            processedMessageText!!,
+            message,
+            itemView
+        )
 
 
-        binding.messageTime.setTextColor(textColor)
-        if (messageParameters != null && messageParameters.size > 0) {
-            processedMessageText = processMessageParameters(messageParameters, message, processedMessageText)
-        } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.text)) {
+        val messageParameters = message.messageParameters
+        if (
+            (messageParameters == null || messageParameters.size <= 0) &&
+            TextMatchers.isMessageWithSingleEmoticonOnly(message.text)
+        ) {
             textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat()
             textSize = (textSize * TEXT_SIZE_MULTIPLIER).toFloat()
             layoutParams.isWrapBefore = true
             layoutParams.isWrapBefore = true
             realView.isSelected = true
             realView.isSelected = true
@@ -165,7 +174,12 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH
         }
         }
         binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
         binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
             ?: context!!.getText(R.string.nc_nick_guest)
             ?: 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.quotedMessageAuthor.setTextColor(textColor)
         binding.messageQuote.quotedMessage.setTextColor(textColor)
         binding.messageQuote.quotedMessage.setTextColor(textColor)
@@ -181,46 +195,6 @@ class OutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessageViewH
         viewThemeUtils.talk.themeOutgoingMessageBubble(bubble, message.isGrouped, message.isDeleted)
         viewThemeUtils.talk.themeOutgoingMessageBubble(bubble, message.isGrouped, message.isDeleted)
     }
     }
 
 
-    private fun processMessageParameters(
-        messageParameters: HashMap<String?, HashMap<String?, String?>>,
-        message: ChatMessage,
-        messageString: Spanned
-    ): Spanned {
-        var messageStringInternal = messageString
-        for (key in messageParameters.keys) {
-            val individualHashMap: HashMap<String?, String?>? = 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) {
     fun assignCommonMessageInterface(commonMessageInterface: CommonMessageInterface) {
         this.commonMessageInterface = commonMessageInterface
         this.commonMessageInterface = commonMessageInterface
     }
     }

+ 10 - 1
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.ui.theme.ViewThemeUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.DateUtils
 import com.nextcloud.talk.utils.DateUtils
+import com.nextcloud.talk.utils.message.MessageUtils
 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 java.util.concurrent.ExecutionException
 import java.util.concurrent.ExecutionException
@@ -63,6 +64,9 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
     @Inject
     @Inject
     lateinit var viewThemeUtils: ViewThemeUtils
     lateinit var viewThemeUtils: ViewThemeUtils
 
 
+    @Inject
+    lateinit var messageUtils: MessageUtils
+
     @Inject
     @Inject
     lateinit var dateUtils: DateUtils
     lateinit var dateUtils: DateUtils
 
 
@@ -271,7 +275,12 @@ class OutcomingVoiceMessageViewHolder(outcomingView: View) :
             }
             }
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
             binding.messageQuote.quotedMessageAuthor.text = parentChatMessage.actorDisplayName
                 ?: context!!.getText(R.string.nc_nick_guest)
                 ?: 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.colorOutgoingQuoteText(binding.messageQuote.quotedMessage)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
             viewThemeUtils.talk.colorOutgoingQuoteAuthorText(binding.messageQuote.quotedMessageAuthor)
             viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)
             viewThemeUtils.talk.colorOutgoingQuoteBackground(binding.messageQuote.quoteColoredView)

+ 7 - 0
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 android.content.Context
 import com.nextcloud.talk.utils.DateUtils
 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.PlatformPermissionUtil
 import com.nextcloud.talk.utils.permissions.PlatformPermissionUtilImpl
 import com.nextcloud.talk.utils.permissions.PlatformPermissionUtilImpl
 import dagger.Module
 import dagger.Module
@@ -42,4 +43,10 @@ class UtilsModule {
     fun provideDateUtils(context: Context): DateUtils {
     fun provideDateUtils(context: Context): DateUtils {
         return DateUtils(context)
         return DateUtils(context)
     }
     }
+
+    @Provides
+    @Reusable
+    fun provideMessageUtils(context: Context): MessageUtils {
+        return MessageUtils(context)
+    }
 }
 }

+ 0 - 27
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.ClickableSpan;
 import android.text.style.ForegroundColorSpan;
 import android.text.style.ForegroundColorSpan;
 import android.text.style.StyleSpan;
 import android.text.style.StyleSpan;
-import android.util.Log;
 import android.util.TypedValue;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.View;
 import android.view.Window;
 import android.view.Window;
@@ -88,11 +87,6 @@ import coil.Coil;
 import coil.request.ImageRequest;
 import coil.request.ImageRequest;
 import coil.target.Target;
 import coil.target.Target;
 import coil.transform.CircleCropTransformation;
 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 third.parties.fresco.BetterImageSpan;
 
 
 import static com.nextcloud.talk.utils.FileSortOrder.sort_a_to_z_id;
 import static com.nextcloud.talk.utils.FileSortOrder.sort_a_to_z_id;
@@ -253,27 +247,6 @@ public class DisplayUtils {
         return chip;
         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,
     public static Spannable searchAndReplaceWithMentionSpan(String key, Context context, Spanned text,
                                                             String id, String label, String type,
                                                             String id, String label, String type,
                                                             User conversationUser,
                                                             User conversationUser,

+ 145 - 0
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 <info@andy-scherzinger.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+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<String?, HashMap<String?, String?>>,
+        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"
+    }
+}