Make it even smoother

Signed-off-by: denis0001-dev <denis0001.dev@ya.ru>
This commit is contained in:
2026-02-19 23:46:28 +03:00
Unverified
parent 900fc3429d
commit 6303657e10
3 changed files with 14 additions and 8 deletions
@@ -8,6 +8,7 @@ import androidx.compose.animation.fadeOut
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -59,7 +60,7 @@ import ru.fromchat.api.DmEnvelope
import ru.fromchat.api.DmFile import ru.fromchat.api.DmFile
private val IMAGE_SIZE = 160.dp private val IMAGE_SIZE = 160.dp
private val IMAGE_RADIUS = 8.dp private val IMAGE_RADIUS = 12.dp
internal fun isImageFilename(name: String): Boolean = internal fun isImageFilename(name: String): Boolean =
name.endsWith(".png", true) || name.endsWith(".jpg", true) || name.endsWith(".png", true) || name.endsWith(".jpg", true) ||
@@ -125,7 +126,7 @@ fun AttachmentPreview(
Box( Box(
modifier = modifier modifier = modifier
.then( .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 else Modifier
) )
.conditional( .conditional(
@@ -180,7 +180,7 @@ fun ImageFullscreenPreview(
val thumbWidth = thumbnailBounds.width val thumbWidth = thumbnailBounds.width
val s = thumbWidth / containerWidth val s = thumbWidth / containerWidth
val o = thumbCenter - fullCenter val o = thumbCenter - fullCenter
InitialTransform(s, o.x, o.y, 8f, 0f) InitialTransform(s, o.x, o.y, 12f, 0f)
} else { } else {
InitialTransform(1f, 0f, 0f, 0f, 1f) InitialTransform(1f, 0f, 0f, 0f, 1f)
} }
@@ -216,7 +216,7 @@ fun ImageFullscreenPreview(
scaleAnim.snapTo(startScale) scaleAnim.snapTo(startScale)
offsetXAnim.snapTo(startOffset.x) offsetXAnim.snapTo(startOffset.x)
offsetYAnim.snapTo(startOffset.y) offsetYAnim.snapTo(startOffset.y)
cornerRadiusAnim.snapTo(8f) cornerRadiusAnim.snapTo(12f)
backgroundAlpha.snapTo(0f) backgroundAlpha.snapTo(0f)
menusVisible = false menusVisible = false
@@ -262,7 +262,7 @@ fun ImageFullscreenPreview(
launch { scaleAnim.animateTo(targetScale, tween(250)) } launch { scaleAnim.animateTo(targetScale, tween(250)) }
launch { offsetXAnim.animateTo(targetOffset.x, tween(250)) } launch { offsetXAnim.animateTo(targetOffset.x, tween(250)) }
launch { offsetYAnim.animateTo(targetOffset.y, 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)) } launch { backgroundAlpha.animateTo(0f, tween(250)) }
} }
} else { } else {
@@ -351,8 +351,9 @@ fun ImageFullscreenPreview(
.graphicsLayer { .graphicsLayer {
scaleX = scaleAnim.value scaleX = scaleAnim.value
scaleY = scaleAnim.value scaleY = scaleAnim.value
shape = androidx.compose.foundation.shape.RoundedCornerShape(cornerRadiusAnim.value.dp) val scale = maxOf(scaleAnim.value, 0.01f)
clip = cornerRadiusAnim.value > 0f shape = androidx.compose.foundation.shape.RoundedCornerShape((cornerRadiusAnim.value / scale).dp)
clip = true
}, },
contentScale = ContentScale.FillWidth contentScale = ContentScale.FillWidth
) )
@@ -119,6 +119,10 @@ fun MessageItem(
) { ) {
// Message bubble // Message bubble
val isDark = isSystemInDarkTheme() 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( Box(
modifier = Modifier modifier = Modifier
// Max width: 70% of row, min width: content-driven // Max width: 70% of row, min width: content-driven
@@ -151,7 +155,7 @@ fun MessageItem(
background(MaterialTheme.colorScheme.surfaceContainerHighest) background(MaterialTheme.colorScheme.surfaceContainerHighest)
} }
) )
.padding(top = 6.dp) .padding(top = if (firstContentIsImage) 0.dp else 6.dp)
) { ) {
Column { Column {
// Username inside bubble (for received messages) // Username inside bubble (for received messages)