Почти плавный скрол чата

This commit is contained in:
Халимов Рустам
2026-04-28 00:16:52 +03:00
parent d9a20e40b0
commit 46c22300e9
15 changed files with 145 additions and 110 deletions
@@ -200,7 +200,9 @@ private fun EmojiContent(
LazyVerticalGrid(
columns = GridCells.Fixed(8),
state = scrollState,
modifier = Modifier.weight(1f).padding(horizontal = 4.dp)
modifier = Modifier.weight(1f).padding(horizontal = 4.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
emojiCategories.forEach { category ->
// Заголовок категории
@@ -214,7 +216,7 @@ private fun EmojiContent(
)
}
items(category.emojis) { emoji ->
items(category.emojis, key = { emoji -> emoji }) { emoji ->
Box(
modifier = Modifier
.aspectRatio(1f)
@@ -362,9 +364,11 @@ private fun GifContent(
LazyVerticalGrid(
columns = GridCells.Fixed(3),
modifier = Modifier.weight(1f).padding(4.dp),
contentPadding = PaddingValues(4.dp)
contentPadding = PaddingValues(4.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
items(displayGifs) { gif ->
items(displayGifs, key = { gif -> gif.id }, contentType = { "gif" }) { gif ->
val url = gif.files?.get("hd")?.get("gif")?.url
?: gif.files?.get("sd")?.get("gif")?.url
?: gif.file?.get("hd")?.get("gif")?.url
@@ -1,6 +1,5 @@
package chats.presentation.components
import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.draggable
@@ -30,10 +29,10 @@ fun SwipeableMessageItem(
) {
val density = LocalDensity.current
val scope = rememberCoroutineScope()
val offsetX = remember { Animatable(0f) }
val replyThreshold = with(density) { 60.dp.toPx() }
val maxDrag = with(density) { 90.dp.toPx() }
var offsetX by remember { mutableFloatStateOf(0f) }
var isTriggered by remember { mutableStateOf(false) }
Box(
@@ -42,27 +41,18 @@ fun SwipeableMessageItem(
.draggable(
orientation = Orientation.Horizontal,
state = rememberDraggableState { delta ->
scope.launch {
// We only allow swiping to the left (negative delta)
val newOffset = (offsetX.value + delta).coerceIn(-maxDrag, 0f)
offsetX.snapTo(newOffset)
if (newOffset <= -replyThreshold && !isTriggered) {
isTriggered = true
// Trigger haptic feedback if available?
} else if (newOffset > -replyThreshold) {
isTriggered = false
}
}
// We only allow swiping to the left (negative delta)
val newOffset = (offsetX + delta).coerceIn(-maxDrag, 0f)
offsetX = newOffset
isTriggered = newOffset <= -replyThreshold
},
onDragStopped = {
if (offsetX.value <= -replyThreshold) {
if (offsetX <= -replyThreshold) {
onReply()
}
scope.launch {
offsetX.animateTo(0f)
isTriggered = false
}
offsetX = 0f
isTriggered = false
}
)
) {
@@ -72,7 +62,7 @@ fun SwipeableMessageItem(
.align(Alignment.CenterEnd)
.padding(end = 16.dp)
.size(36.dp)
.alpha(((-offsetX.value) / replyThreshold).coerceIn(0f, 1f))
.alpha(((-offsetX) / replyThreshold).coerceIn(0f, 1f))
.clip(CircleShape)
.background(if (isTriggered) MaterialTheme.colorScheme.primary else Color.Gray.copy(alpha = 0.2f)),
contentAlignment = Alignment.Center
@@ -88,7 +78,7 @@ fun SwipeableMessageItem(
// Message Content
Box(
modifier = Modifier
.offset { IntOffset(offsetX.value.roundToInt(), 0) }
.offset { IntOffset(offsetX.roundToInt(), 0) }
.fillMaxWidth()
) {
content()