Merge pull request #1498 from vector-im/feature/bma/renderEmote
Render emote
This commit is contained in:
commit
1923417be9
8 changed files with 28 additions and 17 deletions
1
changelog.d/1497.feature
Normal file
1
changelog.d/1497.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Improve rendering of m.emote.
|
||||||
|
|
@ -24,6 +24,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParse
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
||||||
|
|
@ -49,7 +50,10 @@ class TimelineItemContentFactory @Inject constructor(
|
||||||
return when (val itemContent = eventTimelineItem.content) {
|
return when (val itemContent = eventTimelineItem.content) {
|
||||||
is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent)
|
is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent)
|
||||||
is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent)
|
is FailedToParseStateContent -> failedToParseStateFactory.create(itemContent)
|
||||||
is MessageContent -> messageFactory.create(itemContent)
|
is MessageContent -> {
|
||||||
|
val senderDisplayName = (eventTimelineItem.senderProfile as? ProfileTimelineDetails.Ready)?.displayName ?: eventTimelineItem.sender.value
|
||||||
|
messageFactory.create(itemContent, senderDisplayName)
|
||||||
|
}
|
||||||
is ProfileChangeContent -> profileChangeFactory.create(eventTimelineItem)
|
is ProfileChangeContent -> profileChangeFactory.create(eventTimelineItem)
|
||||||
is RedactedContent -> redactedMessageFactory.create(itemContent)
|
is RedactedContent -> redactedMessageFactory.create(itemContent)
|
||||||
is RoomMembershipContent -> roomMembershipFactory.create(eventTimelineItem)
|
is RoomMembershipContent -> roomMembershipFactory.create(eventTimelineItem)
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessa
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -47,11 +48,11 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||||
private val fileExtensionExtractor: FileExtensionExtractor,
|
private val fileExtensionExtractor: FileExtensionExtractor,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun create(content: MessageContent): TimelineItemEventContent {
|
fun create(content: MessageContent, senderDisplayName: String): TimelineItemEventContent {
|
||||||
return when (val messageType = content.type) {
|
return when (val messageType = content.type ?: UnknownMessageType) {
|
||||||
is EmoteMessageType -> TimelineItemEmoteContent(
|
is EmoteMessageType -> TimelineItemEmoteContent(
|
||||||
body = messageType.body,
|
body = "* $senderDisplayName ${messageType.body}",
|
||||||
htmlDocument = messageType.formatted?.toHtmlDocument(),
|
htmlDocument = messageType.formatted?.toHtmlDocument(prefix = "* senderDisplayName"),
|
||||||
isEdited = content.isEdited,
|
isEdited = content.isEdited,
|
||||||
)
|
)
|
||||||
is ImageMessageType -> {
|
is ImageMessageType -> {
|
||||||
|
|
@ -130,7 +131,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||||
htmlDocument = messageType.formatted?.toHtmlDocument(),
|
htmlDocument = messageType.formatted?.toHtmlDocument(),
|
||||||
isEdited = content.isEdited,
|
isEdited = content.isEdited,
|
||||||
)
|
)
|
||||||
else -> TimelineItemUnknownContent
|
UnknownMessageType -> TimelineItemUnknownContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,12 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
|
|
||||||
fun FormattedBody.toHtmlDocument(): Document? {
|
fun FormattedBody.toHtmlDocument(prefix: String? = null): Document? {
|
||||||
return takeIf { it.format == MessageFormat.HTML }?.body?.let { formattedBody ->
|
return takeIf { it.format == MessageFormat.HTML }?.body?.let { formattedBody ->
|
||||||
Jsoup.parse(formattedBody)
|
if (prefix != null) {
|
||||||
|
Jsoup.parse("$prefix $formattedBody")
|
||||||
|
} else {
|
||||||
|
Jsoup.parse(formattedBody)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
val internalMessage = when (messageType) {
|
val internalMessage = when (messageType) {
|
||||||
// Doesn't need a prefix
|
// Doesn't need a prefix
|
||||||
is EmoteMessageType -> {
|
is EmoteMessageType -> {
|
||||||
return "- $senderDisplayName ${messageType.body}"
|
return "* $senderDisplayName ${messageType.body}"
|
||||||
}
|
}
|
||||||
is TextMessageType -> {
|
is TextMessageType -> {
|
||||||
messageType.body
|
messageType.body
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ class DefaultRoomLastMessageFormatterTests {
|
||||||
is ImageMessageType -> "Image"
|
is ImageMessageType -> "Image"
|
||||||
is FileMessageType -> "File"
|
is FileMessageType -> "File"
|
||||||
is LocationMessageType -> "Shared location"
|
is LocationMessageType -> "Shared location"
|
||||||
is EmoteMessageType -> "- $senderName ${type.body}"
|
is EmoteMessageType -> "* $senderName ${type.body}"
|
||||||
is TextMessageType, is NoticeMessageType -> body
|
is TextMessageType, is NoticeMessageType -> body
|
||||||
UnknownMessageType -> "Unsupported event"
|
UnknownMessageType -> "Unsupported event"
|
||||||
}
|
}
|
||||||
|
|
@ -217,7 +217,7 @@ class DefaultRoomLastMessageFormatterTests {
|
||||||
is ImageMessageType -> "$senderName: Image"
|
is ImageMessageType -> "$senderName: Image"
|
||||||
is FileMessageType -> "$senderName: File"
|
is FileMessageType -> "$senderName: File"
|
||||||
is LocationMessageType -> "$senderName: Shared location"
|
is LocationMessageType -> "$senderName: Shared location"
|
||||||
is EmoteMessageType -> "- $senderName ${type.body}"
|
is EmoteMessageType -> "* $senderName ${type.body}"
|
||||||
is TextMessageType, is NoticeMessageType -> "$senderName: $body"
|
is TextMessageType, is NoticeMessageType -> "$senderName: $body"
|
||||||
UnknownMessageType -> "$senderName: Unsupported event"
|
UnknownMessageType -> "$senderName: Unsupported event"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ sealed interface InReplyTo {
|
||||||
data object Error : InReplyTo
|
data object Error : InReplyTo
|
||||||
}
|
}
|
||||||
|
|
||||||
object RedactedContent : EventContent
|
data object RedactedContent : EventContent
|
||||||
|
|
||||||
data class StickerContent(
|
data class StickerContent(
|
||||||
val body: String,
|
val body: String,
|
||||||
|
|
@ -124,11 +124,11 @@ data class FailedToParseStateContent(
|
||||||
val error: String
|
val error: String
|
||||||
) : EventContent
|
) : EventContent
|
||||||
|
|
||||||
object UnknownContent : EventContent
|
data object UnknownContent : EventContent
|
||||||
|
|
||||||
sealed interface MessageType
|
sealed interface MessageType
|
||||||
|
|
||||||
object UnknownMessageType : MessageType
|
data object UnknownMessageType : MessageType
|
||||||
|
|
||||||
enum class MessageFormat {
|
enum class MessageFormat {
|
||||||
HTML, UNKNOWN
|
HTML, UNKNOWN
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
noisy = isNoisy,
|
noisy = isNoisy,
|
||||||
timestamp = this.timestamp,
|
timestamp = this.timestamp,
|
||||||
senderName = senderDisplayName,
|
senderName = senderDisplayName,
|
||||||
body = descriptionFromMessageContent(content),
|
body = descriptionFromMessageContent(content, senderDisplayName ?: content.senderId.value),
|
||||||
imageUriString = this.contentUrl,
|
imageUriString = this.contentUrl,
|
||||||
roomName = roomDisplayName,
|
roomName = roomDisplayName,
|
||||||
roomIsDirect = isDirect,
|
roomIsDirect = isDirect,
|
||||||
|
|
@ -133,7 +133,7 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
NotificationContent.MessageLike.KeyVerificationStart -> null.also {
|
NotificationContent.MessageLike.KeyVerificationStart -> null.also {
|
||||||
Timber.tag(loggerTag.value).d("Ignoring notification for verification ${content.javaClass.simpleName}")
|
Timber.tag(loggerTag.value).d("Ignoring notification for verification ${content.javaClass.simpleName}")
|
||||||
}
|
}
|
||||||
is NotificationContent.MessageLike.Poll -> {
|
is NotificationContent.MessageLike.Poll -> {
|
||||||
buildNotifiableMessageEvent(
|
buildNotifiableMessageEvent(
|
||||||
sessionId = userId,
|
sessionId = userId,
|
||||||
senderId = content.senderId,
|
senderId = content.senderId,
|
||||||
|
|
@ -205,10 +205,11 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
|
|
||||||
private fun descriptionFromMessageContent(
|
private fun descriptionFromMessageContent(
|
||||||
content: NotificationContent.MessageLike.RoomMessage,
|
content: NotificationContent.MessageLike.RoomMessage,
|
||||||
|
senderDisplayName: String,
|
||||||
): String {
|
): String {
|
||||||
return when (val messageType = content.messageType) {
|
return when (val messageType = content.messageType) {
|
||||||
is AudioMessageType -> messageType.body
|
is AudioMessageType -> messageType.body
|
||||||
is EmoteMessageType -> messageType.body
|
is EmoteMessageType -> "* $senderDisplayName ${messageType.body}"
|
||||||
is FileMessageType -> messageType.body
|
is FileMessageType -> messageType.body
|
||||||
is ImageMessageType -> messageType.body
|
is ImageMessageType -> messageType.body
|
||||||
is NoticeMessageType -> messageType.body
|
is NoticeMessageType -> messageType.body
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue