diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/components/MediaPickerBottomSheet.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/components/MediaPickerBottomSheet.kt index 1e2a65f..a486577 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/components/MediaPickerBottomSheet.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/components/MediaPickerBottomSheet.kt @@ -264,35 +264,68 @@ fun MediaPickerBottomSheet( } // Функция snap к ближайшему состоянию с плавной анимацией - fun snapToNearestState() { + // Используем velocity для определения направления + fun snapToNearestState(velocity: Float = 0f) { animationScope.launch { val currentHeight = sheetHeightPx.value - val midPoint = (collapsedHeightPx + expandedHeightPx) / 2 + + // Пороги основаны на velocity (скорости свайпа) - не на позиции! + // velocity < 0 = свайп вверх, velocity > 0 = свайп вниз + val velocityThreshold = 300f // Маленький порог для лёгкого свайпа when { - // Слишком низко - закрываем - currentHeight < minHeightPx + 50 -> { + // Быстрый свайп вниз при минимальной высоте - закрываем + velocity > velocityThreshold && currentHeight < collapsedHeightPx -> { animatedClose() } - // Ближе к expanded - currentHeight > midPoint -> { + // Слишком низко - закрываем + currentHeight < minHeightPx + 30 -> { + animatedClose() + } + // Быстрый свайп вверх - разворачиваем + velocity < -velocityThreshold -> { isExpanded = true sheetHeightPx.animateTo( expandedHeightPx, animationSpec = spring( - dampingRatio = Spring.DampingRatioMediumBouncy, - stiffness = Spring.StiffnessMedium + dampingRatio = Spring.DampingRatioLowBouncy, + stiffness = Spring.StiffnessMediumLow + ) + ) + } + // Быстрый свайп вниз - сворачиваем (или закрываем если уже свёрнут) + velocity > velocityThreshold -> { + if (isExpanded) { + isExpanded = false + sheetHeightPx.animateTo( + collapsedHeightPx, + animationSpec = spring( + dampingRatio = Spring.DampingRatioLowBouncy, + stiffness = Spring.StiffnessMediumLow + ) + ) + } else { + animatedClose() + } + } + // Без velocity - snap к ближайшему + currentHeight > (collapsedHeightPx + expandedHeightPx) / 2 -> { + isExpanded = true + sheetHeightPx.animateTo( + expandedHeightPx, + animationSpec = spring( + dampingRatio = Spring.DampingRatioLowBouncy, + stiffness = Spring.StiffnessMediumLow ) ) } - // Ближе к collapsed else -> { isExpanded = false sheetHeightPx.animateTo( collapsedHeightPx, animationSpec = spring( - dampingRatio = Spring.DampingRatioMediumBouncy, - stiffness = Spring.StiffnessMedium + dampingRatio = Spring.DampingRatioLowBouncy, + stiffness = Spring.StiffnessMediumLow ) ) } @@ -364,6 +397,9 @@ fun MediaPickerBottomSheet( val currentHeightDp = with(density) { sheetHeightPx.value.toDp() } val slideOffset = (sheetHeightPx.value * animatedOffset).toInt() + // Отслеживаем velocity для плавного snap + var lastDragVelocity by remember { mutableFloatStateOf(0f) } + Column( modifier = Modifier .fillMaxWidth() @@ -385,12 +421,17 @@ fun MediaPickerBottomSheet( .pointerInput(Unit) { detectVerticalDragGestures( onDragEnd = { - // Snap к ближайшему состоянию - snapToNearestState() + // Snap с учётом velocity + snapToNearestState(lastDragVelocity) + lastDragVelocity = 0f }, onVerticalDrag = { change, dragAmount -> change.consume() - // 🔥 КЛЮЧЕВОЕ: Меняем высоту в реальном времени! + // Сохраняем velocity (dragAmount в пикселях) + // Усиливаем чувствительность в 1.5 раза + lastDragVelocity = dragAmount * 1.5f + + // 🔥 Меняем высоту в реальном времени val newHeight = (sheetHeightPx.value - dragAmount) .coerceIn(minHeightPx, expandedHeightPx) animationScope.launch {