diff --git a/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/network.kt b/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/network.kt index 2d5726b..11ac8f7 100644 --- a/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/network.kt +++ b/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/network.kt @@ -30,20 +30,15 @@ public value class EmojiUrl private constructor(public val url: String) { public val code: String get() = url.split('/').let { it[it.lastIndex - 1] } } -public suspend fun simpleDownloadBytes(url: EmojiUrl): ByteArray? = - try { +public suspend fun simpleDownloadBytes(url: EmojiUrl): ByteArray = platformDownloadBytes(url.url) - } catch (t: Throwable) { - t.printStackTrace() - null - } -public val LocalEmojiDownloader: ProvidableCompositionLocal ByteArray?> = +public val LocalEmojiDownloader: ProvidableCompositionLocal ByteArray> = compositionLocalOf { ::simpleDownloadBytes } @Composable public fun ProvideEmojiDownloader( - download: suspend (EmojiUrl) -> ByteArray?, + download: suspend (EmojiUrl) -> ByteArray, content: @Composable () -> Unit ) { CompositionLocalProvider( diff --git a/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/noto.kt b/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/noto.kt index 65c8c24..62d45fd 100644 --- a/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/noto.kt +++ b/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/noto.kt @@ -51,9 +51,11 @@ public fun NotoImageEmoji( val download = LocalEmojiDownloader.current var svg: SVGImage? by remember { mutableStateOf(null) } LaunchedEffect(emoji) { - val bytes = download(EmojiUrl.from(emoji, EmojiUrl.Type.SVG)) - if (bytes != null) { + try { + val bytes = download(EmojiUrl.from(emoji, EmojiUrl.Type.SVG)) svg = SVGImage.create(bytes) + } catch (t: Throwable) { + println("${t::class.simpleName}: ${t.message}") } } @@ -75,16 +77,25 @@ public fun NotoAnimatedEmoji( return } val download = LocalEmojiDownloader.current - var animation: LottieAnimation? by remember { mutableStateOf(null) } + var result: Result? by remember { mutableStateOf(null) } LaunchedEffect(emoji) { - val bytes = download(EmojiUrl.from(emoji, EmojiUrl.Type.Lottie)) - if (bytes != null) { - animation = LottieAnimation.create(bytes) + result = runCatching { + val bytes = download(EmojiUrl.from(emoji, EmojiUrl.Type.Lottie)) + LottieAnimation.create(bytes) + }.also { + if (it.isFailure) { + val t = it.exceptionOrNull()!! + println("${t::class.simpleName}: ${t.message}") + } } } - if (animation != null) { - LottieAnimation(animation!!, "${emoji.details.description} emoji", modifier) + if (result != null) { + if (result!!.isSuccess) { + LottieAnimation(result!!.getOrThrow(), "${emoji.details.description} emoji", modifier) + } else { + NotoImageEmoji(emoji, modifier, placeholder) + } } else { placeholder() } diff --git a/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/text.kt b/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/text.kt index 68c563e..5a3d833 100644 --- a/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/text.kt +++ b/emoji-compose/src/commonMain/kotlin/org/kodein/emoji/compose/text.kt @@ -72,6 +72,21 @@ private fun WithNotoEmoji( content(annotatedString, inlineContent) } +private suspend fun createNotoSvgInlineContent(emoji: Emoji, download: suspend (EmojiUrl) -> ByteArray): InlineTextContent? { + try { + val bytes = download(EmojiUrl.from(emoji, EmojiUrl.Type.SVG)) + val svg = SVGImage.create(bytes) + return InlineTextContent( + placeholder = Placeholder(1.em, 1.em / svg.sizeRatio(), PlaceholderVerticalAlign.Center), + children = { + SVGImage(svg, "${emoji.details.description} emoji", Modifier.fillMaxSize()) + } + ) + } catch (t: Throwable) { + println("${t::class.simpleName}: ${t.message}") + return null + } +} @Composable public fun WithNotoImageEmoji( @@ -82,19 +97,27 @@ public fun WithNotoImageEmoji( WithNotoEmoji( text = text, content = content, - createInlineTextContent = { found -> - val bytes = download(EmojiUrl.from(found.emoji, EmojiUrl.Type.SVG)) ?: return@WithNotoEmoji null - val svg = SVGImage.create(bytes) - InlineTextContent( - placeholder = Placeholder(1.em, 1.em / svg.sizeRatio(), PlaceholderVerticalAlign.Center), - children = { - SVGImage(svg, "${found.emoji.details.description} emoji", Modifier.fillMaxSize()) - } - ) - } + createInlineTextContent = { found -> createNotoSvgInlineContent(found.emoji, download) } ) } +private suspend fun createNotoLottieInlineContent(emoji: Emoji, download: suspend (EmojiUrl) -> ByteArray): InlineTextContent? { + if (!emoji.details.notoAnimated) return createNotoSvgInlineContent(emoji, download) + try { + val bytes = download(EmojiUrl.from(emoji, EmojiUrl.Type.Lottie)) + val animation = LottieAnimation.create(bytes) + return InlineTextContent( + placeholder = Placeholder(1.em, 1.em / animation.sizeRatio(), PlaceholderVerticalAlign.Center), + children = { + LottieAnimation(animation, "${emoji.details.description} emoji", Modifier.fillMaxSize()) + } + ) + } catch (t: Throwable) { + println("${t::class.simpleName}: ${t.message}") + return createNotoSvgInlineContent(emoji, download) + } +} + @Composable public fun WithNotoAnimatedEmoji( text: String, @@ -104,27 +127,7 @@ public fun WithNotoAnimatedEmoji( WithNotoEmoji( text = text, content = content, - createInlineTextContent = { found -> - val bytes = download(EmojiUrl.from(found.emoji, if (found.emoji.details.notoAnimated) EmojiUrl.Type.Lottie else EmojiUrl.Type.SVG)) - ?: return@WithNotoEmoji null - if (found.emoji.details.notoAnimated) { - val animation = LottieAnimation.create(bytes) - InlineTextContent( - placeholder = Placeholder(1.em, 1.em / animation.sizeRatio(), PlaceholderVerticalAlign.Center), - children = { - LottieAnimation(animation, "${found.emoji.details.description} emoji", Modifier.fillMaxSize()) - } - ) - } else { - val svg = SVGImage.create(bytes) - InlineTextContent( - placeholder = Placeholder(1.em, 1.em / svg.sizeRatio(), PlaceholderVerticalAlign.Center), - children = { - SVGImage(svg, "${found.emoji.details.description} emoji", Modifier.fillMaxSize()) - } - ) - } - } + createInlineTextContent = { found -> createNotoLottieInlineContent(found.emoji, download) } ) } diff --git a/emoji-kt/src/commonMain/kotlin/org/kodein/emoji/Emoji.kt b/emoji-kt/src/commonMain/kotlin/org/kodein/emoji/Emoji.kt index 272d324..2c7f7c1 100644 --- a/emoji-kt/src/commonMain/kotlin/org/kodein/emoji/Emoji.kt +++ b/emoji-kt/src/commonMain/kotlin/org/kodein/emoji/Emoji.kt @@ -163,7 +163,7 @@ internal open class SkinTone1EmojiImpl( unicodeVersion = details.unicodeVersion, aliases = details.aliases.map { it + "~${tone.alias}" }, emoticons = emptyList(), - notoAnimated = false + notoAnimated = details.notoAnimated ), original = this, tone1 = tone @@ -185,7 +185,7 @@ internal open class UnqualifiedSkinTone1EmojiImpl( unicodeVersion = details.unicodeVersion, aliases = details.aliases.map { it + "~${tone.alias}" }, emoticons = emptyList(), - notoAnimated = false + notoAnimated = details.notoAnimated ), original = this, tone1 = tone @@ -210,7 +210,7 @@ internal class SkinTone2EmojiZWJImpl internal constructor( unicodeVersion = zwjUnicodeVersion, aliases = details.aliases.map { it + "~${tone1.alias},${tone2.alias}" }, emoticons = emptyList(), - notoAnimated = false + notoAnimated = details.notoAnimated ), original = this, tone1 = tone1, @@ -233,7 +233,7 @@ internal class SkinTone2EmojiImpl internal constructor( unicodeVersion = details.unicodeVersion, aliases = details.aliases.map { it + "~${tone1.alias},${tone2.alias}" }, emoticons = emptyList(), - notoAnimated = false + notoAnimated = details.notoAnimated ), original = this, tone1 = tone1,