Fix formatting inconsistencies in latest event summaries (#6855)

* Fix message type prefixes formatting inconsistencies

* Use new string for the poll summary prefix instead of the A11y text. Also add tests check for the bold spans.

---------

Co-authored-by: Jorge Martín <jorgem@element.io>
This commit is contained in:
bxdxnn 2026-05-25 12:40:25 +03:00 committed by GitHub
parent ff263e611e
commit 23abc91510
4 changed files with 38 additions and 8 deletions

View file

@ -93,8 +93,8 @@ class DefaultRoomLatestEventFormatter(
message.prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing) message.prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing)
} }
is StickerContent -> { is StickerContent -> {
val message = sp.getString(CommonStrings.common_sticker) + " (" + content.bestDescription + ")" content.bestDescription.prefixWith(sp.getString(CommonStrings.common_sticker))
message.prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing) .prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing)
} }
is UnableToDecryptContent -> { is UnableToDecryptContent -> {
val message = sp.getString(CommonStrings.common_waiting_for_decryption_key) val message = sp.getString(CommonStrings.common_waiting_for_decryption_key)
@ -110,8 +110,8 @@ class DefaultRoomLatestEventFormatter(
stateContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing, RenderingMode.RoomList) stateContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing, RenderingMode.RoomList)
} }
is PollContent -> { is PollContent -> {
val message = sp.getString(CommonStrings.common_poll_summary, content.question) content.question.prefixWith(sp.getString(CommonStrings.common_poll_summary_prefix))
message.prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing) .prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing)
} }
is FailedToParseMessageLikeContent, is FailedToParseStateContent, is UnknownContent -> { is FailedToParseMessageLikeContent, is FailedToParseStateContent, is UnknownContent -> {
val message = sp.getString(CommonStrings.common_unsupported_event) val message = sp.getString(CommonStrings.common_unsupported_event)

View file

@ -20,6 +20,10 @@ internal fun CharSequence.prefixWith(prefix: String): AnnotatedString {
append(prefix) append(prefix)
} }
append(": ") append(": ")
append(this@prefixWith) if (this@prefixWith is AnnotatedString) {
append(this@prefixWith)
} else {
append(this@prefixWith.toString())
}
} }
} }

View file

@ -10,6 +10,7 @@ package io.element.android.libraries.eventformatter.impl
import android.content.Context import android.content.Context
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage import com.google.common.truth.Truth.assertWithMessage
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
@ -103,7 +104,14 @@ class DefaultRoomLatestEventFormatterTest {
val info = ImageInfo(null, null, null, null, null, null, null) val info = ImageInfo(null, null, null, null, null, null, null)
val message = createLatestEvent(false, null, aStickerContent(body, info, aMediaSource(url = "url"))) val message = createLatestEvent(false, null, aStickerContent(body, info, aMediaSource(url = "url")))
val result = formatter.format(message, false) val result = formatter.format(message, false)
val expectedBody = someoneElseId.value + ": Sticker (a sticker body)" val expectedBody = someoneElseId.value + ": Sticker: a sticker body"
// Check we have formatting
assertThat(result is AnnotatedString).isTrue()
// And there is a bold span for the 'Sticker' part
val boldSpanStyle = (result as AnnotatedString).spanStyles.lastOrNull { it.item.fontWeight == FontWeight.Bold }
assertThat(boldSpanStyle).isNotNull()
val spanStart = someoneElseId.value.length + 2
assertThat(boldSpanStyle!!.start..boldSpanStyle.end).isEqualTo(spanStart..spanStart + 7)
assertThat(result.toString()).isEqualTo(expectedBody) assertThat(result.toString()).isEqualTo(expectedBody)
} }
@ -909,10 +917,18 @@ class DefaultRoomLatestEventFormatterTest {
val pollContent = aPollContent() val pollContent = aPollContent()
val mineContentEvent = createLatestEvent(sentByYou = true, senderDisplayName = "Alice", content = pollContent) val mineContentEvent = createLatestEvent(sentByYou = true, senderDisplayName = "Alice", content = pollContent)
assertThat(formatter.format(mineContentEvent, true)).isEqualTo("Poll: Do you like polls?") assertThat(formatter.format(mineContentEvent, true).toString()).isEqualTo("Poll: Do you like polls?")
val contentEvent = createLatestEvent(sentByYou = false, senderDisplayName = "Bob", content = pollContent) val contentEvent = createLatestEvent(sentByYou = false, senderDisplayName = "Bob", content = pollContent)
assertThat(formatter.format(contentEvent, true)).isEqualTo("Poll: Do you like polls?") assertThat(formatter.format(contentEvent, true).toString()).isEqualTo("Poll: Do you like polls?")
val result = formatter.format(contentEvent, true)
// Check we have formatting
assertThat(result is AnnotatedString).isTrue()
// And there is a bold span for the 'Poll' part
val boldSpanStyle = (result as AnnotatedString).spanStyles.lastOrNull { it.item.fontWeight == FontWeight.Bold }
assertThat(boldSpanStyle).isNotNull()
assertThat(boldSpanStyle!!.start..boldSpanStyle.end).isEqualTo(0..4)
} }
@Test @Test
@ -925,6 +941,15 @@ class DefaultRoomLatestEventFormatterTest {
val contentEvent = createLatestEvent(sentByYou = false, senderDisplayName = "Bob", content = pollContent) val contentEvent = createLatestEvent(sentByYou = false, senderDisplayName = "Bob", content = pollContent)
assertThat(formatter.format(contentEvent, false).toString()).isEqualTo("Bob: Poll: Do you like polls?") assertThat(formatter.format(contentEvent, false).toString()).isEqualTo("Bob: Poll: Do you like polls?")
val result = formatter.format(contentEvent, false)
// Check we have formatting
assertThat(result is AnnotatedString).isTrue()
// And there is a bold span for the 'Poll' part
val boldSpanStyle = (result as AnnotatedString).spanStyles.lastOrNull { it.item.fontWeight == FontWeight.Bold }
assertThat(boldSpanStyle).isNotNull()
val spanStart = "Bob".length + 2
assertThat(boldSpanStyle!!.start..boldSpanStyle.end).isEqualTo(spanStart..spanStart + 4)
} }
// endregion // endregion

View file

@ -303,6 +303,7 @@ Reason: %1$s."</string>
<string name="common_please_wait">"Please wait…"</string> <string name="common_please_wait">"Please wait…"</string>
<string name="common_poll_end_confirmation">"Are you sure you want to end this poll?"</string> <string name="common_poll_end_confirmation">"Are you sure you want to end this poll?"</string>
<string name="common_poll_summary">"Poll: %1$s"</string> <string name="common_poll_summary">"Poll: %1$s"</string>
<string name="common_poll_summary_prefix">"Poll"</string>
<string name="common_poll_total_votes">"Total votes: %1$s"</string> <string name="common_poll_total_votes">"Total votes: %1$s"</string>
<string name="common_poll_undisclosed_text">"Results will show after the poll has ended"</string> <string name="common_poll_undisclosed_text">"Results will show after the poll has ended"</string>
<plurals name="common_poll_votes_count"> <plurals name="common_poll_votes_count">