feat: Refactor MessageInputBar to improve emoji picker integration and UI responsiveness

This commit is contained in:
k1ngsterr1
2026-01-10 20:42:40 +05:00
parent 69ed43d26e
commit 9c0fae385c

View File

@@ -19,8 +19,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
@@ -107,7 +109,7 @@ fun ChatDetailScreen(
// Кастомный TopAppBar для чата // Кастомный TopAppBar для чата
Surface( Surface(
color = backgroundColor, color = backgroundColor,
shadowElevation = 4.dp shadowElevation = 0.dp
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@@ -209,7 +211,6 @@ fun ChatDetailScreen(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(paddingValues) .padding(paddingValues)
.imePadding() // Весь контент поднимается с клавиатурой
) { ) {
// Список сообщений // Список сообщений
Box( Box(
@@ -407,29 +408,23 @@ private fun MessageInputBar(
// Состояние эмодзи пикера // Состояние эмодзи пикера
var showEmojiPicker by remember { mutableStateOf(false) } var showEmojiPicker by remember { mutableStateOf(false) }
val keyboardController = LocalSoftwareKeyboardController.current val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
// Скрываем клавиатуру когда открыт эмодзи пикер
LaunchedEffect(showEmojiPicker) {
if (showEmojiPicker) {
keyboardController?.hide()
}
}
// Цвета для glass morphism эффекта // Цвета для glass morphism эффекта
val glassBackground = if (isDarkTheme) val glassBackground = if (isDarkTheme)
Color(0xFF1A1A1A).copy(alpha = 0.85f) Color(0xFF1A1A1A).copy(alpha = 0.95f)
else else
Color(0xFFFFFFFF).copy(alpha = 0.9f) Color(0xFFFFFFFF).copy(alpha = 0.95f)
val inputGlass = if (isDarkTheme) val inputGlass = if (isDarkTheme)
Color(0xFF2C2C2E).copy(alpha = 0.7f) Color(0xFF2C2C2E).copy(alpha = 0.8f)
else else
Color(0xFFF2F2F7).copy(alpha = 0.85f) Color(0xFFF2F2F7).copy(alpha = 0.9f)
val inputBorder = if (isDarkTheme) val inputBorder = if (isDarkTheme)
Color(0xFFFFFFFF).copy(alpha = 0.15f) Color(0xFFFFFFFF).copy(alpha = 0.12f)
else else
Color(0xFF000000).copy(alpha = 0.08f) Color(0xFF000000).copy(alpha = 0.06f)
val iconColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666) val iconColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
@@ -458,33 +453,11 @@ private fun MessageInputBar(
) )
Column( Column(
modifier = Modifier.fillMaxWidth() modifier = Modifier
.fillMaxWidth()
.imePadding() // Только инпут поднимается с клавиатурой
) { ) {
// Эмодзи пикер (показывается над инпутом) // Основной контейнер инпута
AnimatedVisibility(
visible = showEmojiPicker,
enter = slideInVertically(
initialOffsetY = { it },
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessMediumLow
)
) + fadeIn(),
exit = slideOutVertically(
targetOffsetY = { it },
animationSpec = tween(200)
) + fadeOut()
) {
EmojiPickerPanel(
isDarkTheme = isDarkTheme,
onEmojiSelected = { emoji ->
onValueChange(value + emoji)
},
onClose = { showEmojiPicker = false }
)
}
// Основной контейнер
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -493,9 +466,7 @@ private fun MessageInputBar(
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 12.dp, vertical = 8.dp) .padding(horizontal = 12.dp, vertical = 8.dp),
.padding(bottom = 4.dp)
.navigationBarsPadding(),
verticalAlignment = Alignment.Bottom verticalAlignment = Alignment.Bottom
) { ) {
// Единый стеклянный контейнер для всего инпута // Единый стеклянный контейнер для всего инпута
@@ -514,9 +485,9 @@ private fun MessageInputBar(
.background( .background(
brush = Brush.verticalGradient( brush = Brush.verticalGradient(
colors = listOf( colors = listOf(
Color.White.copy(alpha = if (isDarkTheme) 0.06f else 0.4f), Color.White.copy(alpha = if (isDarkTheme) 0.05f else 0.3f),
Color.Transparent, Color.Transparent,
Color.Black.copy(alpha = if (isDarkTheme) 0.03f else 0.02f) Color.Black.copy(alpha = if (isDarkTheme) 0.02f else 0.01f)
), ),
startY = 0f, startY = 0f,
endY = 80f endY = 80f
@@ -532,7 +503,14 @@ private fun MessageInputBar(
) { ) {
// Кнопка смайликов (слева внутри инпута) // Кнопка смайликов (слева внутри инпута)
IconButton( IconButton(
onClick = { showEmojiPicker = !showEmojiPicker }, onClick = {
if (showEmojiPicker) {
showEmojiPicker = false
} else {
keyboardController?.hide()
showEmojiPicker = true
}
},
modifier = Modifier.size(36.dp) modifier = Modifier.size(36.dp)
) { ) {
Icon( Icon(
@@ -547,7 +525,10 @@ private fun MessageInputBar(
Box( Box(
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.padding(vertical = 8.dp), .padding(vertical = 8.dp)
.clickable {
showEmojiPicker = false
},
contentAlignment = Alignment.CenterStart contentAlignment = Alignment.CenterStart
) { ) {
BasicTextField( BasicTextField(
@@ -558,7 +539,13 @@ private fun MessageInputBar(
fontSize = 16.sp fontSize = 16.sp
), ),
cursorBrush = SolidColor(PrimaryBlue), cursorBrush = SolidColor(PrimaryBlue),
modifier = Modifier.fillMaxWidth(), modifier = Modifier
.fillMaxWidth()
.onFocusChanged { focusState ->
if (focusState.isFocused) {
showEmojiPicker = false
}
},
maxLines = 5, maxLines = 5,
decorationBox = { innerTextField -> decorationBox = { innerTextField ->
Box( Box(
@@ -645,6 +632,35 @@ private fun MessageInputBar(
} }
} }
} }
// Эмодзи пикер (показывается под инпутом, заменяя клавиатуру)
AnimatedVisibility(
visible = showEmojiPicker,
enter = expandVertically(
expandFrom = Alignment.Top,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessMediumLow
)
) + fadeIn(animationSpec = tween(150)),
exit = shrinkVertically(
shrinkTowards = Alignment.Top,
animationSpec = tween(200)
) + fadeOut(animationSpec = tween(100))
) {
EmojiPickerPanel(
isDarkTheme = isDarkTheme,
onEmojiSelected = { emoji ->
onValueChange(value + emoji)
},
onClose = { showEmojiPicker = false }
)
}
// Spacer для navigation bar когда эмодзи пикер НЕ открыт
if (!showEmojiPicker) {
Spacer(modifier = Modifier.navigationBarsPadding())
}
} }
} }