feat: Implement smart logging for keyboard and emoji height transitions

This commit is contained in:
k1ngsterr1
2026-01-15 15:49:05 +05:00
parent 959e56461a
commit 64acf515d2
4 changed files with 77 additions and 26 deletions

View File

@@ -38,6 +38,10 @@ android {
) )
signingConfig = signingConfigs.getByName("release") signingConfig = signingConfigs.getByName("release")
} }
debug {
// Enable baseline profiles in debug builds too for testing
// Remove this in production
}
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
@@ -100,6 +104,9 @@ dependencies {
// Biometric authentication // Biometric authentication
implementation("androidx.biometric:biometric:1.1.0") implementation("androidx.biometric:biometric:1.1.0")
// Baseline Profiles for startup performance
implementation("androidx.profileinstaller:profileinstaller:1.3.1")
// Testing dependencies // Testing dependencies
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk:1.13.8") testImplementation("io.mockk:mockk:1.13.8")

View File

@@ -0,0 +1,38 @@
# Baseline Profile для Rosetta Messenger
# Предкомпилирует критические функции при установке APK
# ============ Keyboard & Animation (приоритет #1) ============
# MessageInputBar - основной источник JIT лага
Lcom/rosetta/messenger/ui/chats/ChatDetailScreenKt;->MessageInputBar-c4CPeSU(Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;ZJJJJLjava/util/List;ZLkotlin/jvm/functions/Function0;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;Landroidx/compose/ui/focus/FocusRequester;Lapp/rosette/android/ui/keyboard/KeyboardTransitionCoordinator;Landroidx/compose/runtime/Composer;III)V
# AnimatedKeyboardTransition - fade анимация
Lapp/rosette/android/ui/keyboard/AnimatedKeyboardTransitionKt;->AnimatedKeyboardTransition(Lapp/rosette/android/ui/keyboard/KeyboardTransitionCoordinator;ZLkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;I)V
# KeyboardTransitionCoordinator - управление состоянием
Lapp/rosette/android/ui/keyboard/KeyboardTransitionCoordinator;->updateKeyboardHeight(F)V
Lapp/rosette/android/ui/keyboard/KeyboardTransitionCoordinator;->requestShowEmoji(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
Lapp/rosette/android/ui/keyboard/KeyboardTransitionCoordinator;->requestShowKeyboard(Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
# ============ EmojiPicker (приоритет #2) ============
# OptimizedEmojiPicker - основной UI эмодзи
Lcom/rosetta/messenger/ui/components/emoji/OptimizedEmojiPickerKt;->OptimizedEmojiPicker(Lkotlin/jvm/functions/Function1;FLandroidx/compose/runtime/Composer;I)V
# EmojiPickerContent - рендеринг эмодзи
Lcom/rosetta/messenger/ui/components/emoji/OptimizedEmojiPickerKt;->EmojiPickerContent(Lkotlin/jvm/functions/Function1;FLandroidx/compose/runtime/Composer;I)V
# ============ ChatDetailScreen (приоритет #3) ============
# Главный экран чата
Lcom/rosetta/messenger/ui/chats/ChatDetailScreenKt;->ChatDetailScreen(JLandroidx/navigation/NavController;Landroidx/compose/runtime/Composer;I)V
# MessageBubble - рендеринг сообщений
Lcom/rosetta/messenger/ui/chats/ChatDetailScreenKt;->MessageBubble(Lcom/rosetta/messenger/data/local/entity/Message;ZZZLkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
# ============ Navigation (приоритет #4) ============
# Навигация между экранами
Lcom/rosetta/messenger/MainActivity;->onCreate(Landroid/os/Bundle;)V
# ============ Common Compose (приоритет #5) ============
# Часто используемые Compose компоненты
HSPLandroidx/compose/foundation/lazy/LazyListState;->scrollToItem(IILkotlin/coroutines/Continuation;)Ljava/lang/Object;
HSPLandroidx/compose/ui/text/input/TextFieldValue;-><init>(Ljava/lang/String;JLandroidx/compose/ui/text/TextRange;)V
HSPLandroidx/compose/animation/core/Animatable;->animateTo(Ljava/lang/Object;Landroidx/compose/animation/core/AnimationSpec;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;

View File

@@ -41,6 +41,9 @@ fun AnimatedKeyboardTransition(
var wasEmojiShown by remember { mutableStateOf(false) } var wasEmojiShown by remember { mutableStateOf(false) }
var isTransitioningToKeyboard by remember { mutableStateOf(false) } var isTransitioningToKeyboard by remember { mutableStateOf(false) }
// 📊 Последнее залогированное значение alpha (для фильтрации)
val lastLoggedAlpha = remember { mutableStateOf(-1f) }
// 🔥 Клавиатура достигла ПОЛНОЙ высоты (разница не более 3dp) // 🔥 Клавиатура достигла ПОЛНОЙ высоты (разница не более 3dp)
val isKeyboardFullHeight = coordinator.emojiHeight > 0.dp && val isKeyboardFullHeight = coordinator.emojiHeight > 0.dp &&
coordinator.keyboardHeight >= coordinator.emojiHeight - 3.dp coordinator.keyboardHeight >= coordinator.emojiHeight - 3.dp
@@ -54,15 +57,11 @@ fun AnimatedKeyboardTransition(
isTransitioningToKeyboard = true isTransitioningToKeyboard = true
} }
// 🔥 КЛЮЧЕВОЕ: Сбрасываем флаг ПОСЛЕ небольшой задержки когда клавиатура полностью открылась // 🔥 КЛЮЧЕВОЕ: Сбрасываем флаг БЕЗ задержки когда клавиатура полностью открылась
// Это гарантирует что Box останется виден пока система не отрисует клавиатуру // Проверяем прямо в composition для мгновенной реакции
LaunchedEffect(isKeyboardFullHeight, isTransitioningToKeyboard) { if (isKeyboardFullHeight && isTransitioningToKeyboard) {
if (isKeyboardFullHeight && isTransitioningToKeyboard) { isTransitioningToKeyboard = false
delay(50) // Небольшая задержка для завершения отрисовки wasEmojiShown = false
isTransitioningToKeyboard = false
wasEmojiShown = false
Log.d("AnimatedTransition", "✅ Transition complete, keyboard at full height")
}
} }
// 🎯 Целевая прозрачность // 🎯 Целевая прозрачность
@@ -86,7 +85,17 @@ fun AnimatedKeyboardTransition(
// 🔥 ВАЖНО: Обновляем состояние в координаторе для отключения imePadding // 🔥 ВАЖНО: Обновляем состояние в координаторе для отключения imePadding
coordinator.isEmojiBoxVisible = shouldShowBox coordinator.isEmojiBoxVisible = shouldShowBox
Log.d(tag, "🎨 Emoji panel: show=$showEmojiPicker, alpha=$animatedAlpha, shouldShow=$shouldShowBox, transitioning=$isTransitioningToKeyboard, kbHeight=${coordinator.keyboardHeight}, emojiH=${coordinator.emojiHeight}") // 📊 Умное логирование: только ключевые моменты (0%, 25%, 50%, 75%, 100%)
val alphaPercent = (animatedAlpha * 100).toInt()
val lastPercent = (lastLoggedAlpha.value * 100).toInt()
val shouldLog = alphaPercent == 0 || alphaPercent == 25 || alphaPercent == 50 ||
alphaPercent == 75 || alphaPercent == 100 ||
(lastPercent != alphaPercent && (alphaPercent % 10 == 0))
if (shouldLog && lastLoggedAlpha.value != animatedAlpha) {
lastLoggedAlpha.value = animatedAlpha
Log.d(tag, "🎬 Alpha: ${alphaPercent}%, show=$showEmojiPicker, shouldShow=$shouldShowBox, transitioning=$isTransitioningToKeyboard, kb=${coordinator.keyboardHeight.value.toInt()}dp")
}
if (shouldShowBox) { if (shouldShowBox) {
Box( Box(

View File

@@ -71,6 +71,10 @@ class KeyboardTransitionCoordinator {
// 🔥 Коллбэк для показа emoji (сохраняем для вызова после закрытия клавиатуры) // 🔥 Коллбэк для показа emoji (сохраняем для вызова после закрытия клавиатуры)
private var pendingShowEmojiCallback: (() -> Unit)? = null private var pendingShowEmojiCallback: (() -> Unit)? = null
// 📊 Для умного логирования (не каждый фрейм)
private var lastLogTime = 0L
private var lastLoggedHeight = -1f
/** /**
* Переход от системной клавиатуры к emoji панели. * Переход от системной клавиатуры к emoji панели.
* *
@@ -253,40 +257,38 @@ class KeyboardTransitionCoordinator {
* Обновить высоту клавиатуры из IME. * Обновить высоту клавиатуры из IME.
*/ */
fun updateKeyboardHeight(height: Dp) { fun updateKeyboardHeight(height: Dp) {
Log.d(TAG, "════════════════════════════════════════════════════════") val now = System.currentTimeMillis()
Log.d(TAG, "📏 updateKeyboardHeight called: $keyboardHeight$height") val heightChanged = kotlin.math.abs(height.value - lastLoggedHeight) > 5f
Log.d(TAG, " isKeyboardVisible=$isKeyboardVisible, emojiHeight=$emojiHeight, maxHeight=$maxKeyboardHeight")
// Логируем раз в 50ms ИЛИ при значительном изменении высоты (>5dp)
if (heightChanged && (now - lastLogTime > 50 || lastLoggedHeight < 0)) {
Log.d(TAG, "⌨️ KB: ${height.value.toInt()}dp, emoji: ${emojiHeight.value.toInt()}dp, visible=$isKeyboardVisible")
lastLogTime = now
lastLoggedHeight = height.value
}
if (height > 100.dp && height != keyboardHeight) { if (height > 100.dp && height != keyboardHeight) {
Log.d(TAG, "✅ Keyboard height updated: $keyboardHeight$height")
keyboardHeight = height keyboardHeight = height
// 🔥 Сохраняем максимальную высоту // 🔥 Сохраняем максимальную высоту
if (height > maxKeyboardHeight) { if (height > maxKeyboardHeight) {
Log.d(TAG, "📊 Updating max height: $maxKeyboardHeight$height")
maxKeyboardHeight = height maxKeyboardHeight = height
} }
// Если emoji высота не установлена, синхронизировать // Если emoji высота не установлена, синхронизировать
if (emojiHeight == 0.dp) { if (emojiHeight == 0.dp) {
Log.d(TAG, "🔄 Syncing emoji height (was 0): $emojiHeight$height")
emojiHeight = height emojiHeight = height
} }
} else if (height == 0.dp && keyboardHeight != 0.dp) { } else if (height == 0.dp && keyboardHeight != 0.dp) {
// 🔥 Клавиатура закрывается - восстанавливаем emojiHeight до МАКСИМАЛЬНОЙ высоты // 🔥 Клавиатура закрывается - восстанавливаем emojiHeight до МАКСИМАЛЬНОЙ высоты
Log.d(TAG, "⌨️ Keyboard closing, restoring emoji height to max")
Log.d(TAG, " Before: keyboardHeight=$keyboardHeight, emojiHeight=$emojiHeight, maxHeight=$maxKeyboardHeight")
// Восстанавливаем emojiHeight до максимальной высоты // Восстанавливаем emojiHeight до максимальной высоты
if (maxKeyboardHeight > 0.dp) { if (maxKeyboardHeight > 0.dp) {
emojiHeight = maxKeyboardHeight emojiHeight = maxKeyboardHeight
Log.d(TAG, " After: emojiHeight restored to $maxKeyboardHeight")
} }
// Обнуляем keyboardHeight // Обнуляем keyboardHeight
keyboardHeight = 0.dp keyboardHeight = 0.dp
} else {
Log.d(TAG, "⏭️ No update needed (height too small or unchanged)")
} }
// 🔥 УБРАН pending callback - теперь emoji показывается сразу в requestShowEmoji() // 🔥 УБРАН pending callback - теперь emoji показывается сразу в requestShowEmoji()
@@ -297,7 +299,6 @@ class KeyboardTransitionCoordinator {
*/ */
fun updateEmojiHeight(height: Dp) { fun updateEmojiHeight(height: Dp) {
if (height > 0.dp && height != emojiHeight) { if (height > 0.dp && height != emojiHeight) {
Log.d(TAG, "📏 Emoji height updated: $emojiHeight$height")
emojiHeight = height emojiHeight = height
} }
} }
@@ -311,10 +312,7 @@ class KeyboardTransitionCoordinator {
fun syncHeights() { fun syncHeights() {
// 🔥 Синхронизируем ТОЛЬКО если клавиатура ОТКРЫТА и высота больше текущей emoji // 🔥 Синхронизируем ТОЛЬКО если клавиатура ОТКРЫТА и высота больше текущей emoji
if (keyboardHeight > 100.dp && keyboardHeight > emojiHeight) { if (keyboardHeight > 100.dp && keyboardHeight > emojiHeight) {
Log.d(TAG, "🔄 syncHeights: updating emoji $emojiHeight$keyboardHeight")
emojiHeight = keyboardHeight emojiHeight = keyboardHeight
} else {
Log.d(TAG, "⏭️ syncHeights: skipped (keyboard=$keyboardHeight, emoji=$emojiHeight)")
} }
} }
@@ -324,7 +322,6 @@ class KeyboardTransitionCoordinator {
*/ */
fun initializeEmojiHeight(height: Dp) { fun initializeEmojiHeight(height: Dp) {
if (emojiHeight == 0.dp && height > 0.dp) { if (emojiHeight == 0.dp && height > 0.dp) {
Log.d(TAG, "🚀 Initializing emoji height: $height")
emojiHeight = height emojiHeight = height
maxKeyboardHeight = height maxKeyboardHeight = height
} }