Add item count text as the placeholder for in reply to box for galleries

This commit is contained in:
bxdxnn
2026-07-08 20:01:21 +00:00
parent 3642065202
commit 566b0c6f86
3 changed files with 270 additions and 0 deletions
@@ -10,12 +10,15 @@ package io.element.android.libraries.matrix.ui.messages.reply
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.GalleryItemType
import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.LegacyCallInviteContent
import io.element.android.libraries.matrix.api.timeline.item.event.LiveLocationContent
@@ -35,6 +38,7 @@ import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToMetadata.Text
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToMetadata.Thumbnail
import io.element.android.libraries.ui.strings.CommonPlurals
import io.element.android.libraries.ui.strings.CommonStrings
@Immutable
@@ -104,6 +108,44 @@ internal fun InReplyToDetails.Ready.metadata(hideImage: Boolean): InReplyToMetad
type = AttachmentThumbnailType.Voice,
)
)
is GalleryMessageType -> {
val caption = textContent?.takeIf { it.isNotBlank() }
val isMediaGallery = type.items.all { it is GalleryItemType.Image || it is GalleryItemType.Video }
val countPlural = if (isMediaGallery) {
CommonPlurals.common_gallery_reply_media_items
} else {
CommonPlurals.common_gallery_reply_attachments
}
val text = caption ?: pluralStringResource(countPlural, type.items.size, type.items.size)
if (isMediaGallery) {
val firstMediaItem = type.items.firstOrNull { it is GalleryItemType.Image || it is GalleryItemType.Video }
val thumbnailSource = when (firstMediaItem) {
is GalleryItemType.Image -> (firstMediaItem.content.info?.thumbnailSource ?: firstMediaItem.content.source).takeUnless { hideImage }
is GalleryItemType.Video -> firstMediaItem.content.info?.thumbnailSource?.takeUnless { hideImage }
else -> null
}
val blurHash = when (firstMediaItem) {
is GalleryItemType.Image -> firstMediaItem.content.info?.blurhash
is GalleryItemType.Video -> firstMediaItem.content.info?.blurhash
else -> null
}
Thumbnail(
AttachmentThumbnailInfo(
thumbnailSource = thumbnailSource,
textContent = text,
type = AttachmentThumbnailType.Image,
blurHash = blurHash,
)
)
} else {
Thumbnail(
AttachmentThumbnailInfo(
textContent = text,
type = AttachmentThumbnailType.File,
)
)
}
}
else -> Text(textContent ?: eventContent.body)
}
is StickerContent -> Thumbnail(
@@ -24,6 +24,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.GalleryItemType
import io.element.android.libraries.matrix.api.timeline.item.event.GalleryMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.OtherState
@@ -407,6 +409,226 @@ class InReplyToMetadataKtTest : RobolectricTest() {
}
}
@Test
fun `a gallery message with all media items shows media count`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
withConfigurationAndContext {
anInReplyToDetailsReady(
eventContent = aMessageContent(
messageType = GalleryMessageType(
body = "",
formatted = null,
items = listOf(
GalleryItemType.Image(
ImageMessageType(
filename = "image1.jpg",
caption = null,
formattedCaption = null,
source = aMediaSource(),
info = anImageInfo(),
)
),
GalleryItemType.Image(
ImageMessageType(
filename = "image2.jpg",
caption = null,
formattedCaption = null,
source = aMediaSource(),
info = anImageInfo(),
)
),
),
)
),
textContent = "",
).metadata(hideImage = false)
}
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
InReplyToMetadata.Thumbnail(
attachmentThumbnailInfo = AttachmentThumbnailInfo(
thumbnailSource = aMediaSource(),
textContent = "2 media items…",
type = AttachmentThumbnailType.Image,
blurHash = A_BLUR_HASH,
)
)
)
}
}
}
@Test
fun `a gallery message with attachment items shows attachment count`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
withConfigurationAndContext {
anInReplyToDetailsReady(
eventContent = aMessageContent(
messageType = GalleryMessageType(
body = "",
formatted = null,
items = listOf(
GalleryItemType.File(
FileMessageType(
filename = "doc1.pdf",
caption = null,
formattedCaption = null,
source = aMediaSource(),
info = FileInfo(
mimetype = null,
size = null,
thumbnailInfo = null,
thumbnailSource = null,
),
)
),
GalleryItemType.File(
FileMessageType(
filename = "doc2.pdf",
caption = null,
formattedCaption = null,
source = aMediaSource(),
info = FileInfo(
mimetype = null,
size = null,
thumbnailInfo = null,
thumbnailSource = null,
),
)
),
),
)
),
textContent = "",
).metadata(hideImage = false)
}
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
InReplyToMetadata.Thumbnail(
attachmentThumbnailInfo = AttachmentThumbnailInfo(
thumbnailSource = null,
textContent = "2 attachments…",
type = AttachmentThumbnailType.File,
blurHash = null,
)
)
)
}
}
}
@Test
fun `a gallery message with caption shows caption instead of count`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
withConfigurationAndContext {
anInReplyToDetailsReady(
eventContent = aMessageContent(
messageType = GalleryMessageType(
body = "My vacation photos",
formatted = null,
items = listOf(
GalleryItemType.Image(
ImageMessageType(
filename = "image1.jpg",
caption = null,
formattedCaption = null,
source = aMediaSource(),
info = anImageInfo(),
)
),
GalleryItemType.Image(
ImageMessageType(
filename = "image2.jpg",
caption = null,
formattedCaption = null,
source = aMediaSource(),
info = anImageInfo(),
)
),
),
)
),
textContent = "My vacation photos",
).metadata(hideImage = false)
}
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
InReplyToMetadata.Thumbnail(
attachmentThumbnailInfo = AttachmentThumbnailInfo(
thumbnailSource = aMediaSource(),
textContent = "My vacation photos",
type = AttachmentThumbnailType.Image,
blurHash = A_BLUR_HASH,
)
)
)
}
}
}
@Test
fun `a gallery message with attachment items and caption shows caption instead of count`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
withConfigurationAndContext {
anInReplyToDetailsReady(
eventContent = aMessageContent(
messageType = GalleryMessageType(
body = "My documents",
formatted = null,
items = listOf(
GalleryItemType.File(
FileMessageType(
filename = "doc1.pdf",
caption = null,
formattedCaption = null,
source = aMediaSource(),
info = FileInfo(
mimetype = null,
size = null,
thumbnailInfo = null,
thumbnailSource = null,
),
)
),
GalleryItemType.File(
FileMessageType(
filename = "doc2.pdf",
caption = null,
formattedCaption = null,
source = aMediaSource(),
info = FileInfo(
mimetype = null,
size = null,
thumbnailInfo = null,
thumbnailSource = null,
),
)
),
),
)
),
textContent = "My documents",
).metadata(hideImage = false)
}
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
InReplyToMetadata.Thumbnail(
attachmentThumbnailInfo = AttachmentThumbnailInfo(
thumbnailSource = null,
textContent = "My documents",
type = AttachmentThumbnailType.File,
blurHash = null,
)
)
)
}
}
}
@Test
fun `a poll content`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
@@ -8,4 +8,10 @@
<resources>
<string name="action_mark_as_read">"Mark as read"</string>
<string name="a11y_jump_to_unread_messages">"Jump to first unread message"</string>
<plurals name="common_gallery_reply_media_items">
<item quantity="other">"%1$d media items…"</item>
</plurals>
<plurals name="common_gallery_reply_attachments">
<item quantity="other">"%1$d attachments…"</item>
</plurals>
</resources>