fix: add detailed logging for unlock process to improve debugging and performance tracking
This commit is contained in:
@@ -294,7 +294,8 @@ fun ChatDetailScreen(
|
||||
val isOnline by viewModel.opponentOnline.collectAsState()
|
||||
val isLoading by viewModel.isLoading.collectAsState() // 🔥 Для скелетона
|
||||
|
||||
// 🔥 Reply/Forward state
|
||||
|
||||
// <20>🔥 Reply/Forward state
|
||||
val replyMessages by viewModel.replyMessages.collectAsState()
|
||||
val hasReply = replyMessages.isNotEmpty()
|
||||
val isForwardMode by viewModel.isForwardMode.collectAsState()
|
||||
|
||||
@@ -251,12 +251,21 @@ fun ChatsListScreen(
|
||||
// Load dialogs when account is available
|
||||
LaunchedEffect(accountPublicKey, accountPrivateKey) {
|
||||
if (accountPublicKey.isNotEmpty() && accountPrivateKey.isNotEmpty()) {
|
||||
val launchStart = System.currentTimeMillis()
|
||||
android.util.Log.d("ChatsListScreen", "🚀 LaunchedEffect started")
|
||||
|
||||
chatsViewModel.setAccount(accountPublicKey, accountPrivateKey)
|
||||
android.util.Log.d("ChatsListScreen", "📋 setAccount took ${System.currentTimeMillis() - launchStart}ms")
|
||||
|
||||
// Устанавливаем аккаунт для RecentSearchesManager
|
||||
RecentSearchesManager.setAccount(accountPublicKey)
|
||||
|
||||
// 🔥 КРИТИЧНО: Инициализируем MessageRepository для обработки входящих
|
||||
// сообщений
|
||||
val initStart = System.currentTimeMillis()
|
||||
ProtocolManager.initializeAccount(accountPublicKey, accountPrivateKey)
|
||||
android.util.Log.d("ChatsListScreen", "🌐 initializeAccount took ${System.currentTimeMillis() - initStart}ms")
|
||||
android.util.Log.d("ChatsListScreen", "✅ Total LaunchedEffect: ${System.currentTimeMillis() - launchStart}ms")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,11 +105,17 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
|
||||
private val _isLoading = MutableStateFlow(false)
|
||||
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
|
||||
|
||||
private val TAG = "ChatsListVM"
|
||||
|
||||
/**
|
||||
* Установить текущий аккаунт и загрузить диалоги
|
||||
*/
|
||||
fun setAccount(publicKey: String, privateKey: String) {
|
||||
val setAccountStart = System.currentTimeMillis()
|
||||
android.util.Log.d(TAG, "📋 setAccount called for: ${publicKey.take(8)}...")
|
||||
|
||||
if (currentAccount == publicKey) {
|
||||
android.util.Log.d(TAG, "📋 Account already set, skipping")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -119,11 +125,15 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
|
||||
currentAccount = publicKey
|
||||
currentPrivateKey = privateKey
|
||||
|
||||
android.util.Log.d(TAG, "📋 Starting dialogs subscription...")
|
||||
|
||||
// Подписываемся на обычные диалоги
|
||||
viewModelScope.launch {
|
||||
dialogDao.getDialogsFlow(publicKey)
|
||||
.flowOn(Dispatchers.IO) // 🚀 Flow работает на IO
|
||||
.map { dialogsList ->
|
||||
val mapStart = System.currentTimeMillis()
|
||||
android.util.Log.d(TAG, "🔄 Processing ${dialogsList.size} dialogs...")
|
||||
// <20> ОПТИМИЗАЦИЯ: Параллельная расшифровка всех сообщений
|
||||
withContext(Dispatchers.Default) {
|
||||
dialogsList.map { dialog ->
|
||||
@@ -194,10 +204,14 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
|
||||
)
|
||||
}
|
||||
}.awaitAll()
|
||||
}.also {
|
||||
val mapTime = System.currentTimeMillis() - mapStart
|
||||
android.util.Log.d(TAG, "🔄 Dialogs processed in ${mapTime}ms (${dialogsList.size} items)")
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged() // 🔥 ИСПРАВЛЕНИЕ: Игнорируем дублирующиеся списки
|
||||
.collect { decryptedDialogs ->
|
||||
android.util.Log.d(TAG, "✅ Dialogs collected: ${decryptedDialogs.size} items")
|
||||
_dialogs.value = decryptedDialogs
|
||||
|
||||
// 🟢 Подписываемся на онлайн-статусы всех собеседников
|
||||
|
||||
@@ -704,43 +704,43 @@ fun MessageBubble(
|
||||
}
|
||||
)
|
||||
} else if (!hasOnlyMedia && !hasImageWithCaption && message.text.isNotEmpty()) {
|
||||
// Telegram-style: текст + время с автоматическим переносом
|
||||
TelegramStyleMessageContent(
|
||||
textContent = {
|
||||
AppleEmojiText(
|
||||
text = message.text,
|
||||
color = textColor,
|
||||
fontSize = 17.sp,
|
||||
linkColor = linkColor
|
||||
)
|
||||
},
|
||||
timeContent = {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
Text(
|
||||
text = timeFormat.format(message.timestamp),
|
||||
color = timeColor,
|
||||
fontSize = 11.sp,
|
||||
fontStyle =
|
||||
androidx.compose.ui.text.font.FontStyle.Italic
|
||||
// Telegram-style: текст + время с автоматическим переносом
|
||||
TelegramStyleMessageContent(
|
||||
textContent = {
|
||||
AppleEmojiText(
|
||||
text = message.text,
|
||||
color = textColor,
|
||||
fontSize = 17.sp,
|
||||
linkColor = linkColor
|
||||
)
|
||||
if (message.isOutgoing) {
|
||||
val displayStatus =
|
||||
if (isSavedMessages) MessageStatus.READ
|
||||
else message.status
|
||||
AnimatedMessageStatus(
|
||||
status = displayStatus,
|
||||
timeColor = timeColor,
|
||||
timestamp = message.timestamp.time,
|
||||
onRetry = onRetry,
|
||||
onDelete = onDelete
|
||||
},
|
||||
timeContent = {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
Text(
|
||||
text = timeFormat.format(message.timestamp),
|
||||
color = timeColor,
|
||||
fontSize = 11.sp,
|
||||
fontStyle =
|
||||
androidx.compose.ui.text.font.FontStyle.Italic
|
||||
)
|
||||
if (message.isOutgoing) {
|
||||
val displayStatus =
|
||||
if (isSavedMessages) MessageStatus.READ
|
||||
else message.status
|
||||
AnimatedMessageStatus(
|
||||
status = displayStatus,
|
||||
timeColor = timeColor,
|
||||
timestamp = message.timestamp.time,
|
||||
onRetry = onRetry,
|
||||
onDelete = onDelete
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,15 @@ fun MediaPickerBottomSheet(
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val density = LocalDensity.current
|
||||
val focusManager = LocalFocusManager.current
|
||||
val keyboardView = LocalView.current
|
||||
|
||||
// Function to hide keyboard
|
||||
fun hideKeyboard() {
|
||||
focusManager.clearFocus()
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(keyboardView.windowToken, 0)
|
||||
}
|
||||
|
||||
// Media items from gallery
|
||||
var mediaItems by remember { mutableStateOf<List<MediaItem>>(emptyList()) }
|
||||
@@ -496,6 +505,7 @@ fun MediaPickerBottomSheet(
|
||||
QuickActionsRow(
|
||||
isDarkTheme = isDarkTheme,
|
||||
onCameraClick = {
|
||||
hideKeyboard()
|
||||
animatedClose()
|
||||
onOpenCamera()
|
||||
},
|
||||
@@ -578,6 +588,7 @@ fun MediaPickerBottomSheet(
|
||||
mediaItems = mediaItems,
|
||||
selectedItems = selectedItems,
|
||||
onCameraClick = {
|
||||
hideKeyboard()
|
||||
animatedClose()
|
||||
onOpenCamera()
|
||||
},
|
||||
@@ -1222,11 +1233,11 @@ private fun MediaGridItem(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (isSelected) {
|
||||
Text(
|
||||
text = "$selectionIndex",
|
||||
color = Color.White,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
Icon(
|
||||
imageVector = TablerIcons.Check,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import compose.icons.TablerIcons
|
||||
import compose.icons.tablericons.*
|
||||
@@ -16,9 +17,11 @@ import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
@@ -30,6 +33,8 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import app.rosette.android.ui.keyboard.AnimatedKeyboardTransition
|
||||
import app.rosette.android.ui.keyboard.KeyboardTransitionCoordinator
|
||||
import coil.compose.AsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.rosetta.messenger.network.AttachmentType
|
||||
import com.rosetta.messenger.ui.components.AppleEmojiTextField
|
||||
import com.rosetta.messenger.ui.components.OptimizedEmojiPicker
|
||||
@@ -48,6 +53,7 @@ import kotlinx.coroutines.launch
|
||||
* Telegram UX rules:
|
||||
* 1. Input always linked to keyboard (imePadding)
|
||||
* 2. Last message always visible
|
||||
|
||||
* 3. No layout jumps
|
||||
* 4. After sending: input clears, keyboard stays open
|
||||
* 5. Input grows upward for multi-line (up to 6 lines)
|
||||
|
||||
Reference in New Issue
Block a user