# Image and Video Previews

## Introduction

The Compose UI Components chat SDK supports various types of attachments by using [attachment factories](/chat/docs/sdk/android/v6/compose/general-customization/attachment-factory/). The one used to display image and video attachments is called `MediaAttachmentFactory` and offers a degree of customization.

## Customization

### Message List

Let's take a look at the `MediaAttachmentFactory` class:

```kotlin
public class MediaAttachmentFactory(
    maximumNumberOfPreviewedItems: Int = 4,
    skipEnrichUrl: Boolean = false,
    onContentItemClick: (MediaAttachmentClickData) -> Unit = { /* default gallery behavior */ },
    canHandle: (attachments: List<Attachment>) -> Boolean = { /* handles image and video attachments */ },
    itemOverlayContent: @Composable (attachmentType: String?) -> Unit = { attachmentType ->
        if (attachmentType == AttachmentType.VIDEO) {
            DefaultItemOverlayContent()
        }
    },
    previewItemOverlayContent: @Composable (attachmentType: String?) -> Unit = { attachmentType ->
        if (attachmentType == AttachmentType.VIDEO) {
            DefaultPreviewItemOverlayContent()
        }
    },
) : AttachmentFactory(...)
```

- `maximumNumberOfPreviewedItems`: Controls the maximum number of tiles that can be displayed when previewing attachments inside the message list. If there are more attachments inside the message than can be previewed, the remaining attachment count is displayed.
- `skipEnrichUrl`: Boolean flag to skip URL enrichment during message updates. Defaults to `false`.
- `onContentItemClick`: Lambda handling item click events. By default, this opens the attachment gallery.
- `canHandle`: Predicate determining whether this factory can handle a given list of attachments. By default, it handles image and video attachments.
- `itemOverlayContent`: Overlays a UI item over the attachment preview inside the message list. By default this is used to display a play button icon over video attachments, signaling their type to the user.
- `previewItemOverlayContent`: Serves the same function as `itemOverlayContent`, but used inside `MessageComposer` when selecting attachments instead.

The stock experience we provide out of the box looks like this:

| Default Image and Video Attachment Previews                                                                                            |
| -------------------------------------------------------------------------------------------------------------------------------------- |
| ![Default Image and Video Attachment Previews](@chat-sdk/android/v6/_assets/compose_customizing_image_and_video_attachments_stock.png) |

We'll start changing it by replacing the stock play button in favor of a flatter, semi-transparent design.

Let's create the new button:

```kotlin
@Composable
private fun CustomPlayButton(modifier: Modifier) {
    Box(
        modifier = modifier,
        contentAlignment = Alignment.Center
    ) {
        Icon(
            modifier = Modifier
                .padding(2.dp)
                .fillMaxSize(0.8f),
            painter = painterResource(id = R.drawable.stream_compose_ic_play),
            tint = Color.White,
            contentDescription = null
        )
    }
}
```

Now that we have created our custom button, we can use the slots provided by `MediaAttachmentContent` to override the default play button inside both the message list and the message composer.
We'll also use the opportunity to increase the maximum number of tiles that the factory can display.

```kotlin
val customMediaAttachmentFactory = MediaAttachmentFactory(
    // Increase the maximum number of previewed items to 5
    maximumNumberOfPreviewedItems = 5,
    // Render a custom item above attachments inside the message list
    itemOverlayContent = { attachmentType ->
        // Apply it only to video attachments
        if (attachmentType == AttachmentType.VIDEO) {
            CustomPlayButton(
                modifier = Modifier
                    .widthIn(10.dp)
                    .padding(2.dp)
                    .background(
                        color = Color(red = 255, blue = 255, green = 255, alpha = 220),
                        shape = RoundedCornerShape(8.dp)
                    )
                    .fillMaxWidth(0.3f)
                    .aspectRatio(1.20f),
            )
        }
    },
    // Render a custom item above attachments inside the message composer
    previewItemOverlayContent = { attachmentType ->
        // Apply it only to video attachments
        if (attachmentType == AttachmentType.VIDEO) {
            CustomPlayButton(
                modifier = Modifier
                    .padding(2.dp)
                    .background(
                        color = Color(red = 255, blue = 255, green = 255, alpha = 220),
                        shape = RoundedCornerShape(8.dp)
                    )
                    .fillMaxWidth(0.35f)
                    .aspectRatio(1.20f),
            )
        }
    })
```

Since we only want to modify `MediaAttachmentFactory` and keep the rest of the default factories, we'll copy them in the same order they are created in [StreamAttachmentFactories.defaultFactories()](https://github.com/GetStream/stream-chat-android/blob/v6/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/StreamAttachmentFactories.kt#L65).

```kotlin
val attachmentFactories = listOf(
    UploadAttachmentFactory(),
    LinkAttachmentFactory(linkDescriptionMaxLines = 5),
    GiphyAttachmentFactory(),
    customMediaAttachmentFactory,
    FileAttachmentFactory(),
    UnsupportedAttachmentFactory()
)
```

Order of precedence matters when creating a list of attachment factories, the first one whose `canHandle()` returns true will render the given attachment.

Finally, let's replace the default attachment factories:

```kotlin
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
    super.onCreate(savedInstanceState, persistentState)

    setContent {
        // Replace the default attachment factories
        ChatTheme(attachmentFactories = attachmentFactories) {
            MessagesScreen(
                viewModelFactory = messageListViewModelFactory,
                onBackPressed = { finish() }
            )
        }
    }
}
```

And the resulting experience looks like this:

| Custom Image and Video Attachment Previews                                                                                             |
| -------------------------------------------------------------------------------------------------------------------------------------- |
| ![Custom Image and Video Attachment Previews](@chat-sdk/android/v6/_assets/compose_customizing_image_and_video_attachments_custom.png) |

### Attachment Gallery

The attachment gallery is used for previewing image and video attachments. By default, this is a feature-complete `Activity`, which provides multiple actions to the user, such as zooming in and out, swiping between attachments, downloading or sharing them, or deleting them from the message.

By default, the gallery looks like:

| Default Image and Video Attachment Gallery (Light Mode)                                                                                                       | Default Image and Video Attachment Gallery with Overview (Light Mode)                                                                                                                | Default Image and Video Attachment Gallery with Options (Light Mode)                                                                                                               |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ![Default Image and Video Attachment Gallery Light Mode](@chat-sdk/android/v6/_assets/compose_customizing_image_and_video_attachments_attachment_gallery.png) | ![Default Image and Video Attachment Gallery with Overview Light Mode](@chat-sdk/android/v6/_assets/compose_customizing_image_and_video_attachments_attachment_gallery_overview.png) | ![Default Image and Video Attachment Gallery with Options Light Mode](@chat-sdk/android/v6/_assets/compose_customizing_image_and_video_attachments_attachment_gallery_options.png) |

| Default Image and Video Attachment Gallery (Dark Mode)                                                                                                            | Default Image and Video Attachment Gallery with Overview (Dark Mode)                                                                                                                     | Default Image and Video Attachment Gallery with Options (Dark Mode)                                                                                                                    |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ![Default Image and Video Attachment Gallery Dark Mode](@chat-sdk/android/v6/_assets/compose_customizing_image_and_video_attachments_attachment_gallery_dark.png) | ![Default Image and Video Attachment Gallery with Overview Dark Mode](@chat-sdk/android/v6/_assets/compose_customizing_image_and_video_attachments_attachment_gallery_overview_dark.png) | ![Default Image and Video Attachment Gallery with Options Dark Mode](@chat-sdk/android/v6/_assets/compose_customizing_image_and_video_attachments_attachment_gallery_options_dark.png) |

You can easily control which of the attachment actions are available to the user via the `MediaGalleryConfig` configuration class. This class is passed to the `ChatTheme` wrapping your `MessagesScreen`/`MessageList` and it is applied to the media gallery.

The `MediaGalleryConfig` class has the following properties:

- `isCloseVisible`: Controls whether the close button is visible or not.
- `isOptionsVisible`: Controls whether the options button is visible or not.
- `isShareVisible`: Controls whether the share button is visible or not.
- `isGalleryVisible`: Controls whether the gallery button is visible or not.
- `optionsConfig`: Controls the visibility of the options inside the options menu. This is a `MediaGalleryOptionsConfig` class that has the following properties:
  - `isShowInChatVisible`: Controls whether the "Show in chat" option is
    visible or not.
  - `isReplyVisible`: Controls whether the "Reply" option is visible or not.
  - `isSaveMediaVisible`: Controls whether the "Save media" option is visible
    or not.
  - `isDeleteVisible`: Controls whether the "Delete" option is visible or not.

The `MediaGalleryConfig` is prepared as follows:

```kotlin
ChatTheme(
    mediaGalleryConfig = MediaGalleryConfig(
        isCloseVisible = true,
        isOptionsVisible = true,
        isShareVisible = false,
        isGalleryVisible = false,
        optionsConfig = MediaGalleryOptionsConfig(
            isShowInChatVisible = true,
            isReplyVisible = true,
            isSaveMediaVisible = false,
            isDeleteVisible = false,
        )
    )
) {
    MessagesScreen(/* ... */)
}
```

This will hide both footer actions (share and gallery), and will hide the "Save media" and "Delete" options from the options menu:

| Custom Image and Video Attachment Gallery                                                                                                                |
| -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ![Custom Image and Video Attachment Gallery](@chat-sdk/android/v6/_assets/compose_customizing_image_and_video_attachments_attachment_gallery_custom.png) |

If you want to fully replace the default gallery with your own, you can do so by intercepting the click handler for media attachment messages, and presenting your own gallery screen. To do that, you need to override the `onMediaContentItemClick` method from the `StreamAttachmentFactories.defaultFactories` builder:

```kotlin
val attachmentFactories = StreamAttachmentFactories.defaultFactories(
    onMediaContentItemClick = { launcher, message, attachmentPosition, thumbnailsEnabled, downloadUriGenerator, downloadRequestInterceptor, imageResizing, skipEnrichUrl ->
        // Present your own gallery screen
    }
)
ChatTheme(
    attachmentFactories = attachmentFactories,
) {
    MessagesScreen(/* ... */)
}
```

If you would like to do more fine-grained customization of the gallery, we also expose the screen-level composable that is used to display the gallery.

## Conclusion

If you need to put small personal touches to how your app displays image and video attachments while spending very little time on development, the approach we've discussed is optimal. If you need to do large changes, remember you can always create your own attachment factory and replace the default one with it.

<admonition type="note">

You can read more about custom attachment factories [here](/chat/docs/sdk/android/v6/compose/general-customization/attachment-factory/).

</admonition>


---

This page was last updated at 2026-04-17T17:33:31.653Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/android/v6/compose/guides/customizing-image-and-video-previews/](https://getstream.io/chat/docs/sdk/android/v6/compose/guides/customizing-image-and-video-previews/).