diff --git a/app/src/main/java/chat/revolt/components/chat/Message.kt b/app/src/main/java/chat/revolt/components/chat/Message.kt index 5728bace..388dfdaf 100644 --- a/app/src/main/java/chat/revolt/components/chat/Message.kt +++ b/app/src/main/java/chat/revolt/components/chat/Message.kt @@ -78,10 +78,10 @@ import chat.revolt.components.generic.UserAvatar import chat.revolt.components.generic.UserAvatarWidthPlaceholder import chat.revolt.components.markdown.LocalMarkdownTreeConfig import chat.revolt.components.markdown.RichMarkdown +import chat.revolt.internals.text.Gigamoji import chat.revolt.markdown.jbm.JBM import chat.revolt.markdown.jbm.JBMRenderer import chat.revolt.markdown.jbm.LocalJBMarkdownTreeState -import chat.revolt.internals.text.Gigamoji import kotlinx.coroutines.launch import chat.revolt.api.schemas.Message as MessageSchema @@ -370,6 +370,7 @@ fun Message( if (Experiments.useKotlinBasedMarkdownRenderer.isEnabled) { CompositionLocalProvider( LocalJBMarkdownTreeState provides LocalJBMarkdownTreeState.current.copy( + currentServer = RevoltAPI.channelCache[message.channel]?.server, fontSizeMultiplier = Gigamoji.useGigamojiForMessage( message.content ) diff --git a/app/src/main/java/chat/revolt/markdown/jbm/JBMRenderer.kt b/app/src/main/java/chat/revolt/markdown/jbm/JBMRenderer.kt index c8966d2a..ecd5707e 100644 --- a/app/src/main/java/chat/revolt/markdown/jbm/JBMRenderer.kt +++ b/app/src/main/java/chat/revolt/markdown/jbm/JBMRenderer.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -34,6 +35,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.runtime.structuralEqualityPolicy +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind @@ -74,6 +76,7 @@ import chat.revolt.api.settings.LoadedSettings import chat.revolt.callbacks.Action import chat.revolt.callbacks.ActionChannel import chat.revolt.components.generic.RemoteImage +import chat.revolt.components.generic.UserAvatar import chat.revolt.components.markdown.Annotations import chat.revolt.components.utils.detectTapGesturesConditionalConsume import chat.revolt.ui.theme.FragmentMono @@ -98,13 +101,11 @@ enum class JBMAnnotations(val tag: String, val clickable: Boolean) { ChannelMention("ChannelMention", true), CustomEmote("CustomEmote", true), Timestamp("Timestamp", false), - Checkbox("Checkbox", false) + Checkbox("Checkbox", false), + UserAvatar("UserAvatar", true), } object JBMRegularExpressions { - val Mention = Regex("<@([0-9A-Z]{26})>") - val Channel = Regex("<#([0-9A-Z]{26})>") - val CustomEmote = Regex(":([0-9A-Z]{26}):") val Timestamp = Regex("") } @@ -130,6 +131,8 @@ data class JBMarkdownTreeState( val LocalJBMarkdownTreeState = compositionLocalOf(structuralEqualityPolicy()) { JBMarkdownTreeState() } +val avatarPadding = 2.dp + @Composable @JBM fun JBMRenderer(content: String, modifier: Modifier = Modifier) { @@ -187,7 +190,6 @@ private fun annotateText( append(annotateText(state, child)) } } else { - // Now we're getting somewhere pushStringAnnotation( tag = JBMAnnotations.UserMention.tag, annotation = userId @@ -198,13 +200,20 @@ private fun annotateText( background = state.colors.clickableBackground ) ) + val member = state.currentServer?.let { serverId -> RevoltAPI.members.getMember(serverId, userId) } - val mentionDisplay = member?.nickname?.let { nick -> "@$nick" } - ?: RevoltAPI.userCache[userId]?.username?.let { username -> "@$username" } + val mentionDisplay = member?.nickname + ?: RevoltAPI.userCache[userId]?.username ?: "<@$userId>" + + append(" ") + appendInlineContent(JBMAnnotations.UserAvatar.tag, userId) + append(" ") append(mentionDisplay) + append(" ") + pop() pop() } @@ -219,7 +228,6 @@ private fun annotateText( append(annotateText(state, child)) } } else { - // Now we're getting somewhere pushStringAnnotation( tag = JBMAnnotations.ChannelMention.tag, annotation = channelId @@ -248,7 +256,6 @@ private fun annotateText( append(annotateText(state, child)) } } else { - // Now we're getting somewhere pushStringAnnotation( tag = JBMAnnotations.CustomEmote.tag, annotation = emoteId @@ -673,6 +680,47 @@ private fun JBMText(node: ASTNode, modifier: Modifier) { ) } } + }, + JBMAnnotations.UserAvatar.tag to with(LocalDensity.current) { + val placeholderBaseWidth = + (LocalTextStyle.current.fontSize * 1.5).toPx() - (avatarPadding * 2).toPx() + val widthTolerancePx = + 2 // Else we get a gap of about 1-2 pixels due to rounding errors + val placeholderBaseHeight = (LocalTextStyle.current.fontSize * 1.5).toPx() + val heightTolerancePx = 2 // Dito + + InlineTextContent( + placeholder = Placeholder( + width = (placeholderBaseWidth - widthTolerancePx).toSp(), + height = (placeholderBaseHeight - heightTolerancePx).toSp(), + placeholderVerticalAlign = PlaceholderVerticalAlign.Center + ), + ) { id -> + val user = RevoltAPI.userCache[id] + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .background(LocalJBMarkdownTreeState.current.colors.clickableBackground) + .padding(vertical = avatarPadding) + ) { + if (user == null) { + UserAvatar( + username = stringResource(R.string.unknown), + userId = id, + size = (LocalTextStyle.current.fontSize * 1.5).toDp() - (avatarPadding * 2), + modifier = Modifier.aspectRatio(1f, true) + ) + } else { + UserAvatar( + username = user.username ?: "", + avatar = user.avatar, + userId = user.id ?: "", + size = (LocalTextStyle.current.fontSize * 1.5).toDp() - (avatarPadding * 2), + modifier = Modifier.aspectRatio(1f, true) + ) + } + } + } } ) )