Trim whitespace at the end of messages (#2169)
Trim whitespace at the end of messages
This commit is contained in:
committed by
GitHub
parent
936127c682
commit
0e3f0ac6b5
1
changelog.d/2099.bugfix
Normal file
1
changelog.d/2099.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Trim whitespace at the end of messages to ensure we render the right content.
|
||||
@@ -72,7 +72,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
suspend fun create(content: MessageContent, senderDisplayName: String, eventId: EventId?): TimelineItemEventContent {
|
||||
return when (val messageType = content.type) {
|
||||
is EmoteMessageType -> {
|
||||
val emoteBody = "* $senderDisplayName ${messageType.body}"
|
||||
val emoteBody = "* $senderDisplayName ${messageType.body.trimEnd()}"
|
||||
TimelineItemEmoteContent(
|
||||
body = emoteBody,
|
||||
htmlDocument = messageType.formatted?.toHtmlDocument(prefix = "* $senderDisplayName"),
|
||||
@@ -83,7 +83,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
is ImageMessageType -> {
|
||||
val aspectRatio = aspectRatioOf(messageType.info?.width, messageType.info?.height)
|
||||
TimelineItemImageContent(
|
||||
body = messageType.body,
|
||||
body = messageType.body.trimEnd(),
|
||||
mediaSource = messageType.source,
|
||||
thumbnailSource = messageType.info?.thumbnailSource,
|
||||
mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream,
|
||||
@@ -98,7 +98,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
is StickerMessageType -> {
|
||||
val aspectRatio = aspectRatioOf(messageType.info?.width, messageType.info?.height)
|
||||
TimelineItemStickerContent(
|
||||
body = messageType.body,
|
||||
body = messageType.body.trimEnd(),
|
||||
mediaSource = messageType.source,
|
||||
thumbnailSource = messageType.info?.thumbnailSource,
|
||||
mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream,
|
||||
@@ -113,16 +113,17 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
is LocationMessageType -> {
|
||||
val location = Location.fromGeoUri(messageType.geoUri)
|
||||
if (location == null) {
|
||||
val body = messageType.body.trimEnd()
|
||||
TimelineItemTextContent(
|
||||
body = messageType.body,
|
||||
body = body,
|
||||
htmlDocument = null,
|
||||
plainText = messageType.body,
|
||||
plainText = body,
|
||||
formattedBody = null,
|
||||
isEdited = content.isEdited,
|
||||
)
|
||||
} else {
|
||||
TimelineItemLocationContent(
|
||||
body = messageType.body,
|
||||
body = messageType.body.trimEnd(),
|
||||
location = location,
|
||||
description = messageType.description
|
||||
)
|
||||
@@ -131,7 +132,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
is VideoMessageType -> {
|
||||
val aspectRatio = aspectRatioOf(messageType.info?.width, messageType.info?.height)
|
||||
TimelineItemVideoContent(
|
||||
body = messageType.body,
|
||||
body = messageType.body.trimEnd(),
|
||||
thumbnailSource = messageType.info?.thumbnailSource,
|
||||
videoSource = messageType.source,
|
||||
mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream,
|
||||
@@ -146,7 +147,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
}
|
||||
is AudioMessageType -> {
|
||||
TimelineItemAudioContent(
|
||||
body = messageType.body,
|
||||
body = messageType.body.trimEnd(),
|
||||
mediaSource = messageType.source,
|
||||
duration = messageType.info?.duration ?: Duration.ZERO,
|
||||
mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream,
|
||||
@@ -159,7 +160,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
true -> {
|
||||
TimelineItemVoiceContent(
|
||||
eventId = eventId,
|
||||
body = messageType.body,
|
||||
body = messageType.body.trimEnd(),
|
||||
mediaSource = messageType.source,
|
||||
duration = messageType.info?.duration ?: Duration.ZERO,
|
||||
mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream,
|
||||
@@ -168,7 +169,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
}
|
||||
false -> {
|
||||
TimelineItemAudioContent(
|
||||
body = messageType.body,
|
||||
body = messageType.body.trimEnd(),
|
||||
mediaSource = messageType.source,
|
||||
duration = messageType.info?.duration ?: Duration.ZERO,
|
||||
mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream,
|
||||
@@ -181,7 +182,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
is FileMessageType -> {
|
||||
val fileExtension = fileExtensionExtractor.extractFromName(messageType.body)
|
||||
TimelineItemFileContent(
|
||||
body = messageType.body,
|
||||
body = messageType.body.trimEnd(),
|
||||
thumbnailSource = messageType.info?.thumbnailSource,
|
||||
fileSource = messageType.source,
|
||||
mimeType = messageType.info?.mimetype ?: MimeTypes.fromFileExtension(fileExtension),
|
||||
@@ -189,26 +190,33 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
fileExtension = fileExtension
|
||||
)
|
||||
}
|
||||
is NoticeMessageType -> TimelineItemNoticeContent(
|
||||
body = messageType.body,
|
||||
htmlDocument = messageType.formatted?.toHtmlDocument(),
|
||||
formattedBody = parseHtml(messageType.formatted) ?: messageType.body.withLinks(),
|
||||
isEdited = content.isEdited,
|
||||
)
|
||||
is TextMessageType -> {
|
||||
TimelineItemTextContent(
|
||||
body = messageType.body,
|
||||
is NoticeMessageType -> {
|
||||
val body = messageType.body.trimEnd()
|
||||
TimelineItemNoticeContent(
|
||||
body = body,
|
||||
htmlDocument = messageType.formatted?.toHtmlDocument(),
|
||||
formattedBody = parseHtml(messageType.formatted) ?: messageType.body.withLinks(),
|
||||
formattedBody = parseHtml(messageType.formatted) ?:body.withLinks(),
|
||||
isEdited = content.isEdited,
|
||||
)
|
||||
}
|
||||
is TextMessageType -> {
|
||||
val body = messageType.body.trimEnd()
|
||||
TimelineItemTextContent(
|
||||
body = body,
|
||||
htmlDocument = messageType.formatted?.toHtmlDocument(),
|
||||
formattedBody = parseHtml(messageType.formatted) ?: body.withLinks(),
|
||||
isEdited = content.isEdited,
|
||||
)
|
||||
}
|
||||
is OtherMessageType -> {
|
||||
val body = messageType.body.trimEnd()
|
||||
TimelineItemTextContent(
|
||||
body = body,
|
||||
htmlDocument = null,
|
||||
formattedBody = body.withLinks(),
|
||||
isEdited = content.isEdited,
|
||||
)
|
||||
}
|
||||
is OtherMessageType -> TimelineItemTextContent(
|
||||
body = messageType.body,
|
||||
htmlDocument = null,
|
||||
formattedBody = messageType.body.withLinks(),
|
||||
isEdited = content.isEdited,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +233,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||
private fun parseHtml(formattedBody: FormattedBody?, prefix: String? = null): CharSequence? {
|
||||
if (formattedBody == null || formattedBody.format != MessageFormat.HTML) return null
|
||||
val result = htmlConverterProvider.provide()
|
||||
.fromHtmlToSpans(formattedBody.body)
|
||||
.fromHtmlToSpans(formattedBody.body.trimEnd())
|
||||
.withFixedURLSpans()
|
||||
return if (prefix != null) {
|
||||
buildSpannedString {
|
||||
|
||||
@@ -32,7 +32,11 @@ import org.jsoup.nodes.Document
|
||||
* @param prefix if not null, the prefix will be inserted at the beginning of the message.
|
||||
*/
|
||||
fun FormattedBody.toHtmlDocument(prefix: String? = null): Document? {
|
||||
return takeIf { it.format == MessageFormat.HTML }?.body?.let { formattedBody ->
|
||||
return takeIf { it.format == MessageFormat.HTML }?.body
|
||||
// Trim whitespace at the end to avoid having wrong rendering of the message.
|
||||
// We don't trim the start in case it's used as indentation.
|
||||
?.trimEnd()
|
||||
?.let { formattedBody ->
|
||||
val dom = if (prefix != null) {
|
||||
Jsoup.parse("$prefix $formattedBody")
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user