feat: Remove animation for emoji picker when keyboard opens and optimize height handling

This commit is contained in:
k1ngsterr1
2026-01-14 02:10:53 +05:00
parent 37b7d6e613
commit 9078d86970

View File

@@ -2298,73 +2298,49 @@ private fun MessageInputBar(
} // Закрытие внешней Column с border
} // End of else (not blocked)
// <20> APPLE EMOJI PICKER - ОПТИМИЗИРОВАННАЯ АНИМАЦИЯ
// Используем slide up + alpha вместо height анимации (нет relayout = супер плавно)
// 🔥 APPLE EMOJI PICKER - БЕЗ анимации когда клавиатура открывается
if (!isBlocked) {
// Панель ВСЕГДА в DOM (pre-render), просто скрыта через offset/alpha
val shouldShow = showEmojiPicker && !isKeyboardVisible
// Высота панели: 0 если клавиатура видна или эмодзи закрыты, иначе emojiPanelHeight
val targetHeight = if (isKeyboardVisible || !showEmojiPicker) 0.dp else emojiPanelHeight
// 🚀 Animatable для максимального контроля (быстрее чем animateDpAsState)
val slideProgress = remember { Animatable(0f) }
LaunchedEffect(shouldShow) {
if (shouldShow) {
// Открытие: быстрая spring анимация (critically damped = без пружинистости)
slideProgress.animateTo(
targetValue = 1f,
animationSpec = spring(
dampingRatio = 1f, // Critically damped - без bounce
stiffness = 800f // Высокая жёсткость = быстро
)
)
// Анимируем только когда клавиатура закрыта
val animatedHeight by animateDpAsState(
targetValue = targetHeight,
animationSpec = if (isKeyboardVisible) {
// Мгновенно когда клавиатура открывается
snap()
} else {
// Закрытие: мгновенно если клавиатура открылась, иначе быстрая анимация
if (isKeyboardVisible) {
slideProgress.snapTo(0f)
} else {
slideProgress.animateTo(
targetValue = 0f,
animationSpec = tween(120, easing = FastOutSlowInEasing)
// Быстрая анимация (200ms)
tween(durationMillis = 200, easing = FastOutSlowInEasing)
},
label = "EmojiPanelHeight"
)
// 🔥 Показываем Box только когда есть высота (НЕ занимает место когда скрыт!)
if (animatedHeight > 0.dp) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(animatedHeight)
.padding(bottom = 16.dp)
) {
if (showEmojiPicker) {
AppleEmojiPickerPanel(
isDarkTheme = isDarkTheme,
onEmojiSelected = { emoji ->
onValueChange(value + emoji)
},
onClose = {
onToggleEmojiPicker(false)
},
modifier = Modifier
.fillMaxWidth()
.height(emojiPanelHeight - 16.dp)
)
}
}
}
val panelHeightPx = with(LocalDensity.current) { (emojiPanelHeight - 16.dp).toPx() }
Box(
modifier = Modifier
.fillMaxWidth()
.height(emojiPanelHeight)
.padding(bottom = 16.dp)
.graphicsLayer {
// 🚀 Slide up анимация через translationY (НЕ вызывает relayout!)
translationY = panelHeightPx * (1f - slideProgress.value)
alpha = slideProgress.value
// Hardware layer для плавности
if (slideProgress.value > 0f && slideProgress.value < 1f) {
shadowElevation = 0f
}
}
.clipToBounds() // Обрезаем контент при slide
) {
// 🚀 Панель ВСЕГДА рендерится (pre-render для instant open)
// Но скрыта через alpha = 0 когда не нужна
if (slideProgress.value > 0f || shouldShow) {
AppleEmojiPickerPanel(
isDarkTheme = isDarkTheme,
onEmojiSelected = { emoji ->
onValueChange(value + emoji)
},
onClose = {
onToggleEmojiPicker(false)
},
modifier = Modifier
.fillMaxWidth()
.height(emojiPanelHeight - 16.dp)
)
}
}
} // End of if (!isBlocked) for emoji picker
}
}