Skip to content

Commit

Permalink
feat(chat): always show mentions as replies (#257)
Browse files Browse the repository at this point in the history
  • Loading branch information
outadoc authored Dec 7, 2023
1 parent 9b3e859 commit e66bb85
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import dev.icerock.moko.resources.compose.stringResource
import fr.outadoc.justchatting.component.chatapi.common.ChatEvent
import fr.outadoc.justchatting.component.chatapi.common.Chatter
import fr.outadoc.justchatting.component.chatapi.common.Emote
import fr.outadoc.justchatting.component.preferences.data.AppUser
import fr.outadoc.justchatting.feature.chat.presentation.AutoCompleteItem
import fr.outadoc.justchatting.shared.MR
import fr.outadoc.justchatting.utils.ui.AppTheme
Expand Down Expand Up @@ -104,7 +105,7 @@ fun ChatInputPreviewReplying() {
@Composable
fun ChatInput(
modifier: Modifier = Modifier,
appUserId: String? = null,
appUser: AppUser.LoggedIn? = null,
message: TextFieldValue = TextFieldValue(),
autoCompleteItems: List<AutoCompleteItem> = emptyList(),
replyingTo: ChatEvent.Message? = null,
Expand Down Expand Up @@ -143,8 +144,8 @@ fun ChatInput(
) {
InReplyToMessage(
modifier = Modifier.weight(1f),
appUserId = appUserId,
chatter = replyingToMessage.chatter,
appUser = appUser,
mentions = listOf(replyingToMessage.chatter.displayName),
message = replyingToMessage.message.orEmpty(),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ fun ChatMessage(
.padding(4.dp),
body = data,
inlineContent = inlineContent,
knownChatters = knownChatters,
pronouns = pronouns,
appUser = appUser,
backgroundHint = backgroundHint,
Expand Down Expand Up @@ -141,10 +140,9 @@ fun ChatMessage(
),
body = message.body,
inlineContent = inlineContent,
pronouns = pronouns,
appUser = appUser,
backgroundHint = backgroundHint,
knownChatters = knownChatters,
pronouns = pronouns,
richEmbed = richEmbed,
maxLines = maxLines,
onShowUserInfoForLogin = onShowUserInfoForLogin,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import fr.outadoc.justchatting.shared.R
import fr.outadoc.justchatting.utils.ui.ensureColorIsAccessible
import fr.outadoc.justchatting.utils.ui.parseHexColor
import kotlinx.collections.immutable.ImmutableMap
import kotlinx.collections.immutable.PersistentSet
import kotlinx.collections.immutable.toImmutableMap
import kotlinx.collections.immutable.toPersistentHashMap
import kotlin.random.Random
Expand All @@ -54,7 +53,6 @@ fun ChatMessageBody(
modifier: Modifier = Modifier,
body: ChatEvent.Message.Body,
inlineContent: ImmutableMap<String, InlineTextContent>,
knownChatters: PersistentSet<Chatter>,
pronouns: ImmutableMap<Chatter, Pronoun>,
appUser: AppUser.LoggedIn,
backgroundHint: Color,
Expand Down Expand Up @@ -83,7 +81,6 @@ fun ChatMessageBody(
val annotatedString = body.toAnnotatedString(
appUser = appUser,
inlineContent = fullInlineContent,
knownChatters = knownChatters,
pronouns = pronouns,
backgroundHint = backgroundHint,
)
Expand All @@ -92,8 +89,8 @@ fun ChatMessageBody(
body.inReplyTo?.let { inReplyTo ->
InReplyToMessage(
modifier = Modifier.padding(bottom = 8.dp),
appUserId = appUser.userId,
chatter = inReplyTo.chatter,
appUser = appUser,
mentions = inReplyTo.mentions,
message = inReplyTo.message,
)
}
Expand Down Expand Up @@ -161,7 +158,6 @@ fun ChatMessageBody(
fun ChatEvent.Message.Body.toAnnotatedString(
appUser: AppUser.LoggedIn,
inlineContent: ImmutableMap<String, InlineTextContent>,
knownChatters: PersistentSet<Chatter>,
pronouns: ImmutableMap<Chatter, Pronoun>,
urlColor: Color = MaterialTheme.colorScheme.primary,
backgroundHint: Color = MaterialTheme.colorScheme.surface,
Expand Down Expand Up @@ -224,14 +220,8 @@ fun ChatEvent.Message.Body.toAnnotatedString(
}

message
?.stripReplyMention(inReplyTo)
?.split(' ')
?.forEach { word ->
val mentionedChatter: Chatter? =
knownChatters.firstOrNull { chatter ->
chatter.matches(word.removePrefix(ChatPrefixConstants.ChatterPrefix.toString()))
}

when {
word.matches(urlRegex) -> {
// This is a URL
Expand All @@ -246,10 +236,10 @@ fun ChatEvent.Message.Body.toAnnotatedString(
)
}

mentionedChatter != null -> {
word.startsWith(ChatPrefixConstants.ChatterPrefix) -> {
// This is a user mention
appendMention(
chatter = mentionedChatter,
mention = word,
appUser = appUser,
mentionBackground = mentionBackground,
mentionColor = mentionColor,
Expand Down Expand Up @@ -277,36 +267,26 @@ private fun AnnotatedString.Builder.appendUrl(url: String, urlColor: Color) {
}
}

@OptIn(ExperimentalTextApi::class)
private fun AnnotatedString.Builder.appendMention(
chatter: Chatter,
mention: String,
appUser: AppUser.LoggedIn,
mentionBackground: Color,
mentionColor: Color,
) {
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
withAnnotation(
tag = CHATTER_LOGIN_ANNOTATION_TAG,
annotation = chatter.login,
withStyle(
getMentionStyle(
// TODO also check for userDisplayName
mentioned = mention.contentEquals(appUser.userLogin, ignoreCase = true),
mentionBackground = mentionBackground,
mentionColor = mentionColor,
),
) {
withStyle(
getMentionStyle(
mentioned = chatter.login == appUser.userLogin,
mentionBackground = mentionBackground,
mentionColor = mentionColor,
),
) {
append(ChatPrefixConstants.ChatterPrefix)
append(chatter.displayName)
}
append(mention)
}
}
}

private fun String.stripReplyMention(inReplyTo: ChatEvent.Message.Body.InReplyTo?): String {
return inReplyTo?.let { replyTo -> removePrefix("@${replyTo.chatter.displayName} ") } ?: this
}

private val Badge.inlineContentId: String
get() = "badge_${id}_$version"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import dev.icerock.moko.resources.compose.stringResource
import fr.outadoc.justchatting.component.chatapi.common.Chatter
import fr.outadoc.justchatting.component.preferences.data.AppUser
import fr.outadoc.justchatting.feature.chat.presentation.ChatPrefixConstants
import fr.outadoc.justchatting.shared.MR

@Composable
fun InReplyToMessage(
modifier: Modifier = Modifier,
chatter: Chatter,
message: String,
appUserId: String? = null,
mentions: List<String>,
message: String?,
appUser: AppUser.LoggedIn? = null,
mentionBackground: Color = MaterialTheme.colorScheme.onBackground,
mentionColor: Color = MaterialTheme.colorScheme.background,
) {
Expand All @@ -47,25 +47,35 @@ fun InReplyToMessage(
.alignByBaseline()
.padding(end = 4.dp, top = 1.dp),
imageVector = Icons.Default.Reply,
contentDescription = stringResource(fr.outadoc.justchatting.shared.MR.strings.chat_replyingTo),
contentDescription = stringResource(MR.strings.chat_replyingTo),
)

Text(
text = buildAnnotatedString {
withStyle(
SpanStyle(fontWeight = FontWeight.Bold) +
getMentionStyle(
mentioned = chatter.id == appUserId,
mentioned = mentions.any { mention ->
mention.equals(appUser?.userLogin, ignoreCase = true)
},
mentionBackground = mentionBackground,
mentionColor = mentionColor,
),
) {
append(ChatPrefixConstants.ChatterPrefix)
append(chatter.displayName)
append(
mentions.joinToString(
separator = " ",
transform = { mention ->
"${ChatPrefixConstants.ChatterPrefix}$mention"
},
),
)
}

append(stringResource(MR.strings.chat_message_standardSeparator))
append(message)
if (message != null) {
append(stringResource(MR.strings.chat_message_standardSeparator))
append(message)
}
},
style = MaterialTheme.typography.bodySmall,
maxLines = 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,7 @@ private val simpleEntries = sequence {
embeddedEmotes = persistentListOf(),
badges = persistentListOf(),
inReplyTo = ChatEvent.Message.Body.InReplyTo(
id = "4d0a8518-9bc5-44a6-8249-c2ed9122f987",
chatter = Chatter(
id = "221570322",
displayName = "djessy728",
login = "djessy728",
),
mentions = listOf("djessy728"),
message = "Salut Antoine, est tu encore en contact avec Mathieu? Et penses tu streamer un peu avec lui?",
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ class TwitchIrcCommandParserTest {
timestamp = Instant.parse("2022-08-23T19:01:58.667Z"),
rewardId = null,
inReplyTo = IrcEvent.Message.ChatMessage.InReplyTo(
userName = "Brankhorst",
userDisplayName = "Brankhorst",
message = "On dirait EVE on line",
id = "7ffcf399-8d69-495c-920c-ea15a96eeee4",
userId = "108193474",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,8 @@ sealed interface ChatEvent {
) {
@Immutable
data class InReplyTo(
val id: String,
val message: String,
val chatter: Chatter,
val message: String?,
val mentions: List<String>,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import fr.outadoc.justchatting.component.chatapi.common.ChatEvent
import fr.outadoc.justchatting.component.chatapi.common.Chatter
import fr.outadoc.justchatting.component.chatapi.common.Icon
import fr.outadoc.justchatting.component.twitch.websocket.irc.model.IrcEvent
import fr.outadoc.justchatting.feature.chat.presentation.ChatPrefixConstants
import fr.outadoc.justchatting.shared.MR
import fr.outadoc.justchatting.utils.core.formatCurrency
import fr.outadoc.justchatting.utils.core.formatNumber
Expand Down Expand Up @@ -291,8 +292,13 @@ class IrcMessageMapper {
}

private fun IrcEvent.Message.ChatMessage.map(): ChatEvent.Message.Body {
val mentions = message.orEmpty().getMentionsPrefix()
val mentionsLength = mentions.sumOf { mention -> mention.length }

return ChatEvent.Message.Body(
message = message.orEmpty(),
message = message.orEmpty()
.drop(mentionsLength)
.removePrefix(" "),
messageId = id,
chatter = Chatter(
id = userId,
Expand All @@ -303,16 +309,15 @@ class IrcMessageMapper {
color = color,
embeddedEmotes = embeddedEmotes.orEmpty().toImmutableList(),
badges = badges.orEmpty().toImmutableList(),
inReplyTo = inReplyTo?.let {
inReplyTo = if (mentions.isNotEmpty()) {
ChatEvent.Message.Body.InReplyTo(
id = inReplyTo.id,
message = inReplyTo.message,
chatter = Chatter(
id = inReplyTo.id,
login = inReplyTo.userLogin,
displayName = inReplyTo.userName,
),
message = inReplyTo?.message,
mentions = mentions.map { mention ->
mention.drop(1)
},
)
} else {
null
},
)
}
Expand Down Expand Up @@ -1174,3 +1179,10 @@ class IrcMessageMapper {
const val SUB_PRIME = "Prime"
}
}

private fun String.getMentionsPrefix(): List<String> {
return split(" ")
.takeWhile { word ->
word.startsWith(ChatPrefixConstants.ChatterPrefix)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ internal fun Map<String, String?>.parseParentMessage(): IrcEvent.Message.ChatMes
message = this["reply-parent-msg-body"] ?: return null,
userId = this["reply-parent-user-id"] ?: return null,
userLogin = this["reply-parent-user-login"] ?: return null,
userName = this["reply-parent-display-name"] ?: return null,
userDisplayName = this["reply-parent-display-name"] ?: return null,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ sealed interface IrcEvent {
@Immutable
data class InReplyTo(
val id: String,
val userName: String,
val message: String,
val userId: String,
val userLogin: String,
val userDisplayName: String,
)

@Immutable
Expand Down

0 comments on commit e66bb85

Please sign in to comment.