Skip to content

Commit

Permalink
Android: split editor and message HTML parsing modes
Browse files Browse the repository at this point in the history
When we translated HTML to spans in Android, we want the paragraph tags (`<p>`) to translate to a double line break ( `\n\n`) since Android doesn't have support for inter-paragraph spacing and we need to simulate this by using this workaround.

However, this is not something we can support in the actual editor since it would break the index matching, add new points in the text that can be selected, removed, etc. and would make it crash.

So we end up having to differentiate between HTML parsing for the editor and HTML parsing to display in messages to support this change. Also, this means the rendering on the editor and what's rendered later for the sent message might not match 1:1 as until now.
  • Loading branch information
jmartinesp committed Nov 25, 2024
1 parent 0fc68b5 commit cbfcfcb
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class MainActivity : ComponentActivity() {
StyledHtmlConverter(
context = context,
mentionDisplayHandler = mentionDisplayHandler,
isEditor = false,
isMention = mentionDetector?.let { detector ->
{ _, url ->
detector.isMention(url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,9 @@ class RichTextEditor : LinearLayout {
val rooms = listOf("matrix", "element").map(Mention::Room)
val everyone = Mention.NotifyEveryone
val names = when (menuAction.suggestionPattern.key) {
PatternKey.AT -> people + everyone
PatternKey.HASH -> rooms
PatternKey.SLASH ->
PatternKey.At -> people + everyone
PatternKey.Hash -> rooms
PatternKey.Slash, is PatternKey.Custom ->
emptyList() // TODO
}
val suggestions = names
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import timber.log.Timber
class StyledHtmlConverter(
private val context: Context,
private val mentionDisplayHandler: MentionDisplayHandler?,
private val isEditor: Boolean,
private val isMention: ((text: String, url: String) -> Boolean)?,
) : HtmlConverter {

Expand All @@ -31,6 +32,7 @@ class StyledHtmlConverter(
context = context,
styleConfig = style.toStyleConfig(context),
mentionDisplayHandler = mentionDisplayHandler,
isEditor = isEditor,
isMention = isMention,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class InterceptInputConnectionIntegrationTest {
it.htmlConverter = HtmlConverter.Factory.create(
context = app,
styleConfig = styleConfig,
isEditor = true,
mentionDisplayHandler = null,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class EditorEditText : AppCompatEditText {
context = context.applicationContext,
styleConfig = styleConfig,
mentionDisplayHandler = mentionDisplayHandler,
isEditor = true,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ open class EditorStyledTextView : AppCompatTextView {
return HtmlConverter.Factory.create(context = context,
styleConfig = styleConfig,
mentionDisplayHandler = mentionDisplayHandler,
isEditor = false,
isMention = mentionDetector?.let { detector ->
{ _, url ->
detector.isMention(url)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface HtmlConverter {
context: Context,
styleConfig: StyleConfig,
mentionDisplayHandler: MentionDisplayHandler?,
isEditor: Boolean,
isMention: ((text: String, url: String) -> Boolean)? = null,
): HtmlConverter {
val resourcesProvider = AndroidResourcesHelper(context)
Expand All @@ -32,6 +33,7 @@ interface HtmlConverter {
html = html,
styleConfig = styleConfig,
mentionDisplayHandler = mentionDisplayHandler,
isEditor = isEditor,
isMention = isMention,
)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ internal class HtmlToSpansParser(
private val html: String,
private val styleConfig: StyleConfig,
private val mentionDisplayHandler: MentionDisplayHandler?,
private val isEditor: Boolean,
private val isMention: ((text: String, url: String) -> Boolean)? = null,
) {
private val safeList = Safelist()
Expand Down Expand Up @@ -301,6 +302,10 @@ internal class HtmlToSpansParser(
private fun SpannableStringBuilder.addLeadingLineBreakForBlockNode(element: Element) {
if (element.isBlock && element.previousElementSibling()?.takeIf { it.tagName() != "br" } != null) {
append('\n')
// If we're not in editor mode, add another line break to separate blocks
if (!isEditor) {
append('\n')
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,43 @@ class HtmlToSpansParserTest {
)
}

@Test
fun testParagraphsAreTranslatedToSingleLineBreakWhenEditorModeIsEnabled() {
val html = """
<p>Hello</p><p>World!</p>
""".trimIndent()
val spanned = convertHtml(html, isEditor = true, mentionDisplayHandler = object : MentionDisplayHandler {
override fun resolveAtRoomMentionDisplay(): TextDisplay =
TextDisplay.Pill

override fun resolveMentionDisplay(text: String, url: String): TextDisplay =
TextDisplay.Pill
})
assertThat(
spanned.toString(), equalTo("Hello\nWorld!")
)
}

@Test
fun testParagraphsAreTranslatedToDoubleLineBreakWhenEditorModeIsDisabled() {
val html = """
<p>Hello</p><p>World!</p>
""".trimIndent()
val spanned = convertHtml(html, isEditor = false, mentionDisplayHandler = object : MentionDisplayHandler {
override fun resolveAtRoomMentionDisplay(): TextDisplay =
TextDisplay.Pill

override fun resolveMentionDisplay(text: String, url: String): TextDisplay =
TextDisplay.Pill
})
assertThat(
spanned.toString(), equalTo("Hello\n\nWorld!")
)
}

private fun convertHtml(
html: String,
isEditor: Boolean = true,
mentionDisplayHandler: MentionDisplayHandler? = null,
): Spanned {
val app = RuntimeEnvironment.getApplication()
Expand All @@ -191,6 +226,7 @@ class HtmlToSpansParserTest {
html = html,
styleConfig = styleConfig,
mentionDisplayHandler = mentionDisplayHandler,
isEditor = isEditor,
isMention = { _, url ->
url.startsWith("https://matrix.to/#/@")
}
Expand Down

0 comments on commit cbfcfcb

Please sign in to comment.