Extend workaround for extra new lines in timeline (#8187)

* Extend workaround for extra new lines in timeline

Closes vector-im/element-android#8179

Caused by noties/Markwon#423

* Refactor

Co-authored-by: Yoan Pintas <y.pintas@gmail.com>

---------

Co-authored-by: Yoan Pintas <y.pintas@gmail.com>
This commit is contained in:
jonnyandrew 2023-03-06 16:03:53 +00:00 committed by GitHub
parent 8595bd2be8
commit 29f2bf25fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 6 deletions

1
changelog.d/8187.bugfix Normal file
View File

@ -0,0 +1 @@
Extend workaround for extra new lines in timeline

View File

@ -20,6 +20,7 @@ import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.text.Layout import android.text.Layout
import android.text.Spanned import android.text.Spanned
import android.text.style.StrikethroughSpan
import androidx.core.text.getSpans import androidx.core.text.getSpans
import im.vector.app.features.html.HtmlCodeSpan import im.vector.app.features.html.HtmlCodeSpan
import io.element.android.wysiwyg.spans.InlineCodeSpan import io.element.android.wysiwyg.spans.InlineCodeSpan
@ -28,6 +29,7 @@ import io.mockk.mockk
import io.mockk.slot import io.mockk.slot
import io.mockk.verify import io.mockk.verify
import io.noties.markwon.core.spans.EmphasisSpan import io.noties.markwon.core.spans.EmphasisSpan
import io.noties.markwon.core.spans.LinkSpan
import io.noties.markwon.core.spans.OrderedListItemSpan import io.noties.markwon.core.spans.OrderedListItemSpan
import io.noties.markwon.core.spans.StrongEmphasisSpan import io.noties.markwon.core.spans.StrongEmphasisSpan
import me.gujun.android.span.style.CustomTypefaceSpan import me.gujun.android.span.style.CustomTypefaceSpan
@ -59,6 +61,8 @@ private fun Any.readTags(): SpanTags {
StrongEmphasisSpan::class -> "bold" StrongEmphasisSpan::class -> "bold"
EmphasisSpan::class, CustomTypefaceSpan::class -> "italic" EmphasisSpan::class, CustomTypefaceSpan::class -> "italic"
InlineCodeSpan::class -> "inline code" InlineCodeSpan::class -> "inline code"
StrikethroughSpan::class -> "strikethrough"
LinkSpan::class -> "link"
else -> if (this::class.qualifiedName!!.startsWith("android.widget")) { else -> if (this::class.qualifiedName!!.startsWith("android.widget")) {
null null
} else { } else {

View File

@ -73,6 +73,30 @@ class EventHtmlRendererTest {
result shouldBeEqualTo "__italic__ **bold**" result shouldBeEqualTo "__italic__ **bold**"
} }
// https://github.com/noties/Markwon/issues/423
@Test
fun doesNotIntroduceExtraNewLines() {
// Given initial render (required to trigger bug)
"""Some <i>italic</i>""".renderAsTestSpan()
val results = arrayOf(
"""Some <i>italic</i>""".renderAsTestSpan(),
"""Some <b>bold</b>""".renderAsTestSpan(),
"""Some <code>code</code>""".renderAsTestSpan(),
"""Some <a href="link">link</a>""".renderAsTestSpan(),
"""Some <del>strikethrough</del>""".renderAsTestSpan(),
"""Some <span>span</span>""".renderAsTestSpan(),
)
results shouldBeEqualTo arrayOf(
"Some [italic]italic[/italic]",
"Some [bold]bold[/bold]",
"Some [inline code]code[/inline code]",
"Some [link]link[/link]",
"Some \n[strikethrough]strikethrough[/strikethrough]", // FIXME
"Some \nspan", // FIXME
)
}
@Test @Test
fun processesHtmlWithinCodeBlocks() { fun processesHtmlWithinCodeBlocks() {
val result = """<code><i>italic</i> <b>bold</b></code>""".renderAsTestSpan() val result = """<code><i>italic</i> <b>bold</b></code>""".renderAsTestSpan()

View File

@ -31,6 +31,9 @@ import android.graphics.Typeface
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.text.Spannable import android.text.Spannable
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.style.StrikethroughSpan
import android.text.style.URLSpan
import android.text.style.UnderlineSpan
import android.widget.TextView import android.widget.TextView
import androidx.core.text.toSpannable import androidx.core.text.toSpannable
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
@ -46,6 +49,8 @@ import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonPlugin import io.noties.markwon.MarkwonPlugin
import io.noties.markwon.MarkwonSpansFactory import io.noties.markwon.MarkwonSpansFactory
import io.noties.markwon.PrecomputedFutureTextSetterCompat import io.noties.markwon.PrecomputedFutureTextSetterCompat
import io.noties.markwon.core.spans.EmphasisSpan
import io.noties.markwon.core.spans.StrongEmphasisSpan
import io.noties.markwon.ext.latex.JLatexMathPlugin import io.noties.markwon.ext.latex.JLatexMathPlugin
import io.noties.markwon.ext.latex.JLatexMathTheme import io.noties.markwon.ext.latex.JLatexMathTheme
import io.noties.markwon.html.HtmlPlugin import io.noties.markwon.html.HtmlPlugin
@ -154,14 +159,24 @@ class EventHtmlRenderer @Inject constructor(
/** /**
* Workaround for https://github.com/noties/Markwon/issues/423 * Workaround for https://github.com/noties/Markwon/issues/423
*/ */
private val removeLeadingNewlineForInlineCode = object : AbstractMarkwonPlugin() { private val removeLeadingNewlineForInlineElement = object : AbstractMarkwonPlugin() {
override fun afterSetText(textView: TextView) { override fun afterSetText(textView: TextView) {
super.afterSetText(textView) super.afterSetText(textView)
val text = SpannableStringBuilder(textView.text.toSpannable()) val text = SpannableStringBuilder(textView.text.toSpannable())
val inlineCodeSpans = text.getSpans(0, textView.length(), InlineCodeSpan::class.java).toList() val length = textView.length()
val legacyInlineCodeSpans = text.getSpans(0, textView.length(), HtmlCodeSpan::class.java).filter { !it.isBlock } val spans = arrayOf(
val spans = inlineCodeSpans + legacyInlineCodeSpans InlineCodeSpan::class.java,
EmphasisSpan::class.java,
CustomTypefaceSpan::class.java,
StrongEmphasisSpan::class.java,
UnderlineSpan::class.java,
URLSpan::class.java,
StrikethroughSpan::class.java
).map { text.getSpans(0, length, it) }
.toTypedArray()
.plus(text.getSpans(0, length, HtmlCodeSpan::class.java).filter { !it.isBlock }.toTypedArray())
.flatten()
if (spans.isEmpty()) return if (spans.isEmpty()) return
@ -179,11 +194,11 @@ class EventHtmlRenderer @Inject constructor(
private val markwon = Markwon.builder(context) private val markwon = Markwon.builder(context)
.usePlugin(HtmlRootTagPlugin()) .usePlugin(HtmlRootTagPlugin())
.usePlugin(HtmlPlugin.create(htmlConfigure)) .usePlugin(HtmlPlugin.create(htmlConfigure))
.usePlugin(removeLeadingNewlineForInlineCode) .usePlugin(removeLeadingNewlineForInlineElement)
.usePlugin(glidePlugin) .usePlugin(glidePlugin)
.apply { .apply {
if (vectorPreferences.latexMathsIsEnabled()) { if (vectorPreferences.latexMathsIsEnabled()) {
// If latex maths is enabled in app preferences, refomat it so Markwon recognises it // If latex maths is enabled in app preferences, reformat it so Markwon recognises it
// It needs to be in this specific format: https://noties.io/Markwon/docs/v4/ext-latex // It needs to be in this specific format: https://noties.io/Markwon/docs/v4/ext-latex
latexPlugins.forEach(::usePlugin) latexPlugins.forEach(::usePlugin)
} }