Add settings to hide images and videos in the timeline.

Hide images, videos and stickers in the timeline.
Disable click on hidden content. It must be revealed first.
Add preview without BlurHash.
Also hide image in thumbnails.
This commit is contained in:
Benoit Marty 2024-10-02 19:47:44 +02:00
parent 98d9abecd9
commit dd2a1b3388
48 changed files with 775 additions and 140 deletions

View file

@ -145,7 +145,7 @@ data class AttachmentThumbnailInfo(
@Composable
internal fun AttachmentThumbnailPreview(@PreviewParameter(AttachmentThumbnailInfoProvider::class) data: AttachmentThumbnailInfo) = ElementPreview {
AttachmentThumbnail(
data,
info = data,
modifier = Modifier
.size(36.dp)
.clip(RoundedCornerShape(4.dp))

View file

@ -57,11 +57,11 @@ internal sealed interface InReplyToMetadata {
* Metadata can be either a thumbnail with a text OR just a text.
*/
@Composable
internal fun InReplyToDetails.Ready.metadata(): InReplyToMetadata? = when (eventContent) {
internal fun InReplyToDetails.Ready.metadata(hideImage: Boolean): InReplyToMetadata? = when (eventContent) {
is MessageContent -> when (val type = eventContent.type) {
is ImageMessageType -> InReplyToMetadata.Thumbnail(
AttachmentThumbnailInfo(
thumbnailSource = type.info?.thumbnailSource ?: type.source,
thumbnailSource = (type.info?.thumbnailSource ?: type.source).takeUnless { hideImage },
textContent = eventContent.body,
type = AttachmentThumbnailType.Image,
blurHash = type.info?.blurhash,
@ -69,7 +69,7 @@ internal fun InReplyToDetails.Ready.metadata(): InReplyToMetadata? = when (event
)
is VideoMessageType -> InReplyToMetadata.Thumbnail(
AttachmentThumbnailInfo(
thumbnailSource = type.info?.thumbnailSource,
thumbnailSource = type.info?.thumbnailSource?.takeUnless { hideImage },
textContent = eventContent.body,
type = AttachmentThumbnailType.Video,
blurHash = type.info?.blurhash,
@ -77,7 +77,7 @@ internal fun InReplyToDetails.Ready.metadata(): InReplyToMetadata? = when (event
)
is FileMessageType -> InReplyToMetadata.Thumbnail(
AttachmentThumbnailInfo(
thumbnailSource = type.info?.thumbnailSource,
thumbnailSource = type.info?.thumbnailSource?.takeUnless { hideImage },
textContent = eventContent.body,
type = AttachmentThumbnailType.File,
)
@ -104,7 +104,7 @@ internal fun InReplyToDetails.Ready.metadata(): InReplyToMetadata? = when (event
}
is StickerContent -> InReplyToMetadata.Thumbnail(
AttachmentThumbnailInfo(
thumbnailSource = eventContent.source,
thumbnailSource = eventContent.source.takeUnless { hideImage },
textContent = eventContent.body,
type = AttachmentThumbnailType.Image,
blurHash = eventContent.info.blurhash,

View file

@ -48,6 +48,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun InReplyToView(
inReplyTo: InReplyToDetails,
hideImage: Boolean,
modifier: Modifier = Modifier,
) {
when (inReplyTo) {
@ -55,7 +56,7 @@ fun InReplyToView(
ReplyToReadyContent(
senderId = inReplyTo.senderId,
senderProfile = inReplyTo.senderProfile,
metadata = inReplyTo.metadata(),
metadata = inReplyTo.metadata(hideImage),
modifier = modifier
)
}
@ -191,5 +192,8 @@ private fun ReplyToContentText(metadata: InReplyToMetadata?) {
@PreviewsDayNight
@Composable
internal fun InReplyToViewPreview(@PreviewParameter(provider = InReplyToDetailsProvider::class) inReplyTo: InReplyToDetails) = ElementPreview {
InReplyToView(inReplyTo)
InReplyToView(
inReplyTo = inReplyTo,
hideImage = false,
)
}

View file

@ -61,7 +61,7 @@ class InReplyToMetadataKtTest {
@Test
fun `any message content`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(eventContent = aMessageContent()).metadata()
anInReplyToDetailsReady(eventContent = aMessageContent()).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(InReplyToMetadata.Text("textContent"))
@ -82,7 +82,7 @@ class InReplyToMetadataKtTest {
info = anImageInfo(),
)
)
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
@ -99,6 +99,36 @@ class InReplyToMetadataKtTest {
}
}
@Test
fun `an image message content, no thumbnail`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = aMessageContent(
messageType = ImageMessageType(
body = "body",
formatted = null,
filename = null,
source = aMediaSource(),
info = anImageInfo(),
)
)
).metadata(hideImage = true)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
InReplyToMetadata.Thumbnail(
attachmentThumbnailInfo = AttachmentThumbnailInfo(
thumbnailSource = null,
textContent = "body",
type = AttachmentThumbnailType.Image,
blurHash = A_BLUR_HASH,
)
)
)
}
}
}
@Test
fun `a sticker message content`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
@ -108,7 +138,7 @@ class InReplyToMetadataKtTest {
info = anImageInfo(),
source = aMediaSource(url = "url")
)
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
@ -125,6 +155,32 @@ class InReplyToMetadataKtTest {
}
}
@Test
fun `a sticker message content, no thumbnail`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = StickerContent(
body = "body",
info = anImageInfo(),
source = aMediaSource(url = "url")
)
).metadata(hideImage = true)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
InReplyToMetadata.Thumbnail(
attachmentThumbnailInfo = AttachmentThumbnailInfo(
thumbnailSource = null,
textContent = "body",
type = AttachmentThumbnailType.Image,
blurHash = A_BLUR_HASH,
)
)
)
}
}
}
@Test
fun `a video message content`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
@ -138,7 +194,7 @@ class InReplyToMetadataKtTest {
info = aVideoInfo(),
)
)
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
@ -155,6 +211,36 @@ class InReplyToMetadataKtTest {
}
}
@Test
fun `a video message content, no thumbnail`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = aMessageContent(
messageType = VideoMessageType(
body = "body",
formatted = null,
filename = null,
source = aMediaSource(),
info = aVideoInfo(),
)
)
).metadata(hideImage = true)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
InReplyToMetadata.Thumbnail(
attachmentThumbnailInfo = AttachmentThumbnailInfo(
thumbnailSource = null,
textContent = "body",
type = AttachmentThumbnailType.Video,
blurHash = A_BLUR_HASH,
)
)
)
}
}
}
@Test
fun `a file message content`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
@ -171,7 +257,7 @@ class InReplyToMetadataKtTest {
),
)
)
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
@ -188,6 +274,39 @@ class InReplyToMetadataKtTest {
}
}
@Test
fun `a file message content, no thumbnail`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = aMessageContent(
messageType = FileMessageType(
body = "body",
source = aMediaSource(),
info = FileInfo(
mimetype = null,
size = null,
thumbnailInfo = null,
thumbnailSource = aMediaSource(),
),
)
)
).metadata(hideImage = true)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
InReplyToMetadata.Thumbnail(
attachmentThumbnailInfo = AttachmentThumbnailInfo(
thumbnailSource = null,
textContent = "body",
type = AttachmentThumbnailType.File,
blurHash = null,
)
)
)
}
}
}
@Test
fun `a audio message content`() = runTest {
moleculeFlow(RecompositionMode.Immediate) {
@ -203,7 +322,7 @@ class InReplyToMetadataKtTest {
),
)
)
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
@ -231,7 +350,7 @@ class InReplyToMetadataKtTest {
description = null,
)
)
).metadata()
).metadata(hideImage = false)
}
}.test {
awaitItem().let {
@ -262,7 +381,7 @@ class InReplyToMetadataKtTest {
details = null,
)
)
).metadata()
).metadata(hideImage = false)
}
}.test {
awaitItem().let {
@ -285,7 +404,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = aPollContent()
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(
@ -307,7 +426,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = RedactedContent
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(InReplyToMetadata.Redacted)
@ -320,7 +439,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = UnableToDecryptContent(UnableToDecryptContent.Data.Unknown)
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isEqualTo(InReplyToMetadata.UnableToDecrypt)
@ -333,7 +452,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = FailedToParseMessageLikeContent("", "")
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isNull()
@ -346,7 +465,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = FailedToParseStateContent("", "", "")
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isNull()
@ -359,7 +478,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = ProfileChangeContent("", "", "", "")
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isNull()
@ -372,7 +491,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = RoomMembershipContent(A_USER_ID, null, null)
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isNull()
@ -385,7 +504,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = StateContent("", OtherState.RoomJoinRules)
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isNull()
@ -398,7 +517,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = UnknownContent
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isNull()
@ -411,7 +530,7 @@ class InReplyToMetadataKtTest {
moleculeFlow(RecompositionMode.Immediate) {
anInReplyToDetailsReady(
eventContent = null
).metadata()
).metadata(hideImage = false)
}.test {
awaitItem().let {
assertThat(it).isNull()