diff --git a/app/src/main/java/chat/stoat/composables/chat/SystemMessage.kt b/app/src/main/java/chat/stoat/composables/chat/SystemMessage.kt
index 1a866fd3..601f5e61 100644
--- a/app/src/main/java/chat/stoat/composables/chat/SystemMessage.kt
+++ b/app/src/main/java/chat/stoat/composables/chat/SystemMessage.kt
@@ -14,7 +14,6 @@ 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
@@ -58,7 +57,7 @@ fun SystemMessage(message: Message) {
SystemMessageType.entries.firstOrNull { it.type == message.system.type }
if (systemMessageType == null) {
- Text(text = message.system.toString())
+ UnsupportedMessage(context = message.system.type)
return
}
diff --git a/app/src/main/java/chat/stoat/composables/chat/UnsupportedMessage.kt b/app/src/main/java/chat/stoat/composables/chat/UnsupportedMessage.kt
new file mode 100644
index 00000000..6702f5c7
--- /dev/null
+++ b/app/src/main/java/chat/stoat/composables/chat/UnsupportedMessage.kt
@@ -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)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/stoat/screens/chat/views/channel/ChannelScreen.kt b/app/src/main/java/chat/stoat/screens/chat/views/channel/ChannelScreen.kt
index 0b4ed969..39b51641 100644
--- a/app/src/main/java/chat/stoat/screens/chat/views/channel/ChannelScreen.kt
+++ b/app/src/main/java/chat/stoat/screens/chat/views/channel/ChannelScreen.kt
@@ -125,6 +125,7 @@ import chat.stoat.composables.chat.DateDivider
import chat.stoat.composables.chat.Message
import chat.stoat.composables.chat.MessageField
import chat.stoat.composables.chat.SystemMessage
+import chat.stoat.composables.chat.UnsupportedMessage
import chat.stoat.composables.emoji.EmojiPicker
import chat.stoat.composables.generic.GroupIcon
import chat.stoat.composables.generic.PresenceBadge
@@ -726,6 +727,14 @@ fun ChannelScreen(
}
when (val item = viewModel.items[index]) {
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(
item.message,
viewModel.channel,
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8a72e86e..172675f5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -255,6 +255,9 @@
Blocked message
Failed to send, long press for options
+ Message cannot be displayed.
+ Message cannot be displayed (%1$s).
+
Tap to play video from YouTube
Ownership changed