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 fad7b0e4af..fe05df008e 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 @@ -106,6 +106,10 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : viewThemeUtils ) + message.message?.let { + messageUtils.hyperLinks(binding.messageText, message.message!!) + } + val spansFromString: Array = processedMessageText!!.getSpans( 0, processedMessageText.length, @@ -135,6 +139,7 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) : message, itemView ) + val messageParameters = message.messageParameters if ( (messageParameters == null || messageParameters.size <= 0) && 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 412dcfbbf8..10de0843a0 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 @@ -117,6 +117,10 @@ class OutcomingTextMessageViewHolder(itemView: View) : viewThemeUtils ) + message.message?.let { + messageUtils.hyperLinks(binding.messageText, message.message!!) + } + val spansFromString: Array = processedMessageText!!.getSpans( 0, processedMessageText.length, diff --git a/app/src/main/java/com/nextcloud/talk/utils/MarkdownUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/MarkdownUtils.kt new file mode 100644 index 0000000000..8248caa535 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/MarkdownUtils.kt @@ -0,0 +1,59 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2025 Sowjanya Kota + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package com.nextcloud.talk.utils + +import android.content.Context +import android.content.Intent +import android.util.Log +import android.view.View +import androidx.core.net.toUri +import com.nextcloud.talk.R +import io.noties.markwon.AbstractMarkwonPlugin +import io.noties.markwon.LinkResolverDef +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 + +object MarkdownUtils { + private const val TAG = "MarkdownUtils" + + fun build(context: Context, textColor: Int): Markwon { + val drawable = TaskListDrawable(textColor, textColor, context.getColor(R.color.bg_default)) + return 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(object : LinkResolverDef() { + override fun resolve(view: View, link: String) { + Log.i(TAG, "Link - $view / $link") + var linkToOpen = link + if (!(linkToOpen.contains("http://") || linkToOpen.contains("https://"))) { + linkToOpen = "https://$link" + } + val browserIntent = Intent( + Intent.ACTION_VIEW, + linkToOpen.toUri() + ) + context.startActivity(browserIntent) + } + }) + } + }) + .usePlugin(TaskListPlugin.create(drawable)) + .usePlugin(StrikethroughPlugin.create()) + .usePlugin(TablePlugin.create { _ -> }) + .build() + } +} 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 index 6beeafecab..9a6547aff7 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/message/MessageUtils.kt @@ -13,21 +13,14 @@ import android.text.SpannableString import android.text.SpannableStringBuilder import android.text.Spanned import android.text.style.StyleSpan -import android.util.Log import android.view.View +import android.widget.TextView import androidx.core.net.toUri import com.nextcloud.talk.R import com.nextcloud.talk.chat.data.model.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 +import com.nextcloud.talk.utils.MarkdownUtils class MessageUtils(val context: Context) { fun enrichChatReplyMessageText( @@ -203,26 +196,27 @@ class MessageUtils(val context: Context) { } 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(TaskListPlugin.create(drawable)) - .usePlugin(TablePlugin.create { _ -> }) - .usePlugin(StrikethroughPlugin.create()).build() + val markwon = MarkdownUtils.build(context, textColor) return markwon.toMarkdown(markdown) } + fun isMarkdownInlineLink(text: String): Boolean { + val markdownLinkRegex = Regex("""\[([^\]]+?)]\((.*?)(?:\s+"[^"]*")?\)""") + return markdownLinkRegex.containsMatchIn(text) + } + + fun hyperLinks(view: TextView, text: String) { + val isMarkdownLink = isMarkdownInlineLink(text) + if (isMarkdownLink) { + view.autoLinkMask = AUTO_LINK_NONE + } else { + view.autoLinkMask = AUTO_LINK_ALL + } + } companion object { private const val TAG = "MessageUtils" const val MAX_REPLY_LENGTH = 250 + const val AUTO_LINK_NONE = 0 + const val AUTO_LINK_ALL = 15 } }