feat: enhance keyboard height management and emoji picker synchronization in GroupSetupScreen
This commit is contained in:
@@ -54,7 +54,7 @@ class KeyboardTransitionCoordinator {
|
|||||||
var keyboardHeight by mutableStateOf(0.dp)
|
var keyboardHeight by mutableStateOf(0.dp)
|
||||||
var emojiHeight by mutableStateOf(0.dp)
|
var emojiHeight by mutableStateOf(0.dp)
|
||||||
|
|
||||||
// 🔥 Сохраняем максимальную высоту клавиатуры для правильного восстановления emoji
|
// Максимальная высота клавиатуры (защищает от промежуточных значений при анимации закрытия)
|
||||||
private var maxKeyboardHeight by mutableStateOf(0.dp)
|
private var maxKeyboardHeight by mutableStateOf(0.dp)
|
||||||
|
|
||||||
// ============ Флаги видимости ============
|
// ============ Флаги видимости ============
|
||||||
@@ -84,8 +84,10 @@ class KeyboardTransitionCoordinator {
|
|||||||
currentState = TransitionState.KEYBOARD_TO_EMOJI
|
currentState = TransitionState.KEYBOARD_TO_EMOJI
|
||||||
isTransitioning = true
|
isTransitioning = true
|
||||||
|
|
||||||
// 🔥 Гарантируем что emojiHeight = maxKeyboardHeight (не меняется при закрытии клавиатуры)
|
// Устанавливаем emojiHeight = текущая высота клавиатуры (клавиатура ещё открыта)
|
||||||
if (maxKeyboardHeight > 0.dp) {
|
if (keyboardHeight > 0.dp) {
|
||||||
|
emojiHeight = keyboardHeight
|
||||||
|
} else if (maxKeyboardHeight > 0.dp) {
|
||||||
emojiHeight = maxKeyboardHeight
|
emojiHeight = maxKeyboardHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +236,7 @@ class KeyboardTransitionCoordinator {
|
|||||||
if (height > 100.dp && height != keyboardHeight) {
|
if (height > 100.dp && height != keyboardHeight) {
|
||||||
keyboardHeight = height
|
keyboardHeight = height
|
||||||
|
|
||||||
// 🔥 Сохраняем максимальную высоту
|
// Обновляем maxKeyboardHeight только вверх (защита от промежуточных значений анимации)
|
||||||
if (height > maxKeyboardHeight) {
|
if (height > maxKeyboardHeight) {
|
||||||
maxKeyboardHeight = height
|
maxKeyboardHeight = height
|
||||||
}
|
}
|
||||||
@@ -244,14 +246,14 @@ class KeyboardTransitionCoordinator {
|
|||||||
emojiHeight = height
|
emojiHeight = height
|
||||||
}
|
}
|
||||||
} else if (height == 0.dp && keyboardHeight != 0.dp) {
|
} else if (height == 0.dp && keyboardHeight != 0.dp) {
|
||||||
// 🔥 Клавиатура закрывается - восстанавливаем emojiHeight до МАКСИМАЛЬНОЙ высоты
|
// Клавиатура закрывается.
|
||||||
|
// Если emoji уже показан (keyboard→emoji переход), НЕ трогаем emojiHeight —
|
||||||
// Восстанавливаем emojiHeight до максимальной высоты
|
// requestShowEmoji() уже установил правильное значение = текущая высота клавиатуры.
|
||||||
if (maxKeyboardHeight > 0.dp) {
|
// Восстанавливаем из maxKeyboardHeight только если emoji НЕ виден (обычное закрытие).
|
||||||
|
if (!isEmojiVisible && !isEmojiBoxVisible && maxKeyboardHeight > 0.dp) {
|
||||||
emojiHeight = maxKeyboardHeight
|
emojiHeight = maxKeyboardHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обнуляем keyboardHeight
|
|
||||||
keyboardHeight = 0.dp
|
keyboardHeight = 0.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +274,8 @@ class KeyboardTransitionCoordinator {
|
|||||||
* emojiHeight должна оставаться фиксированной!
|
* emojiHeight должна оставаться фиксированной!
|
||||||
*/
|
*/
|
||||||
fun syncHeights() {
|
fun syncHeights() {
|
||||||
// 🔥 Синхронизируем ТОЛЬКО если клавиатура ОТКРЫТА и высота больше текущей emoji
|
// Синхронизируем только вверх — при закрытии клавиатуры промежуточные значения
|
||||||
|
// не должны уменьшать emojiHeight. Точная высота ставится в requestShowEmoji().
|
||||||
if (keyboardHeight > 100.dp && keyboardHeight > emojiHeight) {
|
if (keyboardHeight > 100.dp && keyboardHeight > emojiHeight) {
|
||||||
emojiHeight = keyboardHeight
|
emojiHeight = keyboardHeight
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import android.view.inputmethod.InputMethodManager
|
|||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -243,15 +245,28 @@ fun GroupSetupScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lastStableKeyboardHeight by remember { mutableStateOf(0.dp) }
|
var lastStableKeyboardHeight by remember { mutableStateOf(0.dp) }
|
||||||
|
var isKeyboardVisible by remember { mutableStateOf(false) }
|
||||||
LaunchedEffect(imeBottomPx) {
|
LaunchedEffect(imeBottomPx) {
|
||||||
val currentImeHeight = with(density) { imeBottomPx.toDp() }
|
val currentImeHeight = with(density) { imeBottomPx.toDp() }
|
||||||
coordinator.updateKeyboardHeight(currentImeHeight)
|
coordinator.updateKeyboardHeight(currentImeHeight)
|
||||||
|
isKeyboardVisible = currentImeHeight > 50.dp
|
||||||
if (currentImeHeight > 100.dp) {
|
if (currentImeHeight > 100.dp) {
|
||||||
coordinator.syncHeights()
|
coordinator.syncHeights()
|
||||||
lastStableKeyboardHeight = currentImeHeight
|
lastStableKeyboardHeight = currentImeHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save keyboard height for emoji picker sync
|
||||||
|
LaunchedEffect(isKeyboardVisible, showEmojiKeyboard) {
|
||||||
|
if (isKeyboardVisible && !showEmojiKeyboard) {
|
||||||
|
kotlinx.coroutines.delay(350)
|
||||||
|
if (isKeyboardVisible && !showEmojiKeyboard && lastStableKeyboardHeight > 300.dp) {
|
||||||
|
val heightPx = with(density) { lastStableKeyboardHeight.toPx().toInt() }
|
||||||
|
KeyboardHeightProvider.saveKeyboardHeight(context, heightPx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun toggleEmojiPicker() {
|
fun toggleEmojiPicker() {
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
if (now - lastToggleTime < toggleCooldownMs || step != GroupSetupStep.DETAILS || isLoading) return
|
if (now - lastToggleTime < toggleCooldownMs || step != GroupSetupStep.DETAILS || isLoading) return
|
||||||
@@ -725,22 +740,24 @@ fun GroupSetupScreen(
|
|||||||
containerColor = if (actionEnabled) accentColor else accentColor.copy(alpha = 0.42f),
|
containerColor = if (actionEnabled) accentColor else accentColor.copy(alpha = 0.42f),
|
||||||
contentColor = Color.White,
|
contentColor = Color.White,
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
modifier =
|
modifier = run {
|
||||||
|
var lastStableFabBottom by remember { mutableStateOf(18.dp) }
|
||||||
|
val rawBottom = if (imeBottomDp > 0.dp) {
|
||||||
|
imeBottomDp + 14.dp
|
||||||
|
} else if (coordinator.isEmojiBoxVisible && coordinator.emojiHeight > 0.dp) {
|
||||||
|
coordinator.emojiHeight + 14.dp
|
||||||
|
} else {
|
||||||
|
18.dp
|
||||||
|
}
|
||||||
|
// During keyboard switch, keep FAB at last stable position
|
||||||
|
if (!coordinator.isTransitioning) {
|
||||||
|
lastStableFabBottom = rawBottom
|
||||||
|
}
|
||||||
Modifier
|
Modifier
|
||||||
.align(Alignment.BottomEnd)
|
.align(Alignment.BottomEnd)
|
||||||
.padding(
|
.padding(end = 16.dp, bottom = lastStableFabBottom)
|
||||||
end = 16.dp,
|
|
||||||
// Consistent: always 14dp above whichever keyboard is showing.
|
|
||||||
// This Box ignores paddingValues, so we measure from raw screen bottom.
|
|
||||||
bottom = if (imeBottomDp > 0.dp) {
|
|
||||||
imeBottomDp + 14.dp
|
|
||||||
} else if (coordinator.isEmojiBoxVisible && coordinator.emojiHeight > 0.dp) {
|
|
||||||
coordinator.emojiHeight + 14.dp
|
|
||||||
} else {
|
|
||||||
18.dp
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.size(58.dp)
|
.size(58.dp)
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
if (isLoading && step == GroupSetupStep.DESCRIPTION) {
|
if (isLoading && step == GroupSetupStep.DESCRIPTION) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
|
|||||||
Reference in New Issue
Block a user