feat: Enhance AppleEmojiPicker to load all emojis from assets and group them by category
This commit is contained in:
@@ -9,7 +9,6 @@ import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -56,11 +55,8 @@ import com.rosetta.messenger.ui.components.VerifiedBadge
|
||||
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.view.ViewTreeObserver
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -176,10 +172,11 @@ fun ChatDetailScreen(
|
||||
) {
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val focusManager = LocalFocusManager.current
|
||||
val backgroundColor = if (isDarkTheme) Color(0xFF0E0E0E) else Color(0xFFEFEFF3)
|
||||
// Цвета как в React Native themes.ts
|
||||
val backgroundColor = if (isDarkTheme) Color(0xFF1E1E1E) else Color(0xFFFFFFFF)
|
||||
val textColor = if (isDarkTheme) Color.White else Color.Black
|
||||
val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
|
||||
val inputBackgroundColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFF0F0F0)
|
||||
val inputBackgroundColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFF2F3F5)
|
||||
|
||||
// <20> Fade-in анимация для всего экрана
|
||||
var isVisible by remember { mutableStateOf(false) }
|
||||
@@ -288,40 +285,13 @@ fun ChatDetailScreen(
|
||||
// 🔥 Обработка системной кнопки назад
|
||||
BackHandler { hideKeyboardAndBack() }
|
||||
|
||||
// 🔥 Ручное отслеживание высоты клавиатуры
|
||||
val view = LocalView.current
|
||||
val density = LocalDensity.current
|
||||
var keyboardHeight by remember { mutableStateOf(0.dp) }
|
||||
|
||||
DisposableEffect(view) {
|
||||
val listener = ViewTreeObserver.OnGlobalLayoutListener {
|
||||
val rect = Rect()
|
||||
view.getWindowVisibleDisplayFrame(rect)
|
||||
val screenHeight = view.rootView.height
|
||||
val keyboardHeightPx = screenHeight - rect.bottom
|
||||
|
||||
// Учитываем navigation bar (если клавиатура меньше 150px - это не клавиатура)
|
||||
val actualKeyboardHeight = if (keyboardHeightPx > 150) keyboardHeightPx else 0
|
||||
|
||||
keyboardHeight = with(density) { actualKeyboardHeight.toDp() }
|
||||
}
|
||||
|
||||
view.viewTreeObserver.addOnGlobalLayoutListener(listener)
|
||||
|
||||
// 🔥 Cleanup при выходе из экрана
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
view.viewTreeObserver.removeOnGlobalLayoutListener(listener)
|
||||
focusManager.clearFocus()
|
||||
keyboardController?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
// Автоматический скролл вниз при появлении клавиатуры
|
||||
LaunchedEffect(keyboardHeight) {
|
||||
if (keyboardHeight > 0.dp && messages.isNotEmpty()) {
|
||||
delay(50)
|
||||
listState.animateScrollToItem(0)
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализируем ViewModel с ключами и открываем диалог
|
||||
LaunchedEffect(user.publicKey) {
|
||||
@@ -354,7 +324,10 @@ fun ChatDetailScreen(
|
||||
)
|
||||
|
||||
// 🚀 Весь контент с fade-in анимацией
|
||||
Box(modifier = Modifier.fillMaxSize().graphicsLayer { alpha = screenAlpha }) {
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.graphicsLayer { alpha = screenAlpha }
|
||||
) {
|
||||
// Telegram-style solid header background (без blur)
|
||||
val headerBackground = if (isDarkTheme) Color(0xFF212121) else Color(0xFFFFFFFF)
|
||||
|
||||
@@ -577,23 +550,17 @@ fun ChatDetailScreen(
|
||||
)
|
||||
}
|
||||
},
|
||||
containerColor = Color.Transparent
|
||||
containerColor = backgroundColor // Фон всего чата
|
||||
) { paddingValues ->
|
||||
// 🔥 Box с фиксированным Input внизу и сообщениями выше
|
||||
Box(
|
||||
// 🔥 Простой Column - сообщения сверху, инпут снизу
|
||||
// Клавиатура сама поднимает контент через adjustResize
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
) {
|
||||
// Список сообщений - занимает всё пространство, с padding снизу для input и клавиатуры
|
||||
val inputBarHeight = 60.dp
|
||||
val bottomPadding = inputBarHeight + keyboardHeight
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(bottom = bottomPadding)
|
||||
) {
|
||||
// Список сообщений - занимает всё доступное пространство
|
||||
Box(modifier = Modifier.weight(1f).fillMaxWidth()) {
|
||||
if (messages.isEmpty()) {
|
||||
// Пустое состояние
|
||||
Column(
|
||||
@@ -759,42 +726,35 @@ fun ChatDetailScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
} // Закрытие внутреннего Box для сообщений
|
||||
|
||||
// 🔥 INPUT BAR - фиксированный элемент внизу экрана
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = keyboardHeight) // Ручной padding над клавиатурой
|
||||
) {
|
||||
MessageInputBar(
|
||||
value = inputText,
|
||||
onValueChange = {
|
||||
viewModel.updateInputText(it)
|
||||
// Отправляем индикатор печатания
|
||||
if (it.isNotEmpty() && !isSavedMessages) {
|
||||
viewModel.sendTypingIndicator()
|
||||
}
|
||||
},
|
||||
onSend = {
|
||||
// Скрываем кнопку scroll на время отправки
|
||||
isSendingMessage = true
|
||||
viewModel.sendMessage()
|
||||
// Скроллим к новому сообщению
|
||||
scope.launch {
|
||||
delay(100)
|
||||
listState.animateScrollToItem(0)
|
||||
delay(300) // Ждём завершения анимации
|
||||
isSendingMessage = false
|
||||
}
|
||||
},
|
||||
isDarkTheme = isDarkTheme,
|
||||
backgroundColor = inputBackgroundColor,
|
||||
textColor = textColor,
|
||||
placeholderColor = secondaryTextColor
|
||||
)
|
||||
}
|
||||
|
||||
// 🔥 INPUT BAR - обычный элемент внизу Column
|
||||
MessageInputBar(
|
||||
value = inputText,
|
||||
onValueChange = {
|
||||
viewModel.updateInputText(it)
|
||||
// Отправляем индикатор печатания
|
||||
if (it.isNotEmpty() && !isSavedMessages) {
|
||||
viewModel.sendTypingIndicator()
|
||||
}
|
||||
},
|
||||
onSend = {
|
||||
// Скрываем кнопку scroll на время отправки
|
||||
isSendingMessage = true
|
||||
viewModel.sendMessage()
|
||||
// Скроллим к новому сообщению
|
||||
scope.launch {
|
||||
delay(100)
|
||||
listState.animateScrollToItem(0)
|
||||
delay(300) // Ждём завершения анимации
|
||||
isSendingMessage = false
|
||||
}
|
||||
},
|
||||
isDarkTheme = isDarkTheme,
|
||||
backgroundColor = inputBackgroundColor,
|
||||
textColor = textColor,
|
||||
placeholderColor = secondaryTextColor
|
||||
)
|
||||
}
|
||||
}
|
||||
} // Закрытие Box с fade-in
|
||||
@@ -1148,10 +1108,7 @@ private fun MessageInputBar(
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.background(Color.Transparent)
|
||||
// imePadding уже на родительском Column
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
// 🔥 TELEGRAM-STYLE FLOATING LIQUID GLASS INPUT
|
||||
Row(
|
||||
@@ -1344,9 +1301,5 @@ private fun MessageInputBar(
|
||||
onClose = { showEmojiPicker = false }
|
||||
)
|
||||
}
|
||||
|
||||
if (!showEmojiPicker) {
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user