diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index 7ada27d000..89c6f40cfe 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -894,8 +894,27 @@ object ChatController { private suspend fun processSendMessageCmd(rh: Long?, cmd: CC): List? { val r = sendCmd(rh, cmd) - return when (r) { - is CR.NewChatItems -> r.chatItems + return when { + r is CR.NewChatItems -> r.chatItems + r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorStore && r.chatError.storeError is StoreError.LargeMsg && cmd is CC.ApiSendMessages -> { + val mc = cmd.composedMessages.last().msgContent + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.maximum_message_size_title), + if (mc is MsgContent.MCImage || mc is MsgContent.MCVideo || mc is MsgContent.MCLink) { + generalGetString(MR.strings.maximum_message_size_reached_non_text) + } else { + generalGetString(MR.strings.maximum_message_size_reached_text) + } + ) + null + } + r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorStore && r.chatError.storeError is StoreError.LargeMsg && cmd is CC.ApiForwardChatItems -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.maximum_message_size_title), + generalGetString(MR.strings.maximum_message_size_reached_forwarding) + ) + null + } else -> { if (!(networkErrorAlert(r))) { apiErrorAlert("processSendMessageCmd", generalGetString(MR.strings.error_sending_message), r) @@ -943,7 +962,21 @@ object ChatController { suspend fun apiUpdateChatItem(rh: Long?, type: ChatType, id: Long, itemId: Long, mc: MsgContent, live: Boolean = false): AChatItem? { val r = sendCmd(rh, CC.ApiUpdateChatItem(type, id, itemId, mc, live)) - if (r is CR.ChatItemUpdated) return r.chatItem + when { + r is CR.ChatItemUpdated -> return r.chatItem + r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorStore && r.chatError.storeError is StoreError.LargeMsg -> { + AlertManager.shared.showAlertMsg( + generalGetString(MR.strings.maximum_message_size_title), + if (mc is MsgContent.MCImage || mc is MsgContent.MCVideo || mc is MsgContent.MCLink) { + generalGetString(MR.strings.maximum_message_size_reached_non_text) + } else { + generalGetString(MR.strings.maximum_message_size_reached_text) + } + ) + return null + } + } + Log.e(TAG, "apiUpdateChatItem bad response: ${r.responseType} ${r.details}") return null } @@ -6357,6 +6390,7 @@ sealed class StoreError { is HostMemberIdNotFound -> "hostMemberIdNotFound" is ContactNotFoundByFileId -> "contactNotFoundByFileId" is NoGroupSndStatus -> "noGroupSndStatus" + is LargeMsg -> "largeMsg" } @Serializable @SerialName("duplicateName") object DuplicateName: StoreError() @@ -6416,6 +6450,7 @@ sealed class StoreError { @Serializable @SerialName("hostMemberIdNotFound") class HostMemberIdNotFound(val groupId: Long): StoreError() @Serializable @SerialName("contactNotFoundByFileId") class ContactNotFoundByFileId(val fileId: Long): StoreError() @Serializable @SerialName("noGroupSndStatus") class NoGroupSndStatus(val itemId: Long, val groupMemberId: Long): StoreError() + @Serializable @SerialName("largeMsg") object LargeMsg: StoreError() } @Serializable diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt index 6cd46d49a6..3a63cf508e 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt @@ -412,6 +412,7 @@ fun ComposeView( val cInfo = chat.chatInfo val cs = composeState.value var sent: List? + var lastMessageFailedToSend: ComposeState? = null val msgText = text ?: cs.message fun sending() { @@ -461,6 +462,19 @@ fun ComposeView( } } + fun constructFailedMessage(cs: ComposeState): ComposeState { + val preview = when (cs.preview) { + is ComposePreview.MediaPreview -> { + ComposePreview.MediaPreview( + if (cs.preview.images.isNotEmpty()) listOf(cs.preview.images.last()) else emptyList(), + if (cs.preview.content.isNotEmpty()) listOf(cs.preview.content.last()) else emptyList() + ) + } + else -> cs.preview + } + return cs.copy(inProgress = false, preview = preview) + } + fun updateMsgContent(msgContent: MsgContent): MsgContent { return when (msgContent) { is MsgContent.MCText -> checkLinkPreview() @@ -517,6 +531,9 @@ fun ComposeView( sent = null } else if (cs.contextItem is ComposeContextItem.ForwardingItems) { sent = forwardItem(chat.remoteHostId, cs.contextItem.chatItems, cs.contextItem.fromChatInfo, ttl = ttl) + if (sent == null) { + lastMessageFailedToSend = constructFailedMessage(cs) + } if (cs.message.isNotEmpty()) { sent?.mapIndexed { index, message -> if (index == sent!!.lastIndex) { @@ -531,6 +548,7 @@ fun ComposeView( val ei = cs.contextItem.chatItem val updatedMessage = updateMessage(ei, chat, live) sent = if (updatedMessage != null) listOf(updatedMessage) else null + lastMessageFailedToSend = if (updatedMessage == null) constructFailedMessage(cs) else null } else if (liveMessage != null && liveMessage.sent) { val updatedMessage = updateMessage(liveMessage.chatItem, chat, live) sent = if (updatedMessage != null) listOf(updatedMessage) else null @@ -631,19 +649,21 @@ fun ComposeView( ttl = ttl ) sent = if (sendResult != null) listOf(sendResult) else null - } - if (sent == null && - (cs.preview is ComposePreview.MediaPreview || - cs.preview is ComposePreview.FilePreview || - cs.preview is ComposePreview.VoicePreview) - ) { - val sendResult = send(chat, MsgContent.MCText(msgText), quotedItemId, null, live, ttl) - sent = if (sendResult != null) listOf(sendResult) else null + if (sent == null && index == msgs.lastIndex && cs.liveMessage == null) { + constructFailedMessage(cs) + // it's the last message in the series so if it fails, restore it in ComposeView for editing + lastMessageFailedToSend = constructFailedMessage(cs) + } } } val wasForwarding = cs.forwarding val forwardingFromChatId = (cs.contextItem as? ComposeContextItem.ForwardingItems)?.fromChatInfo?.id - clearState(live) + val lastFailed = lastMessageFailedToSend + if (lastFailed == null) { + clearState(live) + } else { + composeState.value = lastFailed + } val draft = chatModel.draft.value if (wasForwarding && chatModel.draftChatId.value == chat.chatInfo.id && forwardingFromChatId != chat.chatInfo.id && draft != null) { composeState.value = draft diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index c390096ee2..d931abab70 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -441,6 +441,10 @@ Files and media not allowed Voice messages not allowed Message + Message is too large! + Please reduce the message size and send again. + Please reduce the message size or remove media and send again. + You can copy and reduce the message size to send it. Image