feat: handle PUA characters

This commit is contained in:
infi 2026-06-06 18:40:39 +02:00
parent 61a7f74d39
commit db39522bbb
4 changed files with 14 additions and 4 deletions

View File

@ -87,6 +87,7 @@ import chat.stoat.core.model.schemas.User
import chat.stoat.internals.text.Gigamoji
import chat.stoat.internals.text.GigamojiState
import chat.stoat.internals.text.MessageProcessor
import chat.stoat.internals.text.stripPUAChars
import chat.stoat.persistence.KVStorage
import com.mikepenz.markdown.model.State
import kotlinx.coroutines.launch
@ -438,9 +439,10 @@ fun Message(
key(message.content) {
message.content?.let {
if (message.content!!.isBlank()) return@let // if only an attachment is sent
val content = it.stripPUAChars()
if (content.isBlank()) return@let // if only an attachment is sent
val gigamoji = Gigamoji.useGigamojiForMessage(message.content!!)
val gigamoji = Gigamoji.useGigamojiForMessage(content)
val fontSizeMultiplier = when (gigamoji) {
GigamojiState.Single -> 5f
GigamojiState.Multiple -> 2f
@ -455,7 +457,7 @@ fun Message(
)
} else {
ChatMarkdown(
content = message.content!!,
content = content,
serverId = StoatAPI.channelCache[message.channel]?.server,
fontSizeMultiplier = fontSizeMultiplier,
)

View File

@ -26,6 +26,7 @@ object Gigamoji {
Character.isWhitespace(codepoint) -> lastWasZwj = false
codepoint == 0x200D -> lastWasZwj = true
codepoint == 0xFE0F || codepoint == 0xFE0E || codepoint == 0x20E3 -> Unit
codepoint in PUA_MIN..PUA_MAX -> Unit
codepoint in 0x1F3FB..0x1F3FF -> lastWasZwj = false
MessageProcessor.emoji.codepointIsEmoji(codepoint) -> {
if (!lastWasZwj) count++

View File

@ -0,0 +1,6 @@
package chat.stoat.internals.text
internal const val PUA_MIN = 0xE0E0
internal const val PUA_MAX = 0xE0E6
internal fun String.stripPUAChars(): String = filter { it.code !in PUA_MIN..PUA_MAX }

View File

@ -49,6 +49,7 @@ import chat.stoat.callbacks.UiCallbacks
import chat.stoat.core.model.schemas.Channel
import chat.stoat.core.model.schemas.Message
import chat.stoat.internals.text.MessageProcessor
import chat.stoat.internals.text.stripPUAChars
import chat.stoat.composables.markdown.prose.easyLineBreaks
import chat.stoat.markdown.StoatMarkdownFlavour
import chat.stoat.persistence.KVStorage
@ -264,7 +265,7 @@ class ChannelScreenViewModel(
private suspend fun parseAst(content: String?): State? =
content?.takeIf { it.isNotBlank() }?.let { c ->
val prepared = injectMassMentionMarkers(easyLineBreaks(c))
val prepared = injectMassMentionMarkers(easyLineBreaks(c.stripPUAChars()))
parseMarkdownFlow(prepared, flavour = StoatMarkdownFlavour(prepared))
.first { it !is State.Loading }
}