diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemTextView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemTextView.kt index a7d54e819b..86b50f3015 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemTextView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemTextView.kt @@ -15,7 +15,9 @@ import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTextStyle import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview @@ -23,6 +25,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import io.element.android.compound.theme.ElementTheme import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayout import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData +import io.element.android.features.messages.impl.timeline.model.event.AN_EMOJI_ONLY_TEXT import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContentPreviewParam import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent @@ -47,8 +50,13 @@ fun TimelineItemTextView( // The View <-> Compose interop is not working well with Compose UI tests (it loops indefinitely), so we skip it in the UI test mode. if (LocalUiTestMode.current) return - val emojiOnly = content.formattedBody.toString() == content.body && - content.body.replace(" ", "").containsOnlyEmojis() + val isInPreview = LocalInspectionMode.current + val emojiOnly = remember(content.body, content.formattedBody, isInPreview) { + content.formattedBody.toString() == content.body && + content.body.replace(" ", "").let { body -> + if (isInPreview) body == AN_EMOJI_ONLY_TEXT else body.containsOnlyEmojis() + } + } val textStyle = when { emojiOnly -> ElementTheme.typography.fontHeadingXlRegular else -> ElementTheme.typography.fontBodyLgRegular diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/Emoji.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/Emoji.kt index 3a0f16b3e9..68019f0c04 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/Emoji.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/utils/Emoji.kt @@ -8,25 +8,15 @@ package io.element.android.features.messages.impl.utils -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalInspectionMode import com.sigpwned.emoji4j.core.Grapheme.Type.EMOJI import com.sigpwned.emoji4j.core.Grapheme.Type.PICTOGRAPHIC import com.sigpwned.emoji4j.core.GraphemeMatchResult import com.sigpwned.emoji4j.core.GraphemeMatcher -import io.element.android.features.messages.impl.timeline.model.event.AN_EMOJI_ONLY_TEXT /** * Returns true if the string consists exclusively of "emoji or pictographic graphemes". */ -@Composable -fun String.containsOnlyEmojis(): Boolean { - if (LocalInspectionMode.current) return this == AN_EMOJI_ONLY_TEXT - if (isEmpty()) return false - return containsOnlyEmojisInternal() -} - -internal fun String.containsOnlyEmojisInternal(): Boolean { +internal fun String.containsOnlyEmojis(): Boolean { val matcher = GraphemeMatcher(this) var m: GraphemeMatchResult? = null var contiguous = true diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/EmojiTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/EmojiTest.kt index 5c979dbb7c..e75eb83d62 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/EmojiTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/utils/EmojiTest.kt @@ -16,23 +16,23 @@ class EmojiTest { @Test fun validEmojis() { // Simple single/multiple single-codepoint emojis per string - assertTrue("👍".containsOnlyEmojisInternal()) - assertTrue("😀".containsOnlyEmojisInternal()) - assertTrue("🙂🙁".containsOnlyEmojisInternal()) - assertTrue("đŸ‘â¤ī¸đŸ".containsOnlyEmojisInternal()) // 👁 is a pictographic - assertTrue("👨‍👩‍đŸ‘Ļ1ī¸âƒŖđŸš€đŸ‘ŗđŸžâ€â™‚ī¸đŸĒŠ".containsOnlyEmojisInternal()) - assertTrue("🌍🌎🌏".containsOnlyEmojisInternal()) + assertTrue("👍".containsOnlyEmojis()) + assertTrue("😀".containsOnlyEmojis()) + assertTrue("🙂🙁".containsOnlyEmojis()) + assertTrue("đŸ‘â¤ī¸đŸ".containsOnlyEmojis()) // 👁 is a pictographic + assertTrue("👨‍👩‍đŸ‘Ļ1ī¸âƒŖđŸš€đŸ‘ŗđŸžâ€â™‚ī¸đŸĒŠ".containsOnlyEmojis()) + assertTrue("🌍🌎🌏".containsOnlyEmojis()) // Awkward multi-codepoint graphemes - assertTrue("🧑‍🧑‍🧒‍🧒".containsOnlyEmojisInternal()) - assertTrue("🏴‍☠".containsOnlyEmojisInternal()) - assertTrue("👩đŸŋ‍🔧".containsOnlyEmojisInternal()) + assertTrue("🧑‍🧑‍🧒‍🧒".containsOnlyEmojis()) + assertTrue("🏴‍☠".containsOnlyEmojis()) + assertTrue("👩đŸŋ‍🔧".containsOnlyEmojis()) - Assert.assertFalse("".containsOnlyEmojisInternal()) - Assert.assertFalse(" ".containsOnlyEmojisInternal()) - Assert.assertFalse("🙂 🙁".containsOnlyEmojisInternal()) - Assert.assertFalse(" 🙂 🙁 ".containsOnlyEmojisInternal()) - Assert.assertFalse("Hello".containsOnlyEmojisInternal()) - Assert.assertFalse("Hello 👋".containsOnlyEmojisInternal()) + Assert.assertFalse("".containsOnlyEmojis()) + Assert.assertFalse(" ".containsOnlyEmojis()) + Assert.assertFalse("🙂 🙁".containsOnlyEmojis()) + Assert.assertFalse(" 🙂 🙁 ".containsOnlyEmojis()) + Assert.assertFalse("Hello".containsOnlyEmojis()) + Assert.assertFalse("Hello 👋".containsOnlyEmojis()) } }