From 0d9399a1a45da32b86c043fa5323866bcd040b18 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 13 Jul 2023 19:23:26 -0400 Subject: [PATCH] Fixing Right To Left Text --- .../amethyst/service/CachedRichTextParser.kt | 18 +++--- .../amethyst/ui/components/RichTextViewer.kt | 64 ++++++++++++------- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt index 1c18c56c3..163ffc0ea 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt @@ -30,9 +30,11 @@ data class RichTextViewerState( val imagesForPager: ImmutableMap, val imageList: ImmutableList, val customEmoji: ImmutableMap, - val paragraphs: ImmutableList> + val paragraphs: ImmutableList ) +data class ParagraphState(val words: ImmutableList, val isRTL: Boolean) + object CachedRichTextParser { val richTextCache = LruCache(200) @@ -108,13 +110,15 @@ class RichTextParser() { ) } - private fun findTextSegments(content: String, images: Set, urls: Set, emojis: Map, tags: ImmutableListOfLists): ImmutableList> { - var paragraphSegments = persistentListOf>() + private fun findTextSegments(content: String, images: Set, urls: Set, emojis: Map, tags: ImmutableListOfLists): ImmutableList { + var paragraphSegments = persistentListOf() content.split('\n').forEach { paragraph -> var segments = persistentListOf() var isDirty = false + val isRTL = isArabic(paragraph) + val wordList = paragraph.split(' ') wordList.forEach { word -> val wordSegment = wordIdentifier(word, images, urls, emojis, tags) @@ -125,13 +129,9 @@ class RichTextParser() { } val newSegments = if (isDirty) { - if (isArabic(paragraph)) { - segments.asReversed().toImmutableList() - } else { - segments - } + ParagraphState(segments, isRTL) } else { - persistentListOf(RegularTextSegment(paragraph)) + ParagraphState(persistentListOf(RegularTextSegment(paragraph)), isRTL) } paragraphSegments = paragraphSegments.add(newSegments) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index 953bc2deb..c366bdfb3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -17,16 +17,19 @@ import androidx.compose.material.ProvideTextStyle import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.takeOrElse import androidx.compose.ui.layout.SubcomposeLayout +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.* import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.em import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.map @@ -136,7 +139,6 @@ private fun RenderRegular( val currentTextStyle = LocalTextStyle.current val textStyle = currentTextStyle.copy( - textDirection = TextDirection.Content, lineHeight = 1.4.em, color = currentTextStyle.color.takeOrElse { LocalContentColor.current.copy(alpha = LocalContentAlpha.current) @@ -144,36 +146,54 @@ private fun RenderRegular( ) MeasureSpaceWidth() { spaceWidth -> - Column { + Column() { if (canPreview) { // FlowRow doesn't work well with paragraphs. So we need to split them state.paragraphs.forEach { paragraph -> - FlowRow(horizontalArrangement = Arrangement.spacedBy(spaceWidth)) { - paragraph.forEach { word -> - RenderWordWithPreview( - word, - state, - backgroundColor, - textStyle, - accountViewModel, - nav - ) + val direction = if (paragraph.isRTL) { + LayoutDirection.Rtl + } else LayoutDirection.Ltr + + CompositionLocalProvider(LocalLayoutDirection provides direction) { + FlowRow( + modifier = Modifier.align(if (paragraph.isRTL) Alignment.End else Alignment.Start), + horizontalArrangement = Arrangement.spacedBy(spaceWidth) + ) { + paragraph.words.forEach { word -> + RenderWordWithPreview( + word, + state, + backgroundColor, + textStyle, + accountViewModel, + nav + ) + } } } } } else { // FlowRow doesn't work well with paragraphs. So we need to split them state.paragraphs.forEach { paragraph -> - FlowRow(horizontalArrangement = Arrangement.spacedBy(spaceWidth)) { - paragraph.forEach { word -> - RenderWordWithoutPreview( - word, - state, - backgroundColor, - textStyle, - accountViewModel, - nav - ) + val direction = if (paragraph.isRTL) { + LayoutDirection.Rtl + } else LayoutDirection.Ltr + + CompositionLocalProvider(LocalLayoutDirection provides direction) { + FlowRow( + horizontalArrangement = Arrangement.spacedBy(spaceWidth), + modifier = Modifier.align(if (paragraph.isRTL) Alignment.End else Alignment.Start), + ) { + paragraph.words.forEach { word -> + RenderWordWithoutPreview( + word, + state, + backgroundColor, + textStyle, + accountViewModel, + nav + ) + } } } }