().filter { it.key == "variable" }
+ .forEach { replace(getSpanStart(it), getSpanEnd(it), args.getValue(it.value)) }
}
@Composable
@@ -284,12 +275,29 @@ private fun Spanned.toHtmlWithoutParagraphs(): String = toHtml()
.substringAfter("")
.substringBeforeLast("
")
-private fun CharSequence.asAnnotatedString(
+@Suppress("UNCHECKED_CAST") // We're sure that we can only get a StringAnnotation
+private fun AnnotatedString.asAnnotatedString(
+ density: Density,
+ colors: SparkColors,
+ typography: SparkTypography,
+): AnnotatedString {
+ return mapAnnotations {
+ when(it.item) {
+ is StringAnnotation -> SparkStringAnnotations.toStyleAnnotation(
+ annotation = it as AnnotatedString.Range,
+ colors = colors,
+ typography = typography
+ )
+ else -> it
+ }
+ }
+}
+
+private fun SpannedString.asAnnotatedString(
density: Density,
colors: SparkColors,
typography: SparkTypography,
): AnnotatedString {
- if (this !is Spanned) return AnnotatedString(this.toString())
return buildAnnotatedString {
append(this@asAnnotatedString.toString())
getSpans(0, length, Any::class.java).forEach {
@@ -326,8 +334,8 @@ private fun AnnotatedString.Builder.buildWithSpan(
is SuperscriptSpan -> SpanStyle(baselineShift = BaselineShift.Superscript)
is SubscriptSpan -> SpanStyle(baselineShift = BaselineShift.Subscript)
is ForegroundColorSpan -> SpanStyle(color = Color(it.foregroundColor))
- is Annotation -> SparkStringAnnotations.toSpanStyle(annotation = it, colors, typography) ?: return
- else -> return
+// is Annotation -> SparkStringAnnotations.toSpanStyle(annotation = it, colors, typography) ?: return
+ else -> return/**/
}
addStyle(span, start, end)
}
@@ -368,5 +376,11 @@ private fun AnnotatedStringResourcePreview() {
persistentMapOf("who" to "Bob"),
),
)
+ Text(
+ text = annotatedStringResource(
+ R.string.spark_annotatedStringResource_test_new_args,
+ "Bob",
+ ),
+ )
}
}
diff --git a/spark/src/main/kotlin/com/adevinta/spark/res/SparkStringAnnotations.kt b/spark/src/main/kotlin/com/adevinta/spark/res/SparkStringAnnotations.kt
index 3dfeb3ff9..03b3f89e1 100644
--- a/spark/src/main/kotlin/com/adevinta/spark/res/SparkStringAnnotations.kt
+++ b/spark/src/main/kotlin/com/adevinta/spark/res/SparkStringAnnotations.kt
@@ -21,9 +21,13 @@
*/
package com.adevinta.spark.res
-import android.text.Annotation
import android.util.Log
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.AnnotatedString.Annotation
+import androidx.compose.ui.text.AnnotatedString.Range
import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.StringAnnotation
+import androidx.compose.ui.unit.TextUnit
import com.adevinta.spark.tokens.SparkColors
import com.adevinta.spark.tokens.SparkTypography
@@ -35,53 +39,89 @@ public object SparkStringAnnotations {
/**
* Given a string representing an annotation key and a string representing an annotation value, returns the corresponding [SpanStyle].
*/
- public fun toSpanStyle(
- annotation: Annotation,
+ public fun toStyleAnnotation(
+ annotation: Range,
colors: SparkColors,
typography: SparkTypography,
- ): SpanStyle? = when (annotation.key) {
- "color" -> annotation.value.toColorSpanStyle(colors)
- "typography" -> annotation.value.toTypographySpanStyle(typography)
- else -> null.also { _ ->
- Log.d("StringResources", "Annotation $this is not supported by spark")
+ ): Range = when (annotation.tag) {
+ "color" -> annotation.toColorSpanStyle(colors)
+ "typography" -> annotation.toTypographySpanStyle(typography)
+ "variable" -> annotation.toTypographySpanStyle(typography)
+ else -> annotation.also { _ ->
+ Log.d("StringResources", "Annotation ${annotation.tag} is not supported by spark")
}
}
/**
* Given a string representing annotation value of a spark color, returns the corresponding [SpanStyle] with the color token.
*/
- private fun String.toColorSpanStyle(token: SparkColors): SpanStyle? = when (this) {
- "main" -> token.main
- "support" -> token.support
- "success" -> token.success
- "alert" -> token.alert
- "error" -> token.error
- "info" -> token.info
- "neutral" -> token.neutral
- "accent" -> token.accent
- else -> null.also { _ ->
- Log.d("StringResources", "Spark color annotation : $this is not supported")
+ private fun Range.toColorSpanStyle(token: SparkColors): Range {
+ val color = when (this.item.value) {
+ "main" -> token.main
+ "support" -> token.support
+ "success" -> token.success
+ "alert" -> token.alert
+ "error" -> token.error
+ "info" -> token.info
+ "neutral" -> token.neutral
+ "accent" -> token.accent
+ else -> null.also { _ ->
+ Log.d("StringResources", "Spark color annotation : $this is not supported")
+ }
}
- }?.let(::SpanStyle)
+ return Range(
+ item = SpanStyle(
+ color = color ?: Color.Unspecified,
+ ),
+ start = start,
+ end = end,
+ tag = tag,
+ )
+ }
/**
* Given a string representing annotation value of a spark typography, returns the corresponding [SpanStyle] with the typography token.
*/
- private fun String.toTypographySpanStyle(token: SparkTypography): SpanStyle? = when (this) {
- "display1" -> token.display1
- "display2" -> token.display2
- "display3" -> token.display3
- "headline1" -> token.headline1
- "headline2" -> token.headline2
- "subhead" -> token.subhead
- "large" -> token.body1
- "body1" -> token.body1
- "body2" -> token.body2
- "caption" -> token.caption
- "small" -> token.small
- "callout" -> token.callout
- else -> null.also { _ ->
- Log.d("StringResources", "Spark typography annotation : $this is not supported")
+ private fun Range.toTypographySpanStyle(token: SparkTypography): Range {
+ val typography = when (this.item.value) {
+ "display1" -> token.display1
+ "display2" -> token.display2
+ "display3" -> token.display3
+ "headline1" -> token.headline1
+ "headline2" -> token.headline2
+ "subhead" -> token.subhead
+ "large" -> token.body1
+ "body1" -> token.body1
+ "body2" -> token.body2
+ "caption" -> token.caption
+ "small" -> token.small
+ "callout" -> token.callout
+ else -> null.also { _ ->
+ Log.d("StringResources", "Spark typography annotation : $this is not supported")
+ }
}
- }?.toSpanStyle()
+ return Range(
+ item = SpanStyle(
+ color = Color.Unspecified,
+ fontSize = typography?.fontSize ?: TextUnit.Unspecified,
+ fontWeight = typography?.fontWeight,
+ fontStyle = typography?.fontStyle,
+ fontSynthesis = typography?.fontSynthesis,
+ fontFamily = typography?.fontFamily,
+ fontFeatureSettings = typography?.fontFeatureSettings,
+ letterSpacing = typography?.letterSpacing ?: TextUnit.Unspecified,
+ baselineShift = typography?.baselineShift,
+ textGeometricTransform = typography?.textGeometricTransform,
+ localeList = typography?.localeList,
+ background = typography?.background ?: Color.Unspecified,
+ textDecoration = typography?.textDecoration,
+ shadow = typography?.shadow,
+ platformStyle = typography?.platformStyle?.spanStyle,
+ drawStyle = typography?.drawStyle,
+ ),
+ start = start,
+ end = end,
+ tag = tag,
+ )
+ }
}
diff --git a/spark/src/main/res/values-fr/strings.xml b/spark/src/main/res/values-fr/strings.xml
index 8f92c6461..761282fbb 100644
--- a/spark/src/main/res/values-fr/strings.xml
+++ b/spark/src/main/res/values-fr/strings.xml
@@ -60,8 +60,9 @@
Boîte de dialogue
- Les Meilleures pratiques pour les textes sur Android
+ Les <b>Meilleures</b> <annotation typography="large">pratiques</annotation> pour les textes sur <i><annotation color="main">Android</annotation></i>
Salut, who!
+ Salut, <b><annotation typography="large" color="main">%1$s</annotation></b>!
Champs requis
diff --git a/spark/src/main/res/values/strings.xml b/spark/src/main/res/values/strings.xml
index 868fa9030..5e6140d2d 100644
--- a/spark/src/main/res/values/strings.xml
+++ b/spark/src/main/res/values/strings.xml
@@ -56,8 +56,9 @@
Dialog
- Best practices for text on
Android
+ <b>Best</b> <annotation typography="large">practices</annotation> <p dir="rtl">for text on</p> <i><annotation color="main">Android</annotation></i>
Hello, who!
+ Hello, <b><annotation color="main" typography="large">%1$s</annotation></b>!
Mandatory