diff --git a/app/src/main/java/com/rosetta/messenger/network/Packets.kt b/app/src/main/java/com/rosetta/messenger/network/Packets.kt index b2a5e1f..c1022a8 100644 --- a/app/src/main/java/com/rosetta/messenger/network/Packets.kt +++ b/app/src/main/java/com/rosetta/messenger/network/Packets.kt @@ -77,13 +77,14 @@ class PacketSearch : Packet() { override fun receive(stream: Stream) { privateKey = stream.readString() search = stream.readString() - val userCount = stream.readInt32() + val userCount = stream.readInt16() // Int16, not Int32! val usersList = mutableListOf() for (i in 0 until userCount) { + // Order: username, title, publicKey, verified, online (matching React Native) val user = SearchUser( - publicKey = stream.readString(), - title = stream.readString(), username = stream.readString(), + title = stream.readString(), + publicKey = stream.readString(), verified = stream.readInt8(), online = stream.readInt8() ) diff --git a/app/src/main/java/com/rosetta/messenger/network/Protocol.kt b/app/src/main/java/com/rosetta/messenger/network/Protocol.kt index e369f34..bfae0a3 100644 --- a/app/src/main/java/com/rosetta/messenger/network/Protocol.kt +++ b/app/src/main/java/com/rosetta/messenger/network/Protocol.kt @@ -135,11 +135,11 @@ class Protocol( } override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { - log("WebSocket closing: $code - $reason") + log("⚠️ WebSocket closing: $code - $reason") } override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { - log("WebSocket closed: $code - $reason") + log("❌ WebSocket closed: $code - $reason") handleDisconnect() } @@ -210,6 +210,10 @@ class Protocol( log("📤 Sending packet: ${packet.getPacketId()} (${data.size} bytes)") + // Debug: log first 50 bytes as hex + val hexDump = data.take(50).joinToString(" ") { String.format("%02X", it) } + log(" Hex: $hexDump${if (data.size > 50) "..." else ""}") + webSocket?.send(ByteString.of(*data)) } @@ -222,10 +226,14 @@ class Protocol( private fun handleMessage(data: ByteArray) { try { + // Debug: log first 50 bytes as hex + val hexDump = data.take(50).joinToString(" ") { String.format("%02X", it.toInt() and 0xFF) } + log("📥 Received ${data.size} bytes: $hexDump${if (data.size > 50) "..." else ""}") + val stream = Stream(data) val packetId = stream.readInt16() - log("📥 Received packet: $packetId") + log("📥 Packet ID: $packetId") val packetFactory = supportedPackets[packetId] if (packetFactory == null) { @@ -246,6 +254,7 @@ class Protocol( } } catch (e: Exception) { log("❌ Error parsing packet: ${e.message}") + e.printStackTrace() } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt index 9f53c4b..b8f89de 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListScreen.kt @@ -757,8 +757,8 @@ fun ChatsListScreen( .fillMaxSize() .padding(paddingValues) ) { - // Show search results when search is expanded and has query - if (isSearchExpanded && searchQuery.isNotEmpty()) { + // Show search results when search is expanded + if (isSearchExpanded) { Column(modifier = Modifier.fillMaxSize()) { // Search Results List SearchResultsList( @@ -767,6 +767,9 @@ fun ChatsListScreen( currentUserPublicKey = accountPublicKey, isDarkTheme = isDarkTheme, onUserClick = { user -> + // Логируем выбор пользователя + ProtocolManager.addLog("🎯 User selected: ${user.title.ifEmpty { user.publicKey.take(10) }}") + ProtocolManager.addLog(" PublicKey: ${user.publicKey.take(20)}...") // Закрываем поиск и вызываем callback searchViewModel.collapseSearch() onUserSelect(user) @@ -774,41 +777,42 @@ fun ChatsListScreen( ) } } else { - // Console button - hidden for now - AnimatedVisibility( - visible = false, - enter = fadeIn(tween(500, delayMillis = 400)) + slideInHorizontally( - initialOffsetX = { -it }, - animationSpec = tween(500, delayMillis = 400) - ), - modifier = Modifier - .align(Alignment.BottomStart) - .padding(16.dp) - ) { - FloatingActionButton( - onClick = { showDevConsole = true }, - containerColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFF5F5F5), - contentColor = if (protocolState == ProtocolState.AUTHENTICATED) - Color(0xFF4CAF50) - else - Color(0xFFFF9800), - shape = CircleShape, - modifier = Modifier.size(48.dp) - ) { - Icon( - Icons.Default.Terminal, - contentDescription = "Dev Console", - modifier = Modifier.size(24.dp) - ) - } - } - // Empty state with Lottie animation EmptyChatsState( isDarkTheme = isDarkTheme, modifier = Modifier.fillMaxSize() ) } + + // Console button - always visible at bottom left + AnimatedVisibility( + visible = visible, + enter = fadeIn(tween(500, delayMillis = 400)) + slideInHorizontally( + initialOffsetX = { -it }, + animationSpec = tween(500, delayMillis = 400) + ), + modifier = Modifier + .align(Alignment.BottomStart) + .padding(16.dp) + ) { + FloatingActionButton( + onClick = { showDevConsole = true }, + containerColor = if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFF5F5F5), + contentColor = when (protocolState) { + ProtocolState.AUTHENTICATED -> Color(0xFF4CAF50) + ProtocolState.CONNECTING, ProtocolState.HANDSHAKING -> Color(0xFFFFA726) + else -> Color(0xFFFF5722) + }, + shape = CircleShape, + modifier = Modifier.size(48.dp) + ) { + Icon( + Icons.Default.Terminal, + contentDescription = "Dev Console", + modifier = Modifier.size(24.dp) + ) + } + } } } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/SearchUsersViewModel.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/SearchUsersViewModel.kt index 6148910..a948466 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/SearchUsersViewModel.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/SearchUsersViewModel.kt @@ -40,7 +40,13 @@ class SearchUsersViewModel : ViewModel() { // Callback для обработки ответа поиска private val searchPacketHandler: (com.rosetta.messenger.network.Packet) -> Unit = { packet -> if (packet is PacketSearch) { - android.util.Log.d("SearchUsersVM", "📥 Search results received: ${packet.users.size} users") + ProtocolManager.addLog("📥 Search response received") + ProtocolManager.addLog(" Users found: ${packet.users.size}") + packet.users.forEachIndexed { index, user -> + ProtocolManager.addLog(" [$index] ${user.title.ifEmpty { "No title" }} (@${user.username.ifEmpty { "no username" }})") + ProtocolManager.addLog(" Key: ${user.publicKey.take(20)}...") + ProtocolManager.addLog(" Verified: ${user.verified}, Online: ${user.online}") + } _searchResults.value = packet.users _isSearching.value = false } @@ -97,7 +103,7 @@ class SearchUsersViewModel : ViewModel() { // Проверяем состояние протокола if (ProtocolManager.state.value != ProtocolState.AUTHENTICATED) { - android.util.Log.w("SearchUsersVM", "Not authenticated, cannot search") + ProtocolManager.addLog("⚠️ Search failed: Not authenticated") _isSearching.value = false return@launch } @@ -109,7 +115,8 @@ class SearchUsersViewModel : ViewModel() { lastSearchedText = query - android.util.Log.d("SearchUsersVM", "🔍 Sending search request: $query") + ProtocolManager.addLog("🔍 Searching for: \"$query\"") + ProtocolManager.addLog(" PrivateKeyHash: ${privateKeyHash.take(20)}...") // Создаем и отправляем пакет поиска val packetSearch = PacketSearch().apply { @@ -125,6 +132,7 @@ class SearchUsersViewModel : ViewModel() { * Открыть панель поиска */ fun expandSearch() { + ProtocolManager.addLog("🔎 Search panel opened") _isSearchExpanded.value = true } @@ -132,6 +140,7 @@ class SearchUsersViewModel : ViewModel() { * Закрыть панель поиска и очистить результаты */ fun collapseSearch() { + ProtocolManager.addLog("🔎 Search panel closed") _isSearchExpanded.value = false _searchQuery.value = "" _searchResults.value = emptyList()