From 3df85017afb43d24610a955889bca90eab325a87 Mon Sep 17 00:00:00 2001 From: bxdxnn <267911624+bxdxnn@users.noreply.github.com> Date: Mon, 25 May 2026 12:40:25 +0300 Subject: [PATCH] Fix formatting inconsistencies in latest event summaries (#6855) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- .../impl/DefaultRoomLatestEventFormatter.kt | 8 ++--- .../eventformatter/impl/PrefixWith.kt | 6 +++- .../DefaultRoomLatestEventFormatterTest.kt | 31 +++++++++++++++++-- .../src/main/res/values/localazy.xml | 1 + 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt index d234e7b239..e8a462da16 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt @@ -93,8 +93,8 @@ class DefaultRoomLatestEventFormatter( message.prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing) } is StickerContent -> { - val message = sp.getString(CommonStrings.common_sticker) + " (" + content.bestDescription + ")" - message.prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing) + content.bestDescription.prefixWith(sp.getString(CommonStrings.common_sticker)) + .prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing) } is UnableToDecryptContent -> { val message = sp.getString(CommonStrings.common_waiting_for_decryption_key) @@ -110,8 +110,8 @@ class DefaultRoomLatestEventFormatter( stateContentFormatter.format(content, senderDisambiguatedDisplayName, isOutgoing, RenderingMode.RoomList) } is PollContent -> { - val message = sp.getString(CommonStrings.common_poll_summary, content.question) - message.prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing) + content.question.prefixWith(sp.getString(CommonStrings.common_poll_summary_prefix)) + .prefixIfNeeded(senderDisambiguatedDisplayName, isDmRoom, isOutgoing) } is FailedToParseMessageLikeContent, is FailedToParseStateContent, is UnknownContent -> { val message = sp.getString(CommonStrings.common_unsupported_event) diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/PrefixWith.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/PrefixWith.kt index 51fdccf256..1a04893e07 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/PrefixWith.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/PrefixWith.kt @@ -20,6 +20,10 @@ internal fun CharSequence.prefixWith(prefix: String): AnnotatedString { append(prefix) } append(": ") - append(this@prefixWith) + if (this@prefixWith is AnnotatedString) { + append(this@prefixWith) + } else { + append(this@prefixWith.toString()) + } } } diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt index e0613ed008..2e55fb0999 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt @@ -10,6 +10,7 @@ package io.element.android.libraries.eventformatter.impl import android.content.Context 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.assertWithMessage 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 message = createLatestEvent(false, null, aStickerContent(body, info, aMediaSource(url = "url"))) 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) } @@ -909,10 +917,18 @@ class DefaultRoomLatestEventFormatterTest { val pollContent = aPollContent() 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) - 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 @@ -925,6 +941,15 @@ class DefaultRoomLatestEventFormatterTest { val contentEvent = createLatestEvent(sentByYou = false, senderDisplayName = "Bob", content = pollContent) 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 diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index e89d45b228..e5bc31396f 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -303,6 +303,7 @@ Reason: %1$s." "Please wait…" "Are you sure you want to end this poll?" "Poll: %1$s" + "Poll" "Total votes: %1$s" "Results will show after the poll has ended"