feat: initial system message impl

Signed-off-by: Infi <wingit@geist.ga>
This commit is contained in:
Infi 2023-07-02 23:19:01 +02:00
parent 963935e037
commit 5683dd85ce
14 changed files with 412 additions and 56 deletions

View File

@ -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,
)

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M17 18H21V16H17V14L14 17L17 20V18M11 4C8.8 4 7 5.8 7 8S8.8 12 11 12 15 10.2 15 8 13.2 4 11 4M11 14C6.6 14 3 15.8 3 18V20H12.5C12.2 19.2 12 18.4 12 17.5C12 16.3 12.3 15.2 12.9 14.1C12.3 14.1 11.7 14 11 14" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M18 16H14V18H18V20L21 17L18 14V16M11 4C8.8 4 7 5.8 7 8S8.8 12 11 12 15 10.2 15 8 13.2 4 11 4M11 14C6.6 14 3 15.8 3 18V20H12.5C12.2 19.2 12 18.4 12 17.5C12 16.3 12.3 15.2 12.9 14.1C12.3 14.1 11.7 14 11 14" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M10 4A4 4 0 0 0 6 8A4 4 0 0 0 10 12A4 4 0 0 0 14 8A4 4 0 0 0 10 4M17.5 13C15 13 13 15 13 17.5C13 20 15 22 17.5 22C20 22 22 20 22 17.5C22 15 20 13 17.5 13M10 14C5.58 14 2 15.79 2 18V20H11.5A6.5 6.5 0 0 1 11 17.5A6.5 6.5 0 0 1 11.95 14.14C11.32 14.06 10.68 14 10 14M17.5 14.5C19.16 14.5 20.5 15.84 20.5 17.5C20.5 18.06 20.35 18.58 20.08 19L16 14.92C16.42 14.65 16.94 14.5 17.5 14.5M14.92 16L19 20.08C18.58 20.35 18.06 20.5 17.5 20.5C15.84 20.5 14.5 19.16 14.5 17.5C14.5 16.94 14.65 16.42 14.92 16Z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M15,14C12.33,14 7,15.33 7,18V20H23V18C23,15.33 17.67,14 15,14M6,10V7H4V10H1V12H4V15H6V12H9V10M15,12A4,4 0 0,0 19,8A4,4 0 0,0 15,4A4,4 0 0,0 11,8A4,4 0 0,0 15,12Z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M13,19A1,1 0 0,0 14,20H16V22H13.5C12.95,22 12,21.55 12,21C12,21.55 11.05,22 10.5,22H8V20H10A1,1 0 0,0 11,19V5A1,1 0 0,0 10,4H8V2H10.5C11.05,2 12,2.45 12,3C12,2.45 12.95,2 13.5,2H16V4H14A1,1 0 0,0 13,5V19Z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M2.3,20.28L11.9,10.68L10.5,9.26L9.78,9.97C9.39,10.36 8.76,10.36 8.37,9.97L7.66,9.26C7.27,8.87 7.27,8.24 7.66,7.85L13.32,2.19C13.71,1.8 14.34,1.8 14.73,2.19L15.44,2.9C15.83,3.29 15.83,3.92 15.44,4.31L14.73,5L16.15,6.43C16.54,6.04 17.17,6.04 17.56,6.43C17.95,6.82 17.95,7.46 17.56,7.85L18.97,9.26L19.68,8.55C20.07,8.16 20.71,8.16 21.1,8.55L21.8,9.26C22.19,9.65 22.19,10.29 21.8,10.68L16.15,16.33C15.76,16.72 15.12,16.72 14.73,16.33L14.03,15.63C13.63,15.24 13.63,14.6 14.03,14.21L14.73,13.5L13.32,12.09L3.71,21.7C3.32,22.09 2.69,22.09 2.3,21.7C1.91,21.31 1.91,20.67 2.3,20.28M20,19A2,2 0 0,1 22,21V22H12V21A2,2 0 0,1 14,19H20Z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M22,16V4A2,2 0 0,0 20,2H8A2,2 0 0,0 6,4V16A2,2 0 0,0 8,18H20A2,2 0 0,0 22,16M11,12L13.03,14.71L16,11L20,16H8M2,6V20A2,2 0 0,0 4,22H18V20H4V6" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M11.7 6C11.1 4.2 9.4 3 7.5 3C5 3 3 5 3 7.5S5 12 7.5 12C9.5 12 11.1 10.8 11.7 9H15V12H18V9H21V6H11.7M7.5 9C6.7 9 6 8.3 6 7.5S6.7 6 7.5 6 9 6.7 9 7.5 8.3 9 7.5 9M13 21V19H8V17H13V15L16 18L13 21" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M12,1L3,5V11C3,16.55 6.84,21.74 12,23C17.16,21.74 21,16.55 21,11V5L12,1Z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M16,15H9V13H16M19,11H9V9H19M19,7H9V5H19M21,1H7C5.89,1 5,1.89 5,3V17C5,18.11 5.9,19 7,19H21C22.11,19 23,18.11 23,17V3C23,1.89 22.1,1 21,1M3,5V21H19V23H3A2,2 0 0,1 1,21V5H3Z" />
</vector>

View File

@ -134,6 +134,18 @@
<string name="reply_message_not_cached">Unknown message, tap to jump</string>
<string name="reply_message_empty_has_attachments">Sent attachments</string>
<string name="system_message_ownership_changed_alt">Ownership changed</string>
<string name="system_message_channel_icon_changed_alt">Channel icon changed</string>
<string name="system_message_channel_description_changed_alt">Channel description changed</string>
<string name="system_message_channel_renamed_alt">Channel renamed</string>
<string name="system_message_user_removed_alt">User removed</string>
<string name="system_message_user_added_alt">User added</string>
<string name="system_message_user_banned_alt">User banned</string>
<string name="system_message_user_kicked_alt">User kicked</string>
<string name="system_message_user_left_alt">User left</string>
<string name="system_message_user_joined_alt">User joined</string>
<string name="system_message_text_alt">System message</string>
<string name="today">Today</string>
<string name="yesterday">Yesterday</string>
<string name="x_days_ago">%1$d days ago</string>