Skip to content

Instantly share code, notes, and snippets.

@Skaldebane
Last active April 22, 2025 01:34
Show Gist options
  • Save Skaldebane/fea5c8c24193c7b05c7f5bbd099a100b to your computer and use it in GitHub Desktop.
Save Skaldebane/fea5c8c24193c7b05c7f5bbd099a100b to your computer and use it in GitHub Desktop.
WaniKani radical/kanji/vocab/reading highlight colors for Compose.
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.*
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize
import androidx.compose.ui.window.singleWindowApplication
fun main() = singleWindowApplication {
val density = LocalDensity.current
val textMeasurer = rememberTextMeasurer()
val text = buildAnnotatedString {
append("Testing: ")
appendInlineContent(id = "radical-0", alternateText = "radical")
append("s, ")
appendInlineContent(id = "kanji-0", alternateText = "kanji")
append(", ")
appendInlineContent(id = "radical-1", alternateText = "another radical")
append(", ")
appendInlineContent(id = "vocab-0", alternateText = "vocab")
append(", and ")
appendInlineContent(id = "reading-0", alternateText = "reading")
append("s.")
}
val style = LocalTextStyle.current
Text(
text = text,
style = style,
inlineContent = buildMap {
val annotations = text.getStringAnnotations(
tag = "androidx.compose.foundation.text.inlineContent",
start = 0, end = text.length
)
for (annotation in annotations) {
val layoutResult = textMeasurer.measure(
text = text.slice(annotation.start..<annotation.end).toString(),
style = style.merge(
color = Color.White,
shadow = Shadow(
color = Color.Black.copy(.2f),
offset = with(density) { Offset(x = 0f, y = 1.dp.toPx()) }
)
)
)
val placeholderSize = with(density) { layoutResult.size.toSize().toDpSize() }
val placeholder = with(density) {
Placeholder(
width = ((placeholderSize.width + 8.dp).value / fontScale).sp,
height = ((placeholderSize.width + 2.dp).value / fontScale).sp,,
placeholderVerticalAlign = PlaceholderVerticalAlign.Center
)
}
this[annotation.item] = InlineTextContent(placeholder) {
val type = annotation.item.substringBefore("-")
Canvas(
modifier = Modifier
.drawBehind {
drawRoundRect(
color = when (type) {
"radical" -> Color.Black.copy(alpha = 0.2f).compositeOver(Color(0xFF0093DD))
"kanji" -> Color.Black.copy(alpha = 0.2f).compositeOver(Color(0xFFDD0093))
"vocab" -> Color.Black.copy(alpha = 0.2f).compositeOver(Color(0xFF9300DD))
else -> Color.Black.copy(alpha = 0.2f).compositeOver(Color(0xFF484848))
},
cornerRadius = CornerRadius(x = 4.dp.toPx(), y = 4.dp.toPx()),
)
drawRoundRect(
brush = when (type) {
"radical" -> Brush.verticalGradient(listOf(Color(0xFF00AAFF), Color(0xFF0093DD)))
"kanji" -> Brush.verticalGradient(listOf(Color(0xFFFF00AA), Color(0xFFDD0093)))
"vocab" -> Brush.verticalGradient(listOf(Color(0xFFAA00FF), Color(0xFF9300DD)))
else -> Brush.verticalGradient(listOf(Color(0xFF505050), Color(0xFF484848)))
},
cornerRadius = CornerRadius(x = 4.dp.toPx(), y = 4.dp.toPx()),
size = size.copy(height = size.height - 2.dp.toPx()),
)
}
.padding(horizontal = 4.dp, vertical = 1.dp)
.size(placeholderSize)
) {
drawText(layoutResult)
}
}
}
}
)
}
@Skaldebane
Copy link
Author

Ah, this isn't material specific at all. I think the only thing I pulled from Material was the Text composable, as well as LocalTextStyle, so just replace them with whatever equivalents exist in Material 3 (in case of LocalTextStyle, you don't necessarily have to use it per se, just use the same TextStyle you do for the rest of the text).

@codejockie
Copy link

Nevermind, got it.

@codejockie
Copy link

Nice job, and very well done and explained!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment