Skip to content
Open
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 @@ -3881,11 +3881,10 @@ public final class io/getstream/chat/android/compose/ui/theme/StreamRippleConfig
public final class io/getstream/chat/android/compose/ui/theme/StreamShapes {
public static final field $stable I
public static final field Companion Lio/getstream/chat/android/compose/ui/theme/StreamShapes$Companion;
public fun <init> (Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;)V
public fun <init> (Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;)V
public final fun component1 ()Landroidx/compose/ui/graphics/Shape;
public final fun component10 ()Landroidx/compose/ui/graphics/Shape;
public final fun component11 ()Landroidx/compose/ui/graphics/Shape;
public final fun component12 ()Landroidx/compose/ui/graphics/Shape;
public final fun component2 ()Landroidx/compose/ui/graphics/Shape;
public final fun component3 ()Landroidx/compose/ui/graphics/Shape;
public final fun component4 ()Landroidx/compose/ui/graphics/Shape;
Expand All @@ -3894,11 +3893,10 @@ public final class io/getstream/chat/android/compose/ui/theme/StreamShapes {
public final fun component7 ()Landroidx/compose/ui/graphics/Shape;
public final fun component8 ()Landroidx/compose/ui/graphics/Shape;
public final fun component9 ()Landroidx/compose/ui/graphics/Shape;
public final fun copy (Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;)Lio/getstream/chat/android/compose/ui/theme/StreamShapes;
public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/StreamShapes;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;ILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/StreamShapes;
public final fun copy (Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;)Lio/getstream/chat/android/compose/ui/theme/StreamShapes;
public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/StreamShapes;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/graphics/Shape;ILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/StreamShapes;
public fun equals (Ljava/lang/Object;)Z
public final fun getAttachment ()Landroidx/compose/ui/graphics/Shape;
public final fun getAttachmentSiteLabel ()Landroidx/compose/ui/graphics/Shape;
public final fun getAvatar ()Landroidx/compose/ui/graphics/Shape;
public final fun getBottomSheet ()Landroidx/compose/ui/graphics/Shape;
public final fun getHeader ()Landroidx/compose/ui/graphics/Shape;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public object StreamAttachmentFactories {
* The default max length of the link attachments description. We limit this, because for some links the description
* can be too long.
*/
private const val DEFAULT_LINK_DESCRIPTION_MAX_LINES = 5
private const val DEFAULT_LINK_DESCRIPTION_MAX_LINES = 2

/**
* Default attachment factories we provide, which can transform image, file and link attachments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import io.getstream.chat.android.compose.ui.theme.ChatTheme
import io.getstream.chat.android.compose.ui.theme.StreamDimens
import io.getstream.chat.android.compose.ui.util.AsyncImagePreviewHandler
import io.getstream.chat.android.compose.ui.util.StreamAsyncImage
import io.getstream.chat.android.compose.ui.util.applyIf
import io.getstream.chat.android.models.Attachment
import io.getstream.chat.android.models.AttachmentType
import io.getstream.chat.android.models.Message
Expand Down Expand Up @@ -215,7 +216,7 @@ public fun GiphyAttachmentContent(
Box(
modifier = modifier
.size(giphyDimensions)
.clip(ChatTheme.shapes.attachment)
.applyIf(message.text.isNotEmpty()) { clip(ChatTheme.shapes.attachment) }
.combinedClickable(
indication = null,
interactionSource = remember { MutableInteractionSource() },
Expand Down Expand Up @@ -332,6 +333,7 @@ internal fun GiphyAttachmentContent() {
GiphyAttachmentContent(
attachmentState = AttachmentState(
message = Message(
text = "Hello",
attachments = listOf(
Attachment(
titleLink = "https://giphy.com/gifs/funny-cat-3oEjI6SIIHBdRxXI40",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,31 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.net.toUri
import coil3.ColorImage
import coil3.annotation.ExperimentalCoilApi
Expand All @@ -63,6 +59,8 @@ import io.getstream.chat.android.compose.R
import io.getstream.chat.android.compose.state.messages.attachments.AttachmentState
import io.getstream.chat.android.compose.ui.components.ShimmerProgressIndicator
import io.getstream.chat.android.compose.ui.theme.ChatTheme
import io.getstream.chat.android.compose.ui.theme.MessageStyling
import io.getstream.chat.android.compose.ui.theme.StreamTokens
import io.getstream.chat.android.compose.ui.util.AsyncImagePreviewHandler
import io.getstream.chat.android.compose.ui.util.StreamAsyncImage
import io.getstream.chat.android.models.Attachment
Expand Down Expand Up @@ -132,20 +130,17 @@ public fun LinkAttachmentContent(

val context = LocalContext.current
val attachment = message.attachments.firstOrNull { it.hasLink() && !it.isGiphy() }
val textColor = MessageStyling.textColor(outgoing = isMine)

checkNotNull(attachment) {
"Missing link attachment."
}

val previewUrl = attachment.titleLink ?: attachment.ogUrl
val urlWithScheme = previewUrl?.addSchemeToUrlIfNeeded()

checkNotNull(previewUrl) {
"Missing preview URL."
}

val errorMessage = stringResource(R.string.stream_compose_message_list_error_cannot_open_link, previewUrl)

Column(
modifier = modifier
.clip(ChatTheme.shapes.attachment)
Expand All @@ -154,140 +149,116 @@ public fun LinkAttachmentContent(
indication = null,
interactionSource = remember { MutableInteractionSource() },
onClick = {
try {
if (urlWithScheme != null) {
onItemClick(
LinkAttachmentClickData(
context = context,
url = urlWithScheme,
attachment = attachment,
message = message,
),
)
} else {
Toast
.makeText(context, errorMessage, Toast.LENGTH_LONG)
.show()
}
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
Toast
.makeText(context, errorMessage, Toast.LENGTH_LONG)
.show()
}
onItemClick(
LinkAttachmentClickData(
context = context,
url = previewUrl.addSchemeToUrlIfNeeded(),
attachment = attachment,
message = message,
),
)
},
onLongClick = { onLongItemClick(message) },
),
) {
val imagePreviewUrl = attachment.imagePreviewUrl
if (imagePreviewUrl != null) {
LinkAttachmentImagePreview(attachment, isMine)
attachment.imagePreviewUrl?.let {
LinkAttachmentImagePreview(it)
}

val title = attachment.title
if (title != null) {
LinkAttachmentTitle(title)
Spacer(Modifier.height(12.dp))

attachment.title?.let {
LinkAttachmentTitle(it, textColor)
}

val description = attachment.text
if (description != null) {
LinkAttachmentDescription(description, linkDescriptionMaxLines)
attachment.text?.let {
LinkAttachmentDescription(it, linkDescriptionMaxLines, textColor)
}

AttachmentLink(previewUrl, textColor)
}
}

@Composable
private fun LinkAttachmentImagePreview(attachment: Attachment, isMine: Boolean) {
val data = attachment.imagePreviewUrl
var maxWidth by remember { mutableStateOf(0.dp) }

Box(
modifier = Modifier.onSizeChanged { size -> maxWidth = size.width.dp },
) {
val contentScale = ContentScale.FillWidth
StreamAsyncImage(
modifier = Modifier
.heightIn(max = 250.dp)
.clip(ChatTheme.shapes.attachment)
.testTag("Stream_LinkAttachmentPreview"),
data = data,
contentScale = contentScale,
) { state ->
val painter = state.painter

if (painter == null) {
ShimmerProgressIndicator(
modifier = Modifier.fillMaxSize(),
)
} else {
val intrinsicSize = painter.intrinsicSize
val aspectRatio = intrinsicSize.width / intrinsicSize.height

Image(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(aspectRatio),
painter = painter,
contentDescription = null,
contentScale = contentScale,
)
}
}

val authorName = attachment.authorName

if (authorName != null) {
Text(
text = authorName,
color = ChatTheme.colors.primaryAccent,
maxLines = 1,
style = ChatTheme.typography.bodyBold,
fontSize = 16.sp,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
.widthIn(max = maxWidth / 2)
.background(
color = getLinkBackgroundColor(isMine),
shape = ChatTheme.shapes.attachmentSiteLabel,
)
.padding(vertical = 6.dp, horizontal = 12.dp)
.align(Alignment.BottomStart),
private fun LinkAttachmentImagePreview(imageUrl: String) {
val contentScale = ContentScale.FillWidth
StreamAsyncImage(
modifier = Modifier
.heightIn(max = 144.dp)
.testTag("Stream_LinkAttachmentPreview"),
data = imageUrl,
contentScale = contentScale,
) { state ->
when (val painter = state.painter) {
null -> ShimmerProgressIndicator(Modifier.fillMaxSize())
else -> Image(
modifier = Modifier.fillMaxSize(),
painter = painter,
contentDescription = null,
contentScale = contentScale,
)
}
}
}

@Composable
private fun LinkAttachmentTitle(text: String) {
private fun LinkAttachmentTitle(text: String, color: Color) {
Text(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp)
.padding(horizontal = StreamTokens.spacingSm)
.testTag("Stream_LinkAttachmentTitle"),
text = text,
style = ChatTheme.typography.bodyBold,
color = ChatTheme.colors.textHighEmphasis,
style = ChatTheme.typography.captionEmphasis,
color = color,
)
}

@Composable
private fun LinkAttachmentDescription(description: String, linkDescriptionMaxLines: Int) {
private fun LinkAttachmentDescription(description: String, maxLines: Int, color: Color) {
Text(
modifier = Modifier
.padding(
start = 8.dp,
end = 8.dp,
bottom = 4.dp,
top = 2.dp,
start = StreamTokens.spacingSm,
end = StreamTokens.spacingSm,
top = StreamTokens.spacing2xs,
)
.testTag("Stream_LinkAttachmentDescription"),
text = description,
style = ChatTheme.typography.footnote,
color = ChatTheme.colors.textHighEmphasis,
maxLines = linkDescriptionMaxLines,
style = ChatTheme.typography.metadataDefault,
color = color,
maxLines = maxLines,
overflow = TextOverflow.Ellipsis,
)
}

@Composable
private fun AttachmentLink(link: String, color: Color) {
Row(
modifier = Modifier.padding(
start = StreamTokens.spacingSm,
end = StreamTokens.spacingSm,
top = StreamTokens.spacing2xs,
bottom = StreamTokens.spacingSm,
),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(R.drawable.stream_compose_ic_link),
contentDescription = null,
modifier = Modifier.size(StreamTokens.size12),
tint = color,
)
Text(
text = link,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(start = StreamTokens.spacing2xs),
style = ChatTheme.typography.metadataDefault,
color = color,
)
}
}

@Composable
private fun getLinkBackgroundColor(isMine: Boolean): Color {
return if (isMine) {
Expand All @@ -304,12 +275,15 @@ private fun getLinkBackgroundColor(isMine: Boolean): Color {
* @param url The url of the link attachment being clicked.
*/
internal fun onLinkAttachmentContentClick(context: Context, url: String) {
context.startActivity(
Intent(
Intent.ACTION_VIEW,
url.toUri(),
),
)
try {
context.startActivity(Intent(Intent.ACTION_VIEW, url.toUri()))
} catch (_: ActivityNotFoundException) {
val errorMessage =
context.getString(R.string.stream_compose_message_list_error_cannot_open_link, url)
Toast
.makeText(context, errorMessage, Toast.LENGTH_LONG)
.show()
}
}

@Preview(showBackground = true)
Expand Down Expand Up @@ -338,7 +312,7 @@ internal fun LinkAttachmentContent() {
state = AttachmentState(
message = Message(attachments = listOf(attachment)),
),
linkDescriptionMaxLines = 5,
linkDescriptionMaxLines = 2,
)
}
}
Expand Down
Loading
Loading