From 18c0cbb32a1f4a94691cb6e15802267b5a1a8d34 Mon Sep 17 00:00:00 2001 From: Ahmed Elshahawy Date: Thu, 11 Jan 2024 02:24:25 +0100 Subject: [PATCH] [Fix] annotatedStringResource with args don't render annotation styles#253 --- .../spark/res/AnnotatedStringResource.kt | 43 +++++++++---------- spark/src/main/res/values-fr/strings.xml | 2 +- spark/src/main/res/values/strings.xml | 2 +- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/spark/src/main/kotlin/com/adevinta/spark/res/AnnotatedStringResource.kt b/spark/src/main/kotlin/com/adevinta/spark/res/AnnotatedStringResource.kt index 034593f05..9e8b64520 100644 --- a/spark/src/main/kotlin/com/adevinta/spark/res/AnnotatedStringResource.kt +++ b/spark/src/main/kotlin/com/adevinta/spark/res/AnnotatedStringResource.kt @@ -59,6 +59,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em +import androidx.core.text.buildSpannedString import androidx.core.text.parseAsHtml import androidx.core.text.toHtml import com.adevinta.spark.PreviewTheme @@ -66,9 +67,8 @@ import com.adevinta.spark.R import com.adevinta.spark.SparkTheme import com.adevinta.spark.tokens.SparkColors import com.adevinta.spark.tokens.SparkTypography - -// FIXME: There is no official way to do this yet so we're waiting for -// https://issuetracker.google.com/issues/139320238 to be fixed +import kotlinx.collections.immutable.PersistentMap +import kotlinx.collections.immutable.persistentMapOf /** * Load a annotated string resource with formatting. @@ -80,17 +80,25 @@ import com.adevinta.spark.tokens.SparkTypography * @return the [AnnotatedString] data associated with the resource */ @Composable -public fun annotatedStringResource(@StringRes id: Int, vararg formatArgs: Any): AnnotatedString { +public fun annotatedStringResource(@StringRes id: Int, formatArgs: PersistentMap): AnnotatedString { val resources = resources() val density = LocalDensity.current val colors = SparkTheme.colors val typography = SparkTheme.typography return remember(id, formatArgs) { - val text = resources.getText(id, *formatArgs) - text.asAnnotatedString(density, colors, typography) + resources.buildSpannedStringWithArgs(id, formatArgs).asAnnotatedString(density, colors, typography) } } +private fun Resources.buildSpannedStringWithArgs( + @StringRes id: Int, + args: PersistentMap, +): SpannedString = buildSpannedString { + append(getText(id)) + getSpans(0, length, Annotation::class.java).filterIsInstance().filter { it.key == "variable" } + .forEach { replace(getSpanStart(it), getSpanEnd(it), args.getValue(it.value)) } +} + /** * Load a annotated string resource. * @@ -163,22 +171,6 @@ internal fun resources(): Resources { return LocalContext.current.resources } -/** - * The framework `getText()` method doesn't support formatting arguments, so we need to do it ourselves. - * - * Unfortunately `toHtml()` doesn't support the `` tag so we loose this span as we need to convert it to a - * [String] to be able to use `String.format()`. - */ -internal fun Resources.getText(@StringRes id: Int, vararg args: Any): CharSequence { - val escapedArgs = args.map { - if (it is Spanned) it.toHtmlWithoutParagraphs() else it - }.toTypedArray() - val spannedString = SpannedString(getText(id)) - val htmlResource = spannedString.toHtmlWithoutParagraphs() - val formattedHtml = String.format(htmlResource, *escapedArgs) - return formattedHtml.parseAsHtml() -} - internal fun Resources.getQuantityText(@PluralsRes id: Int, quantity: Int, vararg args: Any): CharSequence { val escapedArgs = args.map { if (it is Spanned) it.toHtmlWithoutParagraphs() else it @@ -275,6 +267,11 @@ private fun AnnotatedStringResourcePreview() { Text( text = annotatedStringResource(R.string.spark_annotatedStringResource_test), ) - Text(annotatedStringResource(R.string.spark_annotatedStringResource_test_args, "Spark")) + Text( + text = annotatedStringResource( + R.string.spark_annotatedStringResource_test_args, + persistentMapOf("who" to "Bob"), + ), + ) } } diff --git a/spark/src/main/res/values-fr/strings.xml b/spark/src/main/res/values-fr/strings.xml index 42816e507..0af4839c5 100644 --- a/spark/src/main/res/values-fr/strings.xml +++ b/spark/src/main/res/values-fr/strings.xml @@ -54,7 +54,7 @@ Les Meilleures pratiques pour les textes sur Android - Les Meilleures pratiques

pour les %s sur

Android

+ Salut, who! Obligatoire diff --git a/spark/src/main/res/values/strings.xml b/spark/src/main/res/values/strings.xml index 05df2eb63..5c72bec53 100644 --- a/spark/src/main/res/values/strings.xml +++ b/spark/src/main/res/values/strings.xml @@ -50,7 +50,7 @@ Best practices

for text on

Android
- Best practices

for %s on

Android
+ Hello, who! Mandatory