From 64acf515d278c34ea6f059fe3de38185c79670ca Mon Sep 17 00:00:00 2001 From: k1ngsterr1 Date: Thu, 15 Jan 2026 15:49:05 +0500 Subject: [PATCH] feat: Implement smart logging for keyboard and emoji height transitions --- app/build.gradle.kts | 7 ++++ app/src/main/baseline-prof.txt | 38 +++++++++++++++++++ .../ui/keyboard/AnimatedKeyboardTransition.kt | 29 +++++++++----- .../keyboard/KeyboardTransitionCoordinator.kt | 29 +++++++------- 4 files changed, 77 insertions(+), 26 deletions(-) create mode 100644 app/src/main/baseline-prof.txt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 573e4c3..fb2f6ba 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -38,6 +38,10 @@ android { ) signingConfig = signingConfigs.getByName("release") } + debug { + // Enable baseline profiles in debug builds too for testing + // Remove this in production + } } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -100,6 +104,9 @@ dependencies { // Biometric authentication implementation("androidx.biometric:biometric:1.1.0") + // Baseline Profiles for startup performance + implementation("androidx.profileinstaller:profileinstaller:1.3.1") + // Testing dependencies testImplementation("junit:junit:4.13.2") testImplementation("io.mockk:mockk:1.13.8") diff --git a/app/src/main/baseline-prof.txt b/app/src/main/baseline-prof.txt new file mode 100644 index 0000000..c594a05 --- /dev/null +++ b/app/src/main/baseline-prof.txt @@ -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;->(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; diff --git a/app/src/main/java/app/rosette/android/ui/keyboard/AnimatedKeyboardTransition.kt b/app/src/main/java/app/rosette/android/ui/keyboard/AnimatedKeyboardTransition.kt index 4e80546..74e33bc 100644 --- a/app/src/main/java/app/rosette/android/ui/keyboard/AnimatedKeyboardTransition.kt +++ b/app/src/main/java/app/rosette/android/ui/keyboard/AnimatedKeyboardTransition.kt @@ -41,6 +41,9 @@ fun AnimatedKeyboardTransition( var wasEmojiShown by remember { mutableStateOf(false) } var isTransitioningToKeyboard by remember { mutableStateOf(false) } + // 📊 Последнее залогированное значение alpha (для фильтрации) + val lastLoggedAlpha = remember { mutableStateOf(-1f) } + // 🔥 Клавиатура достигла ПОЛНОЙ высоты (разница не более 3dp) val isKeyboardFullHeight = coordinator.emojiHeight > 0.dp && coordinator.keyboardHeight >= coordinator.emojiHeight - 3.dp @@ -54,15 +57,11 @@ fun AnimatedKeyboardTransition( isTransitioningToKeyboard = true } - // 🔥 КЛЮЧЕВОЕ: Сбрасываем флаг ПОСЛЕ небольшой задержки когда клавиатура полностью открылась - // Это гарантирует что Box останется виден пока система не отрисует клавиатуру - LaunchedEffect(isKeyboardFullHeight, isTransitioningToKeyboard) { - if (isKeyboardFullHeight && isTransitioningToKeyboard) { - delay(50) // Небольшая задержка для завершения отрисовки - isTransitioningToKeyboard = false - wasEmojiShown = false - Log.d("AnimatedTransition", "✅ Transition complete, keyboard at full height") - } + // 🔥 КЛЮЧЕВОЕ: Сбрасываем флаг БЕЗ задержки когда клавиатура полностью открылась + // Проверяем прямо в composition для мгновенной реакции + if (isKeyboardFullHeight && isTransitioningToKeyboard) { + isTransitioningToKeyboard = false + wasEmojiShown = false } // 🎯 Целевая прозрачность @@ -86,7 +85,17 @@ fun AnimatedKeyboardTransition( // 🔥 ВАЖНО: Обновляем состояние в координаторе для отключения imePadding 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) { Box( diff --git a/app/src/main/java/app/rosette/android/ui/keyboard/KeyboardTransitionCoordinator.kt b/app/src/main/java/app/rosette/android/ui/keyboard/KeyboardTransitionCoordinator.kt index f8b4139..b1f910e 100644 --- a/app/src/main/java/app/rosette/android/ui/keyboard/KeyboardTransitionCoordinator.kt +++ b/app/src/main/java/app/rosette/android/ui/keyboard/KeyboardTransitionCoordinator.kt @@ -71,6 +71,10 @@ class KeyboardTransitionCoordinator { // 🔥 Коллбэк для показа emoji (сохраняем для вызова после закрытия клавиатуры) private var pendingShowEmojiCallback: (() -> Unit)? = null + + // 📊 Для умного логирования (не каждый фрейм) + private var lastLogTime = 0L + private var lastLoggedHeight = -1f /** * Переход от системной клавиатуры к emoji панели. * @@ -253,40 +257,38 @@ class KeyboardTransitionCoordinator { * Обновить высоту клавиатуры из IME. */ fun updateKeyboardHeight(height: Dp) { - Log.d(TAG, "════════════════════════════════════════════════════════") - Log.d(TAG, "📏 updateKeyboardHeight called: $keyboardHeight → $height") - Log.d(TAG, " isKeyboardVisible=$isKeyboardVisible, emojiHeight=$emojiHeight, maxHeight=$maxKeyboardHeight") + val now = System.currentTimeMillis() + val heightChanged = kotlin.math.abs(height.value - lastLoggedHeight) > 5f + + // Логируем раз в 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) { - Log.d(TAG, "✅ Keyboard height updated: $keyboardHeight → $height") keyboardHeight = height // 🔥 Сохраняем максимальную высоту if (height > maxKeyboardHeight) { - Log.d(TAG, "📊 Updating max height: $maxKeyboardHeight → $height") maxKeyboardHeight = height } // Если emoji высота не установлена, синхронизировать if (emojiHeight == 0.dp) { - Log.d(TAG, "🔄 Syncing emoji height (was 0): $emojiHeight → $height") emojiHeight = height } } else if (height == 0.dp && keyboardHeight != 0.dp) { // 🔥 Клавиатура закрывается - восстанавливаем emojiHeight до МАКСИМАЛЬНОЙ высоты - Log.d(TAG, "⌨️ Keyboard closing, restoring emoji height to max") - Log.d(TAG, " Before: keyboardHeight=$keyboardHeight, emojiHeight=$emojiHeight, maxHeight=$maxKeyboardHeight") // Восстанавливаем emojiHeight до максимальной высоты if (maxKeyboardHeight > 0.dp) { emojiHeight = maxKeyboardHeight - Log.d(TAG, " After: emojiHeight restored to $maxKeyboardHeight") } // Обнуляем keyboardHeight keyboardHeight = 0.dp - } else { - Log.d(TAG, "⏭️ No update needed (height too small or unchanged)") } // 🔥 УБРАН pending callback - теперь emoji показывается сразу в requestShowEmoji() @@ -297,7 +299,6 @@ class KeyboardTransitionCoordinator { */ fun updateEmojiHeight(height: Dp) { if (height > 0.dp && height != emojiHeight) { - Log.d(TAG, "📏 Emoji height updated: $emojiHeight → $height") emojiHeight = height } } @@ -311,10 +312,7 @@ class KeyboardTransitionCoordinator { fun syncHeights() { // 🔥 Синхронизируем ТОЛЬКО если клавиатура ОТКРЫТА и высота больше текущей emoji if (keyboardHeight > 100.dp && keyboardHeight > emojiHeight) { - Log.d(TAG, "🔄 syncHeights: updating emoji $emojiHeight → $keyboardHeight") emojiHeight = keyboardHeight - } else { - Log.d(TAG, "⏭️ syncHeights: skipped (keyboard=$keyboardHeight, emoji=$emojiHeight)") } } @@ -324,7 +322,6 @@ class KeyboardTransitionCoordinator { */ fun initializeEmojiHeight(height: Dp) { if (emojiHeight == 0.dp && height > 0.dp) { - Log.d(TAG, "🚀 Initializing emoji height: $height") emojiHeight = height maxKeyboardHeight = height }