From 6303657e10330c8c22ccd94e58727bc975cdeebe Mon Sep 17 00:00:00 2001 From: denis0001-dev Date: Thu, 19 Feb 2026 23:46:28 +0300 Subject: [PATCH] Make it even smoother Signed-off-by: denis0001-dev --- .../kotlin/ru/fromchat/ui/chat/AttachmentPreview.kt | 5 +++-- .../ru/fromchat/ui/chat/ImageFullscreenPreview.kt | 11 ++++++----- .../kotlin/ru/fromchat/ui/chat/MessageItem.kt | 6 +++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/AttachmentPreview.kt b/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/AttachmentPreview.kt index 4ea499c..4d30a41 100644 --- a/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/AttachmentPreview.kt +++ b/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/AttachmentPreview.kt @@ -8,6 +8,7 @@ import androidx.compose.animation.fadeOut import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -59,7 +60,7 @@ import ru.fromchat.api.DmEnvelope import ru.fromchat.api.DmFile private val IMAGE_SIZE = 160.dp -private val IMAGE_RADIUS = 8.dp +private val IMAGE_RADIUS = 12.dp internal fun isImageFilename(name: String): Boolean = name.endsWith(".png", true) || name.endsWith(".jpg", true) || @@ -125,7 +126,7 @@ fun AttachmentPreview( Box( modifier = modifier .then( - if (onImageClick != null && isFullyLoaded && !isExpanded) Modifier.clickable(onClick = onImageClick) + if (onImageClick != null && isFullyLoaded && !isExpanded) Modifier.clickable(indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = onImageClick) else Modifier ) .conditional( diff --git a/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/ImageFullscreenPreview.kt b/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/ImageFullscreenPreview.kt index 4da27b8..a89f546 100644 --- a/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/ImageFullscreenPreview.kt +++ b/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/ImageFullscreenPreview.kt @@ -180,7 +180,7 @@ fun ImageFullscreenPreview( val thumbWidth = thumbnailBounds.width val s = thumbWidth / containerWidth val o = thumbCenter - fullCenter - InitialTransform(s, o.x, o.y, 8f, 0f) + InitialTransform(s, o.x, o.y, 12f, 0f) } else { InitialTransform(1f, 0f, 0f, 0f, 1f) } @@ -216,7 +216,7 @@ fun ImageFullscreenPreview( scaleAnim.snapTo(startScale) offsetXAnim.snapTo(startOffset.x) offsetYAnim.snapTo(startOffset.y) - cornerRadiusAnim.snapTo(8f) + cornerRadiusAnim.snapTo(12f) backgroundAlpha.snapTo(0f) menusVisible = false @@ -262,7 +262,7 @@ fun ImageFullscreenPreview( launch { scaleAnim.animateTo(targetScale, tween(250)) } launch { offsetXAnim.animateTo(targetOffset.x, tween(250)) } launch { offsetYAnim.animateTo(targetOffset.y, tween(250)) } - launch { cornerRadiusAnim.animateTo(8f, tween(250)) } + launch { cornerRadiusAnim.animateTo(12f, tween(250)) } launch { backgroundAlpha.animateTo(0f, tween(250)) } } } else { @@ -351,8 +351,9 @@ fun ImageFullscreenPreview( .graphicsLayer { scaleX = scaleAnim.value scaleY = scaleAnim.value - shape = androidx.compose.foundation.shape.RoundedCornerShape(cornerRadiusAnim.value.dp) - clip = cornerRadiusAnim.value > 0f + val scale = maxOf(scaleAnim.value, 0.01f) + shape = androidx.compose.foundation.shape.RoundedCornerShape((cornerRadiusAnim.value / scale).dp) + clip = true }, contentScale = ContentScale.FillWidth ) diff --git a/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/MessageItem.kt b/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/MessageItem.kt index 7ec5136..82e0ef4 100644 --- a/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/MessageItem.kt +++ b/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/MessageItem.kt @@ -119,6 +119,10 @@ fun MessageItem( ) { // Message bubble val isDark = isSystemInDarkTheme() + val firstContentIsImage = (!showUsername || isAuthor) && + message.reply_to == null && + (message.pendingFileUri?.let { isImageFilename(it.substringAfterLast('/').substringBefore('?')) } == true || + message.files?.firstOrNull()?.let { isImageFilename(it.name) } == true) Box( modifier = Modifier // Max width: 70% of row, min width: content-driven @@ -151,7 +155,7 @@ fun MessageItem( background(MaterialTheme.colorScheme.surfaceContainerHighest) } ) - .padding(top = 6.dp) + .padding(top = if (firstContentIsImage) 0.dp else 6.dp) ) { Column { // Username inside bubble (for received messages)