feat: point out unsupported messages

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2025-10-19 02:58:29 +02:00
parent 9d9f582683
commit 85632e8e76
4 changed files with 87 additions and 2 deletions

View File

@ -14,7 +14,6 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialShapes import androidx.compose.material3.MaterialShapes
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.toShape import androidx.compose.material3.toShape
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
@ -58,7 +57,7 @@ fun SystemMessage(message: Message) {
SystemMessageType.entries.firstOrNull { it.type == message.system.type } SystemMessageType.entries.firstOrNull { it.type == message.system.type }
if (systemMessageType == null) { if (systemMessageType == null) {
Text(text = message.system.toString()) UnsupportedMessage(context = message.system.type)
return return
} }

View File

@ -0,0 +1,74 @@
package chat.stoat.composables.chat
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialShapes
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.toShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import chat.stoat.R
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun UnsupportedMessage(modifier: Modifier = Modifier, context: String? = null) {
CompositionLocalProvider(
LocalContentColor provides MaterialTheme.colorScheme.error.copy(alpha = 0.7f),
LocalTextStyle provides LocalTextStyle.current.copy(
fontWeight = FontWeight.Medium
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(horizontal = 10.dp, vertical = 16.dp)
.fillMaxWidth()
) {
Box(
contentAlignment = Alignment.Center,
modifier = modifier
.clip(MaterialShapes.PixelCircle.toShape())
.background(
color = MaterialTheme.colorScheme.errorContainer,
)
.size(40.dp)
) {
CompositionLocalProvider(
LocalContentColor provides MaterialTheme.colorScheme.onErrorContainer,
) {
Icon(
painter = painterResource(R.drawable.icn_error_24dp),
contentDescription = null,
tint = LocalContentColor.current,
modifier = Modifier.size(24.dp)
)
}
}
Spacer(modifier = Modifier.width(10.dp))
Text(
if (context != null) stringResource(
R.string.message_not_supported_with_context,
context
) else stringResource(R.string.message_not_supported)
)
}
}
}

View File

@ -125,6 +125,7 @@ import chat.stoat.composables.chat.DateDivider
import chat.stoat.composables.chat.Message import chat.stoat.composables.chat.Message
import chat.stoat.composables.chat.MessageField import chat.stoat.composables.chat.MessageField
import chat.stoat.composables.chat.SystemMessage import chat.stoat.composables.chat.SystemMessage
import chat.stoat.composables.chat.UnsupportedMessage
import chat.stoat.composables.emoji.EmojiPicker import chat.stoat.composables.emoji.EmojiPicker
import chat.stoat.composables.generic.GroupIcon import chat.stoat.composables.generic.GroupIcon
import chat.stoat.composables.generic.PresenceBadge import chat.stoat.composables.generic.PresenceBadge
@ -726,6 +727,14 @@ fun ChannelScreen(
} }
when (val item = viewModel.items[index]) { when (val item = viewModel.items[index]) {
is ChannelScreenItem.RegularMessage -> { is ChannelScreenItem.RegularMessage -> {
if (item.message.content?.replace("\\s".toRegex(), "")
?.contains(">>>>>>>") == true
) {
// FIXME Dirty hack to prevent a crash caused by malicious messages.
UnsupportedMessage()
return@items
}
RegularMessage( RegularMessage(
item.message, item.message,
viewModel.channel, viewModel.channel,

View File

@ -255,6 +255,9 @@
<string name="message_blocked">Blocked message</string> <string name="message_blocked">Blocked message</string>
<string name="message_failed_to_send">Failed to send, long press for options</string> <string name="message_failed_to_send">Failed to send, long press for options</string>
<string name="message_not_supported">Message cannot be displayed.</string>
<string name="message_not_supported_with_context">Message cannot be displayed (%1$s).</string>
<string name="message_embed_special_youtube_switch_alt">Tap to play video from YouTube</string> <string name="message_embed_special_youtube_switch_alt">Tap to play video from YouTube</string>
<string name="system_message_ownership_changed_alt">Ownership changed</string> <string name="system_message_ownership_changed_alt">Ownership changed</string>