feat: Enhance emoji picker animation with smooth slide-up effect and visibility control

This commit is contained in:
k1ngsterr1
2026-01-14 02:32:33 +05:00
parent ee543ddf18
commit 8c5efae0a1

View File

@@ -1039,17 +1039,13 @@ fun ChatDetailScreen(
} }
} }
) { paddingValues -> ) { paddingValues ->
// 🔥 Дополнительный отступ снизу для эмодзи панели // 🔥 Column структура - список сжимается когда клавиатура открывается
// Учитываем высоту панели + 16dp отступ снизу для безопасной зоны // Emoji panel внутри MessageInputBar - НЕ нужен дополнительный отступ
val emojiBottomPadding = if (showEmojiPicker && imeHeight < 50.dp) (emojiPanelHeight + 16.dp) else 0.dp
// 🔥 Column структура - список сжимается когда клавиатура/эмодзи открывается
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(top = paddingValues.calculateTopPadding()) .padding(top = paddingValues.calculateTopPadding())
.imePadding() // 🔥 Поднимаем весь контент над клавиатурой .imePadding() // 🔥 Поднимаем весь контент над клавиатурой
.padding(bottom = emojiBottomPadding) // 🔥 Отступ для эмодзи панели (после imePadding!)
.background(backgroundColor) .background(backgroundColor)
) { ) {
// Список сообщений - занимает всё доступное место // Список сообщений - занимает всё доступное место
@@ -2021,9 +2017,12 @@ private fun MessageInputBar(
// Состояние отправки - можно отправить если есть текст ИЛИ есть reply // Состояние отправки - можно отправить если есть текст ИЛИ есть reply
val canSend = remember(value, hasReply) { value.isNotBlank() || hasReply } val canSend = remember(value, hasReply) { value.isNotBlank() || hasReply }
// 🔥 Закрываем эмодзи панель когда клавиатура открывается // 🔥 Плавно закрываем эмодзи панель когда клавиатура ПОЛНОСТЬЮ открылась
// Используем LaunchedEffect с debounce чтобы избежать дёрганья
LaunchedEffect(isKeyboardVisible) { LaunchedEffect(isKeyboardVisible) {
if (isKeyboardVisible && showEmojiPicker) { if (isKeyboardVisible && showEmojiPicker) {
// Ждём пока клавиатура полностью поднимется (200ms)
kotlinx.coroutines.delay(200)
onToggleEmojiPicker(false) onToggleEmojiPicker(false)
} }
} }
@@ -2049,14 +2048,18 @@ private fun MessageInputBar(
if (showEmojiPicker) { if (showEmojiPicker) {
// Закрываем emoji picker и открываем клавиатуру // Закрываем emoji picker и открываем клавиатуру
onToggleEmojiPicker(false) onToggleEmojiPicker(false)
// Клавиатура откроется автоматически т.к. фокус остался // Открываем клавиатуру
editTextView?.let { editText ->
editText.requestFocus()
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
}
} else { } else {
// Закрываем клавиатуру через IMM // 🔥 Сначала показываем эмодзи панель
onToggleEmojiPicker(true)
// Потом скрываем клавиатуру (панель уже видна, поэтому не будет прыжка)
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0) imm.hideSoftInputFromWindow(view.windowToken, 0)
// 🔥 Показываем эмодзи сразу - без задержки!
onToggleEmojiPicker(true)
android.util.Log.d("MessageInputBar", "🎯 toggleEmojiPicker: showEmojiPicker=true, emojiPanelHeight=$emojiPanelHeight")
} }
} }
@@ -2298,46 +2301,40 @@ private fun MessageInputBar(
} // End of else (not blocked) } // End of else (not blocked)
// 🔥 APPLE EMOJI PICKER - БЕЗ анимации когда клавиатура открывается // 🔥 APPLE EMOJI PICKER - плавная анимация slide up
if (!isBlocked) { if (!isBlocked) {
// Высота панели: 0 если клавиатура видна или эмодзи закрыты, иначе emojiPanelHeight // Показываем только когда клавиатура закрыта И эмодзи открыты
val targetHeight = if (isKeyboardVisible || !showEmojiPicker) 0.dp else emojiPanelHeight val showPanel = showEmojiPicker && !isKeyboardVisible
// Анимируем только когда клавиатура закрыта AnimatedVisibility(
val animatedHeight by animateDpAsState( visible = showPanel,
targetValue = targetHeight, enter = slideInVertically(
animationSpec = if (isKeyboardVisible) { initialOffsetY = { it }, // Снизу вверх
// Мгновенно когда клавиатура открывается animationSpec = tween(200, easing = FastOutSlowInEasing)
snap() ),
} else { exit = slideOutVertically(
// Быстрая анимация (200ms) targetOffsetY = { it }, // Сверху вниз
tween(durationMillis = 200, easing = FastOutSlowInEasing) animationSpec = tween(150, easing = FastOutSlowInEasing)
}, )
label = "EmojiPanelHeight" ) {
)
// 🔥 Показываем Box только когда есть высота (НЕ занимает место когда скрыт!)
if (animatedHeight > 0.dp) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(animatedHeight) .height(emojiPanelHeight)
.padding(bottom = 16.dp) .padding(bottom = 16.dp)
) { ) {
if (showEmojiPicker) { AppleEmojiPickerPanel(
AppleEmojiPickerPanel( isDarkTheme = isDarkTheme,
isDarkTheme = isDarkTheme, onEmojiSelected = { emoji ->
onEmojiSelected = { emoji -> onValueChange(value + emoji)
onValueChange(value + emoji) },
}, onClose = {
onClose = { onToggleEmojiPicker(false)
onToggleEmojiPicker(false) },
}, modifier = Modifier
modifier = Modifier .fillMaxWidth()
.fillMaxWidth() .height(emojiPanelHeight - 16.dp)
.height(emojiPanelHeight - 16.dp) )
)
}
} }
} }
} // End of if (!isBlocked) for emoji picker } // End of if (!isBlocked) for emoji picker