Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1456,7 +1456,7 @@ public final class io/getstream/chat/android/compose/ui/components/messages/Mess
}

public final class io/getstream/chat/android/compose/ui/components/messages/MessageContentKt {
public static final fun MessageContent (Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;III)V
public static final fun MessageContent (Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lio/getstream/chat/android/compose/state/messages/MessageAlignment;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;III)V
}

public final class io/getstream/chat/android/compose/ui/components/messages/MessageFooterKt {
Expand Down Expand Up @@ -5370,20 +5370,22 @@ public final class io/getstream/chat/android/compose/ui/theme/MessageReactionsPi

public final class io/getstream/chat/android/compose/ui/theme/MessageRegularContentParams {
public static final field $stable I
public fun <init> (Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)V
public synthetic fun <init> (Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/compose/state/messages/MessageAlignment;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)V
public synthetic fun <init> (Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/compose/state/messages/MessageAlignment;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lio/getstream/chat/android/models/Message;
public final fun component2 ()Lio/getstream/chat/android/models/User;
public final fun component3 ()Lkotlin/jvm/functions/Function1;
public final fun component3 ()Lio/getstream/chat/android/compose/state/messages/MessageAlignment;
public final fun component4 ()Lkotlin/jvm/functions/Function1;
public final fun component5 ()Lkotlin/jvm/functions/Function1;
public final fun component6 ()Lkotlin/jvm/functions/Function1;
public final fun component7 ()Lkotlin/jvm/functions/Function2;
public final fun copy (Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lio/getstream/chat/android/compose/ui/theme/MessageRegularContentParams;
public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/MessageRegularContentParams;Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/MessageRegularContentParams;
public final fun component7 ()Lkotlin/jvm/functions/Function1;
public final fun component8 ()Lkotlin/jvm/functions/Function2;
public final fun copy (Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/compose/state/messages/MessageAlignment;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Lio/getstream/chat/android/compose/ui/theme/MessageRegularContentParams;
public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/MessageRegularContentParams;Lio/getstream/chat/android/models/Message;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/compose/state/messages/MessageAlignment;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/MessageRegularContentParams;
public fun equals (Ljava/lang/Object;)Z
public final fun getCurrentUser ()Lio/getstream/chat/android/models/User;
public final fun getMessage ()Lio/getstream/chat/android/models/Message;
public final fun getMessageAlignment ()Lio/getstream/chat/android/compose/state/messages/MessageAlignment;
public final fun getOnLinkClick ()Lkotlin/jvm/functions/Function2;
public final fun getOnLongItemClick ()Lkotlin/jvm/functions/Function1;
public final fun getOnMediaGalleryPreviewResult ()Lkotlin/jvm/functions/Function1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import coil3.ColorImage
import coil3.annotation.ExperimentalCoilApi
Expand Down Expand Up @@ -217,7 +218,6 @@ internal fun SingleMediaAttachment(
onContentItemClick: (MediaAttachmentClickData) -> Unit,
overlayContent: @Composable (attachmentType: String?) -> Unit,
) {
val isVideo = attachment.isVideo()
// Depending on the CDN, images might not contain their original dimensions
val ratio: Float by remember(key1 = attachment.originalWidth, key2 = attachment.originalHeight) {
derivedStateOf {
Expand All @@ -237,10 +237,7 @@ internal fun SingleMediaAttachment(
attachment = attachment,
modifier = modifier
.applyIf(!shouldBeFullSize) { padding(MessageStyling.messageSectionPadding) }
.size(
width = 250.dp,
height = singleMediaAttachmentHeight(isVideo, ratio),
),
.size(singleMediaAttachmentSize(ratio)),
shape = if (shouldBeFullSize) null else RoundedCornerShape(StreamTokens.radiusLg),
message = message,
onMediaGalleryPreviewResult = onMediaGalleryPreviewResult,
Expand Down Expand Up @@ -639,20 +636,35 @@ public data class MediaAttachmentClickData internal constructor(
)

/**
* Calculates the actual single-media attachment height, based on the configurable width, maxHeight and the aspectRatio.
* Calculates the single-media attachment size using orientation-based bounding boxes.
*
* - Landscape (ratio > 1): max 256×192 dp, fills width first.
* - Portrait (ratio < 1): max 192×256 dp, fills height first.
* - Square (ratio ≈ 1): 256×256 dp.
*
* @param isVideo true if "video", false if "image".
* @param aspectRatio the desired aspect ratio.
* Media maintains its aspect ratio and scales to fit the bounding box.
*
* @param aspectRatio the width-to-height ratio of the media.
*/
@Composable
private fun singleMediaAttachmentHeight(isVideo: Boolean, aspectRatio: Float): Dp {
val maxHeight = if (isVideo) {
400.dp
} else {
600.dp
private fun singleMediaAttachmentSize(aspectRatio: Float): DpSize = when {
aspectRatio > 1f -> {
// Landscape: bounding box 256×192
val width = 256.dp
val height = (width / aspectRatio).coerceAtMost(192.dp)
DpSize(width, height)
}

aspectRatio < 1f -> {
// Portrait: bounding box 192×256
val height = 256.dp
val width = (height * aspectRatio).coerceAtMost(192.dp)
DpSize(width, height)
}

else -> {
// Square
DpSize(256.dp, 256.dp)
}
val heightAccordingAspectRatio = 250.dp / aspectRatio
return minOf(heightAccordingAspectRatio, maxHeight)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import io.getstream.chat.android.client.utils.message.isDeleted
import io.getstream.chat.android.client.utils.message.isGiphyEphemeral
import io.getstream.chat.android.compose.R
import io.getstream.chat.android.compose.state.mediagallerypreview.MediaGalleryPreviewResult
import io.getstream.chat.android.compose.state.messages.MessageAlignment
import io.getstream.chat.android.compose.state.messages.attachments.AttachmentState
import io.getstream.chat.android.compose.ui.theme.AudioRecordAttachmentContentParams
import io.getstream.chat.android.compose.ui.theme.ChatTheme
Expand Down Expand Up @@ -91,6 +92,7 @@ public fun MessageContent(
onGiphyActionClick: (GiphyAction) -> Unit = {},
onQuotedMessageClick: (Message) -> Unit = {},
onUserMentionClick: (User) -> Unit = {},
messageAlignment: MessageAlignment = MessageAlignment.Start,
onLinkClick: ((Message, String) -> Unit)? = null,
onMediaGalleryPreviewResult: (MediaGalleryPreviewResult?) -> Unit = {},
giphyEphemeralContent: @Composable () -> Unit = {
Expand All @@ -116,6 +118,7 @@ public fun MessageContent(
params = MessageRegularContentParams(
message = message,
currentUser = currentUser,
messageAlignment = messageAlignment,
onLongItemClick = onLongItemClick,
onMediaGalleryPreviewResult = onMediaGalleryPreviewResult,
onQuotedMessageClick = onQuotedMessageClick,
Expand Down Expand Up @@ -178,6 +181,7 @@ internal fun DefaultMessageDeletedContent(
internal fun DefaultMessageContent(
message: Message,
currentUser: User?,
messageAlignment: MessageAlignment = MessageAlignment.Start,
onLongItemClick: (Message) -> Unit,
onMediaGalleryPreviewResult: (MediaGalleryPreviewResult?) -> Unit = {},
onQuotedMessageClick: (Message) -> Unit,
Expand All @@ -186,7 +190,7 @@ internal fun DefaultMessageContent(
) {
val componentFactory = ChatTheme.componentFactory

Column {
Column(horizontalAlignment = messageAlignment.contentAlignment) {
val quotedMessage = message.replyTo
if (quotedMessage != null) {
componentFactory.MessageQuotedContent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,7 @@ public fun RegularMessageContent(
MessageContent(
message = message,
currentUser = messageItem.currentUser,
messageAlignment = messageAlignment,
onLongItemClick = onLongItemClick,
onGiphyActionClick = onGiphyActionClick,
onMediaGalleryPreviewResult = onMediaGalleryPreviewResult,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,7 @@ public interface ChatComponentFactory {
DefaultMessageContent(
message = params.message,
currentUser = params.currentUser,
messageAlignment = params.messageAlignment,
onLongItemClick = params.onLongItemClick,
onMediaGalleryPreviewResult = params.onMediaGalleryPreviewResult,
onQuotedMessageClick = params.onQuotedMessageClick,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import androidx.compose.ui.unit.dp
import io.getstream.chat.android.compose.state.channels.list.ItemState
import io.getstream.chat.android.compose.state.mediagallerypreview.MediaGalleryPreviewResult
import io.getstream.chat.android.compose.state.messageoptions.MessageOptionItemState
import io.getstream.chat.android.compose.state.messages.MessageAlignment
import io.getstream.chat.android.compose.state.messages.MessageReactionItemState
import io.getstream.chat.android.compose.state.messages.attachments.AttachmentPickerItemState
import io.getstream.chat.android.compose.state.messages.attachments.AttachmentPickerMode
Expand Down Expand Up @@ -787,6 +788,7 @@ public data class MessageDeletedContentParams(
*
* @param message The message to display.
* @param currentUser The currently logged in user.
* @param messageAlignment The horizontal alignment of the message in the message list.
* @param onLongItemClick Action invoked when a message is long-clicked.
* @param onMediaGalleryPreviewResult Action invoked with the media gallery preview result.
* @param onQuotedMessageClick Action invoked when a quoted message is clicked.
Expand All @@ -796,6 +798,7 @@ public data class MessageDeletedContentParams(
public data class MessageRegularContentParams(
val message: Message,
val currentUser: User?,
val messageAlignment: MessageAlignment,
val onLongItemClick: (Message) -> Unit,
val onMediaGalleryPreviewResult: (MediaGalleryPreviewResult?) -> Unit,
val onQuotedMessageClick: (Message) -> Unit,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@
package io.getstream.chat.android.ui.common.helper.internal

import android.content.Context
import android.graphics.BitmapFactory
import android.media.MediaMetadataRetriever
import android.net.Uri
import androidx.annotation.WorkerThread
import io.getstream.chat.android.client.utils.attachment.isImage
import io.getstream.chat.android.client.utils.attachment.isVideo
import io.getstream.chat.android.core.internal.InternalStreamChatApi
import io.getstream.chat.android.models.Attachment
import io.getstream.chat.android.ui.common.helper.internal.AttachmentStorageHelper.Companion.EXTRA_SOURCE_URI
import io.getstream.chat.android.ui.common.state.messages.composer.AttachmentMetaData
import io.getstream.log.taggedLogger
import java.io.File

/**
* Handles querying device storage for attachment metadata and converting between
Expand Down Expand Up @@ -111,9 +116,17 @@ public class AttachmentStorageHelper(
logger.w { "[resolveAttachmentFiles] Failed to resolve file for URI: $sourceUri" }
return@mapNotNull null
}

val (width, height) = if (attachment.originalWidth == null && attachment.originalHeight == null) {
resolveLocalDimensions(file, attachment)
} else {
attachment.originalWidth to attachment.originalHeight
}
attachment.copy(
upload = file,
extraData = attachment.extraData - EXTRA_SOURCE_URI,
originalWidth = width,
originalHeight = height,
)
}

Expand All @@ -127,6 +140,37 @@ public class AttachmentStorageHelper(
public fun resolveMetadata(uris: List<Uri>): List<AttachmentMetaData> =
storageHelper.getAttachmentsFromUriList(context, uris).let(attachmentFilter::filterAttachments)

@Suppress("MagicNumber")
private fun resolveLocalDimensions(file: File, attachment: Attachment): Pair<Int?, Int?> = when {
attachment.isImage() -> {
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
BitmapFactory.decodeFile(file.absolutePath, options)
val w = options.outWidth.takeIf { it > 0 }
val h = options.outHeight.takeIf { it > 0 }
w to h
}

attachment.isVideo() -> {
val retriever = MediaMetadataRetriever()
try {
retriever.setDataSource(file.absolutePath)
val w = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)
?.toIntOrNull()?.takeIf { it > 0 }
val h = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)
?.toIntOrNull()?.takeIf { it > 0 }
val rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)
?.toIntOrNull() ?: 0
if (rotation == 90 || rotation == 270) h to w else w to h
} catch (_: Exception) {
null to null
} finally {
retriever.release()
}
}

else -> null to null
}

public companion object {
/**
* Key in [Attachment.extraData] holding the original content URI string
Expand Down
Loading