From 5683dd85cef6a028f71a55cde5ae39f0cb253bdb Mon Sep 17 00:00:00 2001 From: Infi Date: Sun, 2 Jul 2023 23:19:01 +0200 Subject: [PATCH] feat: initial system message impl Signed-off-by: Infi --- .../java/chat/revolt/api/schemas/Messages.kt | 7 +- .../revolt/components/chat/SystemMessage.kt | 245 ++++++++++++++++++ .../chat/views/channel/ChannelScreen.kt | 114 ++++---- .../drawable/ic_account_arrow_left_24dp.xml | 9 + .../drawable/ic_account_arrow_right_24dp.xml | 9 + .../res/drawable/ic_account_cancel_24dp.xml | 9 + .../res/drawable/ic_account_plus_24dp.xml | 9 + .../main/res/drawable/ic_cursor_text_24dp.xml | 9 + app/src/main/res/drawable/ic_gavel_24dp.xml | 9 + .../res/drawable/ic_image_multiple_24dp.xml | 9 + .../res/drawable/ic_key_arrow_right_24dp.xml | 9 + app/src/main/res/drawable/ic_shield_24dp.xml | 9 + .../drawable/ic_text_box_multiple_24dp.xml | 9 + app/src/main/res/values/strings.xml | 12 + 14 files changed, 412 insertions(+), 56 deletions(-) create mode 100644 app/src/main/java/chat/revolt/components/chat/SystemMessage.kt create mode 100644 app/src/main/res/drawable/ic_account_arrow_left_24dp.xml create mode 100644 app/src/main/res/drawable/ic_account_arrow_right_24dp.xml create mode 100644 app/src/main/res/drawable/ic_account_cancel_24dp.xml create mode 100644 app/src/main/res/drawable/ic_account_plus_24dp.xml create mode 100644 app/src/main/res/drawable/ic_cursor_text_24dp.xml create mode 100644 app/src/main/res/drawable/ic_gavel_24dp.xml create mode 100644 app/src/main/res/drawable/ic_image_multiple_24dp.xml create mode 100644 app/src/main/res/drawable/ic_key_arrow_right_24dp.xml create mode 100644 app/src/main/res/drawable/ic_shield_24dp.xml create mode 100644 app/src/main/res/drawable/ic_text_box_multiple_24dp.xml diff --git a/app/src/main/java/chat/revolt/api/schemas/Messages.kt b/app/src/main/java/chat/revolt/api/schemas/Messages.kt index 21a08f70..f68f122c 100644 --- a/app/src/main/java/chat/revolt/api/schemas/Messages.kt +++ b/app/src/main/java/chat/revolt/api/schemas/Messages.kt @@ -95,5 +95,10 @@ data class Masquerade( @Serializable data class SystemInfo( val type: String? = null, - val id: String? = null + val id: String? = null, + val name: String? = null, + val by: String? = null, + val from: String? = null, + val to: String? = null, + val content: String? = null, ) \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/components/chat/SystemMessage.kt b/app/src/main/java/chat/revolt/components/chat/SystemMessage.kt new file mode 100644 index 00000000..c7e1528f --- /dev/null +++ b/app/src/main/java/chat/revolt/components/chat/SystemMessage.kt @@ -0,0 +1,245 @@ +package chat.revolt.components.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.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Info +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +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 androidx.compose.ui.unit.dp +import chat.revolt.R +import chat.revolt.api.schemas.Message + +enum class SystemMessageType(val type: String) { + CHANNEL_OWNERSHIP_CHANGED("channel_ownership_changed"), + CHANNEL_ICON_CHANGED("channel_icon_changed"), + CHANNEL_DESCRIPTION_CHANGED("channel_description_changed"), + CHANNEL_RENAMED("channel_renamed"), + USER_REMOVE("user_remove"), + USER_ADDED("user_added"), + USER_BANNED("user_banned"), + USER_KICKED("user_kicked"), + USER_LEFT("user_left"), + USER_JOINED("user_joined"), + TEXT("text"), +} + +@Composable +fun SystemMessage( + message: Message +) { + if (message.system == null) return + + val systemMessageType = + SystemMessageType.values().firstOrNull { it.type == message.system.type } + + if (systemMessageType == null) { + Text(text = message.system.toString()) + return + } + + CompositionLocalProvider( + LocalContentColor provides LocalContentColor.current.copy(alpha = 0.7f), + LocalTextStyle provides LocalTextStyle.current.copy( + fontWeight = FontWeight.Light + ) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp) + ) { + SystemMessageIconWithBackground(type = systemMessageType) + + Spacer(modifier = Modifier.width(10.dp)) + + when (systemMessageType) { + SystemMessageType.CHANNEL_OWNERSHIP_CHANGED -> { + Text(text = "Channel ownership changed from ${message.system.from} to ${message.system.to}") + } + + SystemMessageType.CHANNEL_ICON_CHANGED -> { + Text(text = "Channel icon changed by ${message.system.by}") + } + + SystemMessageType.CHANNEL_DESCRIPTION_CHANGED -> { + Text(text = "Channel description changed by ${message.system.by}") + } + + SystemMessageType.CHANNEL_RENAMED -> { + Text(text = "Channel renamed to ${message.system.name} by ${message.system.by}") + } + + SystemMessageType.USER_REMOVE -> { + Text(text = "User ${message.system.id} removed by ${message.system.by}") + } + + SystemMessageType.USER_ADDED -> { + Text(text = "User ${message.system.id} added by ${message.system.by}") + } + + SystemMessageType.USER_BANNED -> { + Text(text = "User ${message.system.id} banned") + } + + SystemMessageType.USER_KICKED -> { + Text(text = "User ${message.system.id} kicked") + } + + SystemMessageType.USER_LEFT -> { + Text(text = "User ${message.system.id} left") + } + + SystemMessageType.USER_JOINED -> { + Text(text = "User ${message.system.id} joined") + } + + SystemMessageType.TEXT -> { + message.system.content?.let { Text(text = it) } + } + } + } + } +} + +@Composable +fun SystemMessageIcon( + type: SystemMessageType, + modifier: Modifier = Modifier, + size: Dp = 24.dp +) { + when (type) { + SystemMessageType.CHANNEL_OWNERSHIP_CHANGED -> { + Icon( + painter = painterResource(R.drawable.ic_key_arrow_right_24dp), + contentDescription = stringResource(R.string.system_message_ownership_changed_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.CHANNEL_ICON_CHANGED -> { + Icon( + painter = painterResource(R.drawable.ic_image_multiple_24dp), + contentDescription = stringResource(R.string.system_message_channel_icon_changed_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.CHANNEL_DESCRIPTION_CHANGED -> { + Icon( + painter = painterResource(R.drawable.ic_text_box_multiple_24dp), + contentDescription = stringResource(R.string.system_message_channel_description_changed_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.CHANNEL_RENAMED -> { + Icon( + painter = painterResource(R.drawable.ic_cursor_text_24dp), + contentDescription = stringResource(R.string.system_message_channel_renamed_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.USER_REMOVE -> { + Icon( + painter = painterResource(R.drawable.ic_account_cancel_24dp), + contentDescription = stringResource(R.string.system_message_user_removed_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.USER_ADDED -> { + Icon( + painter = painterResource(R.drawable.ic_account_plus_24dp), + contentDescription = stringResource(R.string.system_message_user_added_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.USER_BANNED -> { + Icon( + painter = painterResource(R.drawable.ic_gavel_24dp), + contentDescription = stringResource(R.string.system_message_user_banned_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.USER_KICKED -> { + Icon( + painter = painterResource(R.drawable.ic_shield_24dp), + contentDescription = stringResource(R.string.system_message_user_kicked_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.USER_LEFT -> { + Icon( + painter = painterResource(R.drawable.ic_account_arrow_left_24dp), + contentDescription = stringResource(R.string.system_message_user_left_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.USER_JOINED -> { + Icon( + painter = painterResource(R.drawable.ic_account_arrow_right_24dp), + contentDescription = stringResource(R.string.system_message_user_joined_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + + SystemMessageType.TEXT -> { + Icon( + imageVector = Icons.Default.Info, + contentDescription = stringResource(R.string.system_message_text_alt), + tint = LocalContentColor.current, + modifier = modifier.size(size) + ) + } + } +} + +@Composable +fun SystemMessageIconWithBackground( + type: SystemMessageType, + modifier: Modifier = Modifier, + size: Dp = 40.dp +) { + Box( + contentAlignment = Alignment.Center, + modifier = modifier + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primary.copy(alpha = 0.3f)) + .size(size) + ) { + SystemMessageIcon(type = type) + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/chat/views/channel/ChannelScreen.kt b/app/src/main/java/chat/revolt/screens/chat/views/channel/ChannelScreen.kt index d1826df9..95592280 100644 --- a/app/src/main/java/chat/revolt/screens/chat/views/channel/ChannelScreen.kt +++ b/app/src/main/java/chat/revolt/screens/chat/views/channel/ChannelScreen.kt @@ -60,6 +60,7 @@ import chat.revolt.api.internals.ChannelUtils import chat.revolt.api.routes.microservices.autumn.FileArgs import chat.revolt.components.chat.Message import chat.revolt.components.chat.MessageField +import chat.revolt.components.chat.SystemMessage import chat.revolt.components.screens.chat.AttachmentManager import chat.revolt.components.screens.chat.ChannelHeader import chat.revolt.components.screens.chat.ReplyManager @@ -244,63 +245,66 @@ fun ChannelScreen( items = viewModel.renderableMessages, key = { it.id!! } ) { message -> - Message( - message, - parse = { - val parser = MarkdownParser() - .addRules( - SimpleMarkdownRules.createEscapeRule(), - UserMentionRule(), - ChannelMentionRule(), - CustomEmoteRule(), - ) - .addRules( - createCodeRule(context, codeBlockColor.toArgb()), - createInlineCodeRule(context, codeBlockColor.toArgb()), - ) - .addRules( - SimpleMarkdownRules.createSimpleMarkdownRules( - includeEscapeRule = false + when { + message.system != null -> SystemMessage(message) + else -> Message( + message, + parse = { + val parser = MarkdownParser() + .addRules( + SimpleMarkdownRules.createEscapeRule(), + UserMentionRule(), + ChannelMentionRule(), + CustomEmoteRule(), + ) + .addRules( + createCodeRule(context, codeBlockColor.toArgb()), + createInlineCodeRule(context, codeBlockColor.toArgb()), + ) + .addRules( + SimpleMarkdownRules.createSimpleMarkdownRules( + includeEscapeRule = false + ) + ) + + SimpleRenderer.render( + source = it.content ?: "", + parser = parser, + initialState = MarkdownState(0), + renderContext = MarkdownContext( + memberMap = mapOf(), + userMap = RevoltAPI.userCache.toMap(), + channelMap = RevoltAPI.channelCache.mapValues { ch -> + ch.value.name ?: ch.value.id ?: "#DeletedChannel" + }, + emojiMap = RevoltAPI.emojiCache, + serverId = channel.server ?: "", ) ) - - SimpleRenderer.render( - source = it.content ?: "", - parser = parser, - initialState = MarkdownState(0), - renderContext = MarkdownContext( - memberMap = mapOf(), - userMap = RevoltAPI.userCache.toMap(), - channelMap = RevoltAPI.channelCache.mapValues { ch -> - ch.value.name ?: ch.value.id ?: "#DeletedChannel" - }, - emojiMap = RevoltAPI.emojiCache, - serverId = channel.server ?: "", - ) - ) - }, - onMessageContextMenu = { - messageContextSheetShown = true - messageContextSheetTarget = message.id ?: "" - }, - onAvatarClick = { - message.author?.let { author -> - onUserSheetOpenFor(author, channel.server) - } - }, - canReply = true, - onReply = { - if (viewModel.pendingReplies.size >= 5) { - Toast.makeText( - context, - context.getString(R.string.too_many_replies, 5), - Toast.LENGTH_SHORT - ).show() - return@Message - } - viewModel.replyToMessage(message) - }, - ) + }, + onMessageContextMenu = { + messageContextSheetShown = true + messageContextSheetTarget = message.id ?: "" + }, + onAvatarClick = { + message.author?.let { author -> + onUserSheetOpenFor(author, channel.server) + } + }, + canReply = true, + onReply = { + if (viewModel.pendingReplies.size >= 5) { + Toast.makeText( + context, + context.getString(R.string.too_many_replies, 5), + Toast.LENGTH_SHORT + ).show() + return@Message + } + viewModel.replyToMessage(message) + }, + ) + } } item { diff --git a/app/src/main/res/drawable/ic_account_arrow_left_24dp.xml b/app/src/main/res/drawable/ic_account_arrow_left_24dp.xml new file mode 100644 index 00000000..63887410 --- /dev/null +++ b/app/src/main/res/drawable/ic_account_arrow_left_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_account_arrow_right_24dp.xml b/app/src/main/res/drawable/ic_account_arrow_right_24dp.xml new file mode 100644 index 00000000..0b609bce --- /dev/null +++ b/app/src/main/res/drawable/ic_account_arrow_right_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_account_cancel_24dp.xml b/app/src/main/res/drawable/ic_account_cancel_24dp.xml new file mode 100644 index 00000000..238d9e6e --- /dev/null +++ b/app/src/main/res/drawable/ic_account_cancel_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_account_plus_24dp.xml b/app/src/main/res/drawable/ic_account_plus_24dp.xml new file mode 100644 index 00000000..833ca68d --- /dev/null +++ b/app/src/main/res/drawable/ic_account_plus_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_cursor_text_24dp.xml b/app/src/main/res/drawable/ic_cursor_text_24dp.xml new file mode 100644 index 00000000..3f0876ab --- /dev/null +++ b/app/src/main/res/drawable/ic_cursor_text_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_gavel_24dp.xml b/app/src/main/res/drawable/ic_gavel_24dp.xml new file mode 100644 index 00000000..7d5c4c46 --- /dev/null +++ b/app/src/main/res/drawable/ic_gavel_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_image_multiple_24dp.xml b/app/src/main/res/drawable/ic_image_multiple_24dp.xml new file mode 100644 index 00000000..589c7eed --- /dev/null +++ b/app/src/main/res/drawable/ic_image_multiple_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_key_arrow_right_24dp.xml b/app/src/main/res/drawable/ic_key_arrow_right_24dp.xml new file mode 100644 index 00000000..a43b6126 --- /dev/null +++ b/app/src/main/res/drawable/ic_key_arrow_right_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_shield_24dp.xml b/app/src/main/res/drawable/ic_shield_24dp.xml new file mode 100644 index 00000000..50ca6055 --- /dev/null +++ b/app/src/main/res/drawable/ic_shield_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_text_box_multiple_24dp.xml b/app/src/main/res/drawable/ic_text_box_multiple_24dp.xml new file mode 100644 index 00000000..f45143ca --- /dev/null +++ b/app/src/main/res/drawable/ic_text_box_multiple_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 46c8444a..20066f0d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -134,6 +134,18 @@ Unknown message, tap to jump Sent attachments + Ownership changed + Channel icon changed + Channel description changed + Channel renamed + User removed + User added + User banned + User kicked + User left + User joined + System message + Today Yesterday %1$d days ago