Fixing parsing of outcoming messages for @room chip (missing incoming messages)

This commit is contained in:
Maxime Naturel 2022-02-11 17:29:33 +01:00
parent 2beff8d4cd
commit fb2401d0b1
5 changed files with 89 additions and 33 deletions

View File

@ -43,8 +43,9 @@ sealed class MatrixItem(
override fun updateAvatar(newAvatar: String?) = copy(avatarUrl = newAvatar)
}
// TODO is it correct to represent it by a Matrix Item ? => to confirm
data class EveryoneInRoomItem(override val id: String,
override val displayName: String? = null,
override val displayName: String = NOTIFY_EVERYONE,
override val avatarUrl: String? = null,
val roomDisplayName: String? = null) :
MatrixItem(id, displayName, avatarUrl) {
@ -190,7 +191,7 @@ fun RoomSummary.toMatrixItem() = if (roomType == RoomType.SPACE) {
fun RoomSummary.toRoomAliasMatrixItem() = MatrixItem.RoomAliasItem(canonicalAlias ?: roomId, displayName, avatarUrl)
fun RoomSummary.toEveryoneInRoomMatrixItem() = MatrixItem.EveryoneInRoomItem(roomId, MatrixItem.NOTIFY_EVERYONE, avatarUrl, displayName)
fun RoomSummary.toEveryoneInRoomMatrixItem() = MatrixItem.EveryoneInRoomItem(id = roomId, avatarUrl = avatarUrl, roomDisplayName = displayName)
// If no name is available, use room alias as Riot-Web does
fun PublicRoom.toMatrixItem() = MatrixItem.RoomItem(roomId, name ?: getPrimaryAlias() ?: "", avatarUrl)

View File

@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.room.send.pills
import android.text.SpannableString
import org.matrix.android.sdk.api.session.room.send.MatrixItemSpan
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.internal.session.displayname.DisplayNameResolver
import java.util.Collections
import javax.inject.Inject
@ -51,6 +52,8 @@ internal class TextPillsUtils @Inject constructor(
val pills = spannableString
?.getSpans(0, text.length, MatrixItemSpan::class.java)
?.map { MentionLinkSpec(it, spannableString.getSpanStart(it), spannableString.getSpanEnd(it)) }
// we use the raw text for @room notification instead of a link
?.filterNot { it.span.matrixItem is MatrixItem.EveryoneInRoomItem }
?.toMutableList()
?.takeIf { it.isNotEmpty() }
?: return null

View File

@ -238,7 +238,7 @@ class AutoCompleter @AssistedInject constructor(
// Adding trailing space " " or ": " if the user started mention someone
val displayNameSuffix =
if (firstChar == TRIGGER_AUTO_COMPLETE_MEMBERS && startIndex == 0) {
if (matrixItem is MatrixItem.UserItem) {
": "
} else {
" "

View File

@ -549,6 +549,7 @@ class MessageItemFactory @Inject constructor(
highlight: Boolean,
callback: TimelineEventController.Callback?,
attributes: AbsMessageItem.Attributes): MessageTextItem? {
// TODO process body to add pills for @room texts: create a dedicated renderer with PillsPostProcessor ?
val bindingOptions = spanUtils.getBindingOptions(body)
val linkifiedBody = body.linkify(callback)

View File

@ -43,51 +43,102 @@ class PillsPostProcessor @AssistedInject constructor(@Assisted private val roomI
fun create(roomId: String?): PillsPostProcessor
}
///////////////////////////////////////////////////////////////////////////
// SPECIALIZATION
///////////////////////////////////////////////////////////////////////////
override fun afterRender(renderedText: Spannable) {
addPillSpans(renderedText, roomId)
}
///////////////////////////////////////////////////////////////////////////
// HELPER METHODS
///////////////////////////////////////////////////////////////////////////
private fun addPillSpans(renderedText: Spannable, roomId: String?) {
addLinkSpans(renderedText, roomId)
roomId?.let { id -> addRawTextSpans(renderedText, id) }
}
private fun addPillSpan(
renderedText: Spannable,
pillSpan: PillImageSpan,
startSpan: Int,
endSpan: Int
) {
renderedText.setSpan(pillSpan, startSpan, endSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
private fun addLinkSpans(renderedText: Spannable, roomId: String?) {
// We let markdown handle links and then we add PillImageSpan if needed.
val linkSpans = renderedText.getSpans(0, renderedText.length, LinkSpan::class.java)
linkSpans.forEach { linkSpan ->
val pillSpan = linkSpan.createPillSpan(roomId) ?: return@forEach
val startSpan = renderedText.getSpanStart(linkSpan)
val endSpan = renderedText.getSpanEnd(linkSpan)
renderedText.setSpan(pillSpan, startSpan, endSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
addPillSpan(renderedText, pillSpan, startSpan, endSpan)
}
}
// TODO move this into another PostProcessor when there is no html
private fun addRawTextSpans(renderedText: Spannable, roomId: String) {
if (renderedText.contains(MatrixItem.NOTIFY_EVERYONE)) {
addNotifyEveryoneSpans(renderedText, roomId)
}
}
private fun addNotifyEveryoneSpans(renderedText: Spannable, roomId: String) {
val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.getRoomSummary(roomId)
val matrixItem = MatrixItem.EveryoneInRoomItem(
id = roomId,
avatarUrl = room?.avatarUrl,
roomDisplayName = room?.displayName
)
val pillSpan = createPillImageSpan(matrixItem)
// search for notify everyone text
var foundIndex = renderedText.indexOf(MatrixItem.NOTIFY_EVERYONE, 0)
while (foundIndex >= 0) {
val endSpan = foundIndex + MatrixItem.NOTIFY_EVERYONE.length
addPillSpan(renderedText, pillSpan, foundIndex, endSpan)
foundIndex = renderedText.indexOf(MatrixItem.NOTIFY_EVERYONE, endSpan)
}
}
private fun createPillImageSpan(matrixItem: MatrixItem) =
PillImageSpan(GlideApp.with(context), avatarRenderer, context, matrixItem)
private fun LinkSpan.createPillSpan(roomId: String?): PillImageSpan? {
// TODO handle @room text to create associated chip
val permalinkData = PermalinkParser.parse(url)
val matrixItem = when (permalinkData) {
is PermalinkData.UserLink -> {
val matrixItem = when (val permalinkData = PermalinkParser.parse(url)) {
is PermalinkData.UserLink -> permalinkData.toMatrixItem(roomId)
is PermalinkData.RoomLink -> permalinkData.toMatrixItem()
is PermalinkData.GroupLink -> permalinkData.toMatrixItem()
else -> null
} ?: return null
return createPillImageSpan(matrixItem)
}
private fun PermalinkData.UserLink.toMatrixItem(roomId: String?): MatrixItem? =
if (roomId == null) {
sessionHolder.getSafeActiveSession()?.getUser(permalinkData.userId)?.toMatrixItem()
sessionHolder.getSafeActiveSession()?.getUser(userId)?.toMatrixItem()
} else {
sessionHolder.getSafeActiveSession()?.getRoomMember(permalinkData.userId, roomId)?.toMatrixItem()
sessionHolder.getSafeActiveSession()?.getRoomMember(userId, roomId)?.toMatrixItem()
}
}
is PermalinkData.RoomLink -> {
if (permalinkData.eventId == null) {
val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.getRoomSummary(permalinkData.roomIdOrAlias)
if (permalinkData.isRoomAlias) {
MatrixItem.RoomAliasItem(permalinkData.roomIdOrAlias, room?.displayName, room?.avatarUrl)
} else {
MatrixItem.RoomItem(permalinkData.roomIdOrAlias, room?.displayName, room?.avatarUrl)
private fun PermalinkData.RoomLink.toMatrixItem(): MatrixItem? =
if (eventId == null) {
val room: RoomSummary? = sessionHolder.getSafeActiveSession()?.getRoomSummary(roomIdOrAlias)
when {
isRoomAlias -> MatrixItem.RoomAliasItem(roomIdOrAlias, room?.displayName, room?.avatarUrl)
else -> MatrixItem.RoomItem(roomIdOrAlias, room?.displayName, room?.avatarUrl)
}
} else {
// Exclude event link (used in reply events, we do not want to pill the "in reply to")
null
}
}
is PermalinkData.GroupLink -> {
val group = sessionHolder.getSafeActiveSession()?.getGroupSummary(permalinkData.groupId)
MatrixItem.GroupItem(permalinkData.groupId, group?.displayName, group?.avatarUrl)
}
else -> null
} ?: return null
return PillImageSpan(GlideApp.with(context), avatarRenderer, context, matrixItem)
private fun PermalinkData.GroupLink.toMatrixItem(): MatrixItem? {
val group = sessionHolder.getSafeActiveSession()?.getGroupSummary(groupId)
return MatrixItem.GroupItem(groupId, group?.displayName, group?.avatarUrl)
}
}