fix(ui): apply "any-RTL" algorithm for correct text direction on some `Text`s (#732)

* fix(ui): apply "any-RTL" algorithm for correct direction on some `Text`s

* Update Type.kt
This commit is contained in:
junkfood 2024-06-05 19:42:29 +09:00 committed by GitHub
parent 0d0477e4ff
commit 3c8e11f086
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 37 additions and 8 deletions

View File

@ -30,7 +30,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -46,6 +46,7 @@ import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.BaselineShift
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import coil.size.Precision
@ -54,6 +55,8 @@ import coil.size.pxOrElse
import me.ash.reader.R
import me.ash.reader.infrastructure.preference.LocalReadingImageMaximize
import me.ash.reader.ui.component.base.RYAsyncImage
import me.ash.reader.ui.ext.requiresBidi
import me.ash.reader.ui.theme.applyTextDirection
import org.jsoup.Jsoup
import org.jsoup.helper.StringUtil
import org.jsoup.nodes.Element
@ -96,6 +99,8 @@ private fun LazyListScope.formatBody(
val composer = TextComposer { paragraphBuilder ->
item {
val paragraph = paragraphBuilder.toAnnotatedString()
val requiresBidi = paragraph.toString().requiresBidi()
val textStyle = bodyStyle().applyTextDirection(requiresBidi = requiresBidi)
// ClickableText prevents taps from deselecting selected text
// So use regular Text if possible
@ -104,7 +109,7 @@ private fun LazyListScope.formatBody(
) {
ClickableText(
text = paragraph,
style = bodyStyle(),
style = textStyle,
modifier = Modifier
.padding(horizontal = textHorizontalPadding().dp)
.width(MAX_CONTENT_WIDTH.dp)
@ -118,7 +123,7 @@ private fun LazyListScope.formatBody(
} else {
Text(
text = paragraph,
style = bodyStyle(),
style = textStyle,
modifier = Modifier
.padding(horizontal = textHorizontalPadding().dp)
.width(MAX_CONTENT_WIDTH.dp)

View File

@ -4,6 +4,7 @@ import android.text.Html
import android.util.Base64
import java.math.BigInteger
import java.security.MessageDigest
import java.text.Bidi
object MimeType {
@ -47,6 +48,9 @@ fun String?.decodeHTML(): String? = this?.run { Html.fromHtml(this).toString() }
fun String?.orNotEmpty(l: (value: String) -> String): String =
if (this.isNullOrBlank()) "" else l(this)
fun String.requiresBidi(): Boolean = Bidi.requiresBidi(this.toCharArray(), 0, this.length)
fun String?.extractDomain(): String {
if (this.isNullOrBlank()) return ""
val urlMatchResult = Regex("(?<=://)([\\w\\d.-]+)").find(this)
@ -56,4 +60,4 @@ fun String?.extractDomain(): String {
val domainRegex = Regex("[\\w\\d.-]+\\.[\\w\\d.-]+")
val domainMatchResult = domainRegex.find(this)
return domainMatchResult?.value ?: ""
}
}

View File

@ -60,10 +60,10 @@ import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import coil.size.Precision
import coil.size.Scale
@ -84,9 +84,11 @@ import me.ash.reader.ui.component.FeedIcon
import me.ash.reader.ui.component.base.RYAsyncImage
import me.ash.reader.ui.component.base.SIZE_1000
import me.ash.reader.ui.component.menu.AnimatedDropdownMenu
import me.ash.reader.ui.ext.requiresBidi
import me.ash.reader.ui.ext.surfaceColorAtElevation
import me.ash.reader.ui.page.settings.color.flow.generateArticleWithFeedPreview
import me.ash.reader.ui.theme.Shape20
import me.ash.reader.ui.theme.applyTextDirection
import me.ash.reader.ui.theme.palette.onDark
@Composable
@ -230,7 +232,7 @@ fun ArticleItem(
Text(
text = title,
color = MaterialTheme.colorScheme.onSurface,
style = MaterialTheme.typography.titleMedium,
style = MaterialTheme.typography.titleMedium.applyTextDirection(title.requiresBidi()),
maxLines = if (articleListDesc.value) 2 else 4,
overflow = TextOverflow.Ellipsis,
)
@ -241,7 +243,9 @@ fun ArticleItem(
modifier = Modifier.padding(top = 4.dp),
text = shortDescription,
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodySmall,
style = MaterialTheme.typography.bodySmall.applyTextDirection(
shortDescription.requiresBidi()
),
maxLines = 2,
overflow = TextOverflow.Ellipsis,
)

View File

@ -11,11 +11,15 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.unit.dp
import me.ash.reader.infrastructure.preference.*
import me.ash.reader.ui.component.reader.bodyStyle
import me.ash.reader.ui.ext.formatAsString
import me.ash.reader.ui.ext.openURL
import me.ash.reader.ui.ext.requiresBidi
import me.ash.reader.ui.ext.roundClick
import me.ash.reader.ui.theme.applyTextDirection
import java.util.*
@Composable
@ -65,6 +69,8 @@ fun Metadata(
style = MaterialTheme.typography.headlineLarge.copy(
fontFamily = LocalReadingFonts.current.asFontFamily(context),
fontWeight = if (titleBold.value) FontWeight.SemiBold else FontWeight.Normal,
).applyTextDirection(
requiresBidi = title.requiresBidi()
),
textAlign = titleAlign.toTextAlign(),
)

View File

@ -5,6 +5,7 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.unit.sp
import java.text.Bidi
// TODO: Rename file to Typography.kt and add @Stable
@ -101,7 +102,16 @@ val SystemTypography = Typography(
),
)
internal fun TextStyle.applyTextDirection() = this.copy(textDirection = TextDirection.Content)
internal fun TextStyle.applyTextDirection(textDirection: TextDirection = TextDirection.Content) =
this.copy(textDirection = textDirection)
/**
* Resolve the text to Rtl if the text requires BiDirectional
* @see [android.view.View.TEXT_DIRECTION_ANY_RTL]
* @see [Bidi.requiresBidi]
*/
fun TextStyle.applyTextDirection(requiresBidi: Boolean) =
this.applyTextDirection(textDirection = if (requiresBidi) TextDirection.Rtl else TextDirection.Ltr)
internal fun Typography.applyTextDirection() = this.copy(
displayLarge = displayLarge.applyTextDirection(),