feat: Optimize chat screen transitions by removing redundant animations for a smoother user experience
This commit is contained in:
@@ -229,16 +229,7 @@ fun ChatDetailScreen(
|
||||
// Цвет иконок в хедере - синий как в React Native
|
||||
val headerIconColor = if (isDarkTheme) Color.White else PrimaryBlue
|
||||
|
||||
// <EFBFBD> Fade-in анимация для всего экрана
|
||||
var isVisible by remember { mutableStateOf(false) }
|
||||
val screenAlpha by
|
||||
animateFloatAsState(
|
||||
targetValue = if (isVisible) 1f else 0f,
|
||||
animationSpec = tween(durationMillis = 250, easing = TelegramEasing),
|
||||
label = "screenFade"
|
||||
)
|
||||
|
||||
LaunchedEffect(Unit) { isVisible = true }
|
||||
// 🚀 Убираем дополнительную анимацию - используем только анимацию навигации из MainActivity
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -297,18 +288,13 @@ fun ChatDetailScreen(
|
||||
var selectedMessages by remember { mutableStateOf<Set<String>>(emptySet()) }
|
||||
val isSelectionMode = selectedMessages.isNotEmpty()
|
||||
|
||||
// 🔥 Быстрое закрытие с fade-out анимацией
|
||||
// 🔥 Быстрое закрытие - мгновенный выход без дополнительной анимации
|
||||
val hideKeyboardAndBack: () -> Unit = {
|
||||
// Мгновенно убираем фокус и клавиатуру
|
||||
focusManager.clearFocus(force = true)
|
||||
keyboardController?.hide()
|
||||
// Запускаем fade-out
|
||||
isVisible = false
|
||||
// Выходим после короткой анимации
|
||||
scope.launch {
|
||||
delay(150)
|
||||
onBack()
|
||||
}
|
||||
// Сразу выходим - анимация в MainActivity
|
||||
onBack()
|
||||
Unit
|
||||
}
|
||||
|
||||
@@ -328,9 +314,11 @@ fun ChatDetailScreen(
|
||||
var showBlockConfirm by remember { mutableStateOf(false) }
|
||||
var showUnblockConfirm by remember { mutableStateOf(false) }
|
||||
|
||||
// Проверяем, заблокирован ли пользователь
|
||||
// Проверяем, заблокирован ли пользователь (отложенно, не блокирует UI)
|
||||
var isBlocked by remember { mutableStateOf(false) }
|
||||
LaunchedEffect(user.publicKey, currentUserPublicKey) {
|
||||
// Отложенная проверка - не блокирует анимацию
|
||||
kotlinx.coroutines.delay(50) // Даём анимации завершиться
|
||||
isBlocked = database.blacklistDao().isUserBlocked(user.publicKey, currentUserPublicKey)
|
||||
}
|
||||
|
||||
@@ -432,11 +420,8 @@ fun ChatDetailScreen(
|
||||
isDarkTheme
|
||||
)
|
||||
|
||||
// 🚀 Весь контент с fade-in анимацией
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.graphicsLayer { alpha = screenAlpha }
|
||||
) {
|
||||
// 🚀 Весь контент без дополнительной анимации (анимация в MainActivity)
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
// Telegram-style solid header background (без blur)
|
||||
val headerBackground = if (isDarkTheme) Color(0xFF212121) else Color(0xFFFFFFFF)
|
||||
|
||||
|
||||
@@ -396,8 +396,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
// Подписываемся на онлайн статус
|
||||
subscribeToOnlineStatus()
|
||||
|
||||
// Загружаем сообщения из БД
|
||||
loadMessagesFromDatabase()
|
||||
// 🔥 ОПТИМИЗАЦИЯ: Загружаем сообщения ПОСЛЕ задержки для плавной анимации
|
||||
// 250ms - это время анимации перехода в чат
|
||||
loadMessagesFromDatabase(delayMs = 250L)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -411,8 +412,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
/**
|
||||
* 🚀 СУПЕР-оптимизированная загрузка сообщений
|
||||
* 🔥 ОПТИМИЗАЦИЯ: Задержка для завершения анимации + чанковая расшифровка
|
||||
*/
|
||||
private fun loadMessagesFromDatabase() {
|
||||
private fun loadMessagesFromDatabase(delayMs: Long = 0L) {
|
||||
val account = myPublicKey ?: return
|
||||
val opponent = opponentKey ?: return
|
||||
|
||||
@@ -421,6 +423,12 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
loadingJob = viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
// 🔥 Задержка перед загрузкой чтобы анимация перехода успела завершиться!
|
||||
// Это критично для плавности - иначе расшифровка блокирует UI thread
|
||||
if (delayMs > 0) {
|
||||
delay(delayMs)
|
||||
}
|
||||
|
||||
// 🔥 Сначала показываем loading НА ГЛАВНОМ потоке - мгновенно
|
||||
withContext(Dispatchers.Main.immediate) {
|
||||
_isLoading.value = true
|
||||
@@ -441,11 +449,18 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
hasMoreMessages = entities.size >= PAGE_SIZE
|
||||
currentOffset = entities.size
|
||||
|
||||
// 🔥 Расшифровка сообщений при загрузке (как в архиве)
|
||||
// 🔥 ЧАНКОВАЯ расшифровка - по DECRYPT_CHUNK_SIZE сообщений с yield между ними
|
||||
// Это предотвращает блокировку UI thread
|
||||
val messages = ArrayList<ChatMessage>(entities.size)
|
||||
for (entity in entities.asReversed()) {
|
||||
val reversedEntities = entities.asReversed()
|
||||
for ((index, entity) in reversedEntities.withIndex()) {
|
||||
val chatMsg = entityToChatMessage(entity)
|
||||
messages.add(chatMsg)
|
||||
|
||||
// Каждые DECRYPT_CHUNK_SIZE сообщений даём UI thread "подышать"
|
||||
if ((index + 1) % DECRYPT_CHUNK_SIZE == 0) {
|
||||
yield() // Позволяем другим корутинам выполниться
|
||||
}
|
||||
}
|
||||
|
||||
ProtocolManager.addLog("📋 Decrypted and loaded ${messages.size} messages from DB")
|
||||
|
||||
Reference in New Issue
Block a user