feat: Update ChatDetailScreen to use inputBackgroundColor for dropdown menus and menu items

This commit is contained in:
k1ngsterr1
2026-01-15 13:21:07 +05:00
parent 1000f017f5
commit 911f9ebb5a
3 changed files with 184 additions and 246 deletions

View File

@@ -28,6 +28,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -71,6 +72,7 @@ import com.rosetta.messenger.ui.components.AppleEmojiTextField
import com.rosetta.messenger.ui.components.VerifiedBadge
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
import app.rosette.android.ui.keyboard.rememberKeyboardTransitionCoordinator
import app.rosette.android.ui.keyboard.KeyboardTransitionCoordinator
import app.rosette.android.ui.keyboard.AnimatedKeyboardTransition
import android.view.inputmethod.InputMethodManager
import android.content.Context
@@ -219,6 +221,8 @@ fun ChatDetailScreen(
onUserProfileClick: () -> Unit = {},
viewModel: ChatViewModel = viewModel()
) {
// 🔥 ОПТИМИЗАЦИЯ: Убрано логирование из композиции чтобы не засорять logcat
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
val clipboardManager = androidx.compose.ui.platform.LocalClipboardManager.current
@@ -247,26 +251,36 @@ fun ChatDetailScreen(
// 🔥 Emoji picker state (поднят из MessageInputBar для KeyboardAvoidingView)
var showEmojiPicker by remember { mutableStateOf(false) }
// Высота эмодзи панели - берём высоту клавиатуры если она открыта, иначе 280dp
val imeInsets = WindowInsets.ime
val imeHeight = with(density) { imeInsets.getBottom(density).toDp() }
val isKeyboardVisible = imeHeight > 50.dp
// 🔥 Запоминаем высоту клавиатуры когда она открыта
var savedKeyboardHeight by remember { mutableStateOf(280.dp) }
LaunchedEffect(imeHeight) {
if (imeHeight > 50.dp) {
savedKeyboardHeight = imeHeight
// 🎯 Координатор плавных переходов клавиатуры (Telegram-style)
val coordinator = rememberKeyboardTransitionCoordinator()
// 🔥 ОПТИМИЗАЦИЯ: НЕ читаем imeHeight напрямую в композиции!
// Используем snapshotFlow чтобы избежать рекомпозиции на каждый пиксель анимации
val imeInsets = WindowInsets.ime
// 🔥 Синхронизируем coordinator с IME высотой через snapshotFlow (БЕЗ рекомпозиции!)
LaunchedEffect(Unit) {
snapshotFlow {
with(density) { imeInsets.getBottom(density).toDp() }
}.collect { currentImeHeight ->
coordinator.updateKeyboardHeight(currentImeHeight)
if (currentImeHeight > 100.dp) {
coordinator.syncHeights()
}
}
}
// 🔥 Высота панели эмодзи = сохранённая высота клавиатуры (минимум 280.dp)
val emojiPanelHeight = maxOf(savedKeyboardHeight, 280.dp)
// 🔥 Флаг видимости панели эмодзи (тот же что в MessageInputBar) - единый источник правды
val isEmojiPanelVisible = showEmojiPicker && !isKeyboardVisible
// <20> Простой отступ без анимации - AnimatedVisibility сама анимирует
val emojiPanelPadding = if (isEmojiPanelVisible) emojiPanelHeight else 0.dp
// 🔥 Инициализируем высоту emoji панели из сохранённой высоты клавиатуры
LaunchedEffect(Unit) {
val savedHeightPx = com.rosetta.messenger.ui.components.KeyboardHeightProvider.getSavedKeyboardHeight(context)
if (savedHeightPx > 0) {
val savedHeightDp = with(density) { savedHeightPx.toDp() }
coordinator.initializeEmojiHeight(savedHeightDp)
} else {
coordinator.initializeEmojiHeight(280.dp) // fallback
}
}
// 🔥 Reply/Forward state
val replyMessages by viewModel.replyMessages.collectAsState()
@@ -736,7 +750,7 @@ fun ChatDetailScreen(
// Выпадающее меню - чистый дизайн без артефактов
MaterialTheme(
colorScheme = MaterialTheme.colorScheme.copy(
surface = if (isDarkTheme) Color(0xFF1C1C1E) else Color.White
surface = inputBackgroundColor
)
) {
DropdownMenu(
@@ -745,7 +759,7 @@ fun ChatDetailScreen(
modifier = Modifier
.width(220.dp)
.background(
color = if (isDarkTheme) Color(0xFF1C1C1E) else Color.White,
color = inputBackgroundColor,
shape = RoundedCornerShape(16.dp)
)
) {
@@ -775,7 +789,8 @@ fun ChatDetailScreen(
showMenu = false
showDeleteConfirm = true
},
modifier = Modifier.padding(horizontal = 8.dp),
modifier = Modifier.padding(horizontal = 8.dp)
.background(inputBackgroundColor),
colors = MenuDefaults.itemColors(
textColor = Color(0xFFE53935)
)
@@ -822,7 +837,8 @@ fun ChatDetailScreen(
showBlockConfirm = true
}
},
modifier = Modifier.padding(horizontal = 8.dp),
modifier = Modifier.padding(horizontal = 8.dp)
.background(inputBackgroundColor),
colors = MenuDefaults.itemColors(
textColor = PrimaryBlue
)
@@ -863,7 +879,8 @@ fun ChatDetailScreen(
showMenu = false
showLogs = true
},
modifier = Modifier.padding(horizontal = 8.dp),
modifier = Modifier.padding(horizontal = 8.dp)
.background(inputBackgroundColor),
colors = MenuDefaults.itemColors(
textColor = textColor
)
@@ -937,7 +954,9 @@ fun ChatDetailScreen(
showEmojiPicker = showEmojiPicker,
onToggleEmojiPicker = { showEmojiPicker = it },
// Focus requester для автофокуса при reply
focusRequester = inputFocusRequester
focusRequester = inputFocusRequester,
// Coordinator для плавных переходов
coordinator = coordinator
)
}
}
@@ -1978,8 +1997,12 @@ private fun MessageInputBar(
showEmojiPicker: Boolean = false,
onToggleEmojiPicker: (Boolean) -> Unit = {},
// Focus requester для автофокуса при reply
focusRequester: FocusRequester? = null
focusRequester: FocusRequester? = null,
// Coordinator для плавных переходов клавиатуры
coordinator: KeyboardTransitionCoordinator
) {
// 🔥 ОПТИМИЗАЦИЯ: Убрано логирование чтобы не засорять logcat
val hasReply = replyMessages.isNotEmpty()
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
@@ -1991,9 +2014,6 @@ private fun MessageInputBar(
val view = LocalView.current
val density = LocalDensity.current
// 🎯 Координатор плавных переходов клавиатуры (Telegram-style)
val coordinator = rememberKeyboardTransitionCoordinator()
// 🔥 Ссылка на EditText для программного фокуса
var editTextView by remember { mutableStateOf<com.rosetta.messenger.ui.components.AppleEmojiEditTextView?>(null) }
@@ -2021,56 +2041,47 @@ private fun MessageInputBar(
}
}
// 🔥 Отслеживаем высоту клавиатуры (Telegram-style)
// 🔥 ОПТИМИЗАЦИЯ: НЕ читаем imeHeight напрямую - это вызывает рекомпозицию!
val imeInsets = WindowInsets.ime
val imeHeight = with(density) { imeInsets.getBottom(density).toDp() }
val isKeyboardVisible = imeHeight > 50.dp // 🔥 Согласованный порог с ChatDetailScreen
// 🔥 Флаг "клавиатура в процессе анимации"
var isKeyboardAnimating by remember { mutableStateOf(false) }
// 🔥 Флаг "клавиатура видна" - обновляется через snapshotFlow, НЕ вызывает рекомпозицию
var isKeyboardVisible by remember { mutableStateOf(false) }
var lastStableKeyboardHeight by remember { mutableStateOf(0.dp) }
// 🔥 Логирование изменений высоты клавиатуры + обновление coordinator
LaunchedEffect(imeHeight) {
android.util.Log.d("KeyboardHeight", "═══════════════════════════════════════════════════════")
android.util.Log.d("KeyboardHeight", "📊 IME height changed: $imeHeight")
android.util.Log.d("KeyboardHeight", " isKeyboardVisible=$isKeyboardVisible")
android.util.Log.d("KeyboardHeight", " showEmojiPicker=$showEmojiPicker")
android.util.Log.d("KeyboardHeight", " isKeyboardAnimating=$isKeyboardAnimating")
// Обновляем coordinator с актуальной высотой клавиатуры
android.util.Log.d("KeyboardHeight", "🔄 Updating coordinator...")
coordinator.updateKeyboardHeight(imeHeight)
// Синхронизируем высоту emoji с клавиатурой
if (imeHeight > 100.dp) {
android.util.Log.d("KeyboardHeight", "🔄 Syncing heights...")
coordinator.syncHeights()
// 🔥 Обновляем coordinator через snapshotFlow (БЕЗ рекомпозиции!)
LaunchedEffect(Unit) {
snapshotFlow {
with(density) { imeInsets.getBottom(density).toDp() }
}.collect { currentImeHeight ->
// Обновляем флаг видимости (это НЕ вызывает рекомпозицию напрямую)
isKeyboardVisible = currentImeHeight > 50.dp
// Обновляем coordinator
coordinator.updateKeyboardHeight(currentImeHeight)
if (currentImeHeight > 100.dp) {
coordinator.syncHeights()
lastStableKeyboardHeight = currentImeHeight
}
}
android.util.Log.d("KeyboardHeight", "✅ Coordinator updated")
}
// 🔥 Запоминаем высоту клавиатуры когда она открыта (Telegram-style with SharedPreferences)
LaunchedEffect(Unit) {
// Загружаем сохранённую высоту при старте
val savedHeightPx = com.rosetta.messenger.ui.components.KeyboardHeightProvider.getSavedKeyboardHeight(context)
android.util.Log.d("KeyboardHeight", "📱 MessageInputBar initialized, loaded height: ${savedHeightPx}px")
com.rosetta.messenger.ui.components.KeyboardHeightProvider.getSavedKeyboardHeight(context)
}
// 🔥 Сохраняем высоту ТОЛЬКО когда клавиатура стабильна
// Используем отдельный LaunchedEffect который НЕ реагирует на каждое изменение
LaunchedEffect(isKeyboardVisible, showEmojiPicker) {
// Если клавиатура стала видимой и emoji закрыт
if (isKeyboardVisible && !showEmojiPicker && !isKeyboardAnimating) {
if (isKeyboardVisible && !showEmojiPicker) {
// Ждем стабилизации
isKeyboardAnimating = true
kotlinx.coroutines.delay(300) // Анимация клавиатуры ~250ms
isKeyboardAnimating = false
kotlinx.coroutines.delay(350) // Анимация клавиатуры ~300ms
// Сохраняем только если всё еще видна и emoji закрыт
if (isKeyboardVisible && !showEmojiPicker && imeHeight > 300.dp) {
val heightPx = with(density) { imeHeight.toPx().toInt() }
if (isKeyboardVisible && !showEmojiPicker && lastStableKeyboardHeight > 300.dp) {
val heightPx = with(density) { lastStableKeyboardHeight.toPx().toInt() }
com.rosetta.messenger.ui.components.KeyboardHeightProvider.saveKeyboardHeight(context, heightPx)
android.util.Log.d("KeyboardHeight", "✅ Stable keyboard height saved: ${imeHeight} (${heightPx}px)")
}
}
}
@@ -2343,8 +2354,6 @@ private fun MessageInputBar(
android.util.Log.d("EmojiPicker", "🔄 TextField focused while emoji open → closing emoji")
android.util.Log.d("EmojiPicker", " 📞 Calling onToggleEmojiPicker(false)...")
onToggleEmojiPicker(false)
android.util.Log.d("EmojiPicker", " 📞 Setting coordinator.isEmojiVisible = false...")
coordinator.isEmojiVisible = false
android.util.Log.d("EmojiPicker", " ✅ Emoji close requested")
} else if (hasFocus && !showEmojiPicker) {
android.util.Log.d("EmojiPicker", "⌨️ TextField focused with emoji closed → normal keyboard behavior")