diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a38d866..a55b7f4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,7 +9,8 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" - android:theme="@style/Theme.FromChat"> + android:theme="@style/Theme.FromChat" + android:usesCleartextTraffic="true"> Unit)? = null return try { + // Check if we have a valid session before sending + if (session == null) { + Log.w("WebSocketManager", "No active WebSocket session") + return null + } + send(message) withTimeout(timeoutMs) { suspendCoroutine { continuation -> - handler = { - continuation.resumeWith(Result.success(it)) - removeGlobalMessageHandler(handler!!) + handler = { response -> + // Only process responses that match our request type + if (response.type == message.type) { + continuation.resumeWith(Result.success(response)) + removeGlobalMessageHandler(handler!!) + } } addGlobalMessageHandler(handler) } @@ -114,6 +132,9 @@ object WebSocketManager { } catch (_: TimeoutCancellationException) { Log.w("WebSocketManager", "Request timed out") null + } catch (e: Exception) { + Log.e("WebSocketManager", "Request failed", e) + null } finally { handler?.let { removeGlobalMessageHandler(it) } } diff --git a/app/src/main/java/ru/fromchat/ui/PublicChatScreen.kt b/app/src/main/java/ru/fromchat/ui/PublicChatScreen.kt index 75db957..11e3796 100644 --- a/app/src/main/java/ru/fromchat/ui/PublicChatScreen.kt +++ b/app/src/main/java/ru/fromchat/ui/PublicChatScreen.kt @@ -67,7 +67,6 @@ import kotlinx.coroutines.launch import kotlinx.datetime.TimeZone import kotlinx.datetime.format import kotlinx.datetime.toLocalDateTime -import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromJsonElement import kotlinx.serialization.json.encodeToJsonElement import ru.fromchat.DATETIME_FORMAT @@ -75,7 +74,6 @@ import ru.fromchat.R import ru.fromchat.api.ApiClient import ru.fromchat.api.Message import ru.fromchat.api.SendMessageRequest -import ru.fromchat.api.SendMessageResponse import ru.fromchat.api.WebSocketCredentials import ru.fromchat.api.WebSocketManager import ru.fromchat.api.WebSocketMessage @@ -116,8 +114,12 @@ fun PublicChatScreen() { scope.launch { if (msg.type == "newMessage") { try { - messages += Json.decodeFromJsonElement(msg.data!!) - scrollDown() + val newMessage = ApiClient.json.decodeFromJsonElement(msg.data!!) + // Check if message already exists to prevent duplicates + if (messages.none { it.id == newMessage.id }) { + messages += newMessage + scrollDown() + } } catch (e: Exception) { Log.e("PublicChatScreen", "Failed to process incoming message:", e) } @@ -188,29 +190,36 @@ fun PublicChatScreen() { IconButton( onClick = { scope.launch { - runCatching { - Json.decodeFromJsonElement( - WebSocketManager.request( - WebSocketMessage( - type = "sendMessage", - credentials = WebSocketCredentials( - scheme = "Bearer", - credentials = ApiClient.token!! - ), - data = Json.encodeToJsonElement( - SendMessageRequest( - content = "${message.text}" - ) + val messageText = "${message.text.trim()}" + if (messageText.isEmpty()) return@launch + + try { + val response = WebSocketManager.request( + WebSocketMessage( + type = "sendMessage", + credentials = WebSocketCredentials( + scheme = "Bearer", + credentials = ApiClient.token!! + ), + data = ApiClient.json.encodeToJsonElement( + SendMessageRequest( + content = messageText ) ) - )!!.data!! + ) ) - }.getOrNull()?.let { - messages += it.message - scrollDown() + + if (response != null && response.error == null) { + message.setTextAndPlaceCursorAtEnd("") + Log.d("PublicChatScreen", "Message sent successfully") + // Message will be added to the list via WebSocket "newMessage" event + } else { + Log.e("PublicChatScreen", "WebSocket error: ${response?.error}") + } + } catch (e: Exception) { + Log.e("PublicChatScreen", "Failed to send message", e) + // Could show a toast or error message to user here } - - message.setTextAndPlaceCursorAtEnd("") } } ) {