add retry logic for sending messages, hide resend button when offline

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2025-01-02 12:41:51 +01:00
parent 2c397ad517
commit 06c8509587
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
2 changed files with 30 additions and 32 deletions

View File

@ -43,7 +43,9 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.retryWhen
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.IOException
import javax.inject.Inject import javax.inject.Inject
class OfflineFirstChatRepository @Inject constructor( class OfflineFirstChatRepository @Inject constructor(
@ -181,7 +183,6 @@ class OfflineFirstChatRepository @Inject constructor(
if (newestMessageIdFromDb.toInt() != 0) { if (newestMessageIdFromDb.toInt() != 0) {
val limit = getCappedMessagesAmountOfChatBlock(newestMessageIdFromDb) val limit = getCappedMessagesAmountOfChatBlock(newestMessageIdFromDb)
val list = getMessagesBeforeAndEqual( val list = getMessagesBeforeAndEqual(
newestMessageIdFromDb, newestMessageIdFromDb,
internalConversationId, internalConversationId,
@ -340,7 +341,7 @@ class OfflineFirstChatRepository @Inject constructor(
} }
private suspend fun handleNewAndTempMessages( private suspend fun handleNewAndTempMessages(
receivedChatMessages : List<ChatMessage>, receivedChatMessages: List<ChatMessage>,
lookIntoFuture: Boolean, lookIntoFuture: Boolean,
showUnreadMessagesMarker: Boolean showUnreadMessagesMarker: Boolean
) { ) {
@ -752,7 +753,6 @@ class OfflineFirstChatRepository @Inject constructor(
it.map(ChatMessageEntity::asModel) it.map(ChatMessageEntity::asModel)
}.first() }.first()
private suspend fun showMessagesBefore(internalConversationId: String, messageId: Long, limit: Int) { private suspend fun showMessagesBefore(internalConversationId: String, messageId: Long, limit: Int) {
suspend fun getMessagesBefore( suspend fun getMessagesBefore(
messageId: Long, messageId: Long,
@ -819,29 +819,29 @@ class OfflineFirstChatRepository @Inject constructor(
emit(Result.success(chatMessageModel)) emit(Result.success(chatMessageModel))
} }
// .retryWhen { cause, attempt -> .retryWhen { cause, attempt ->
// if (cause is IOException && attempt < 3) { if (cause is IOException && attempt < SEND_MESSAGE_RETRY_ATTEMPTS) {
// delay(2000) delay(SEND_MESSAGE_RETRY_DELAY)
// return@retryWhen true return@retryWhen true
// } else { } else {
// return@retryWhen false return@retryWhen false
// } }
// } }
.catch { e -> .catch { e ->
Log.e(TAG, "Error when sending message", e) Log.e(TAG, "Error when sending message", e)
val failedMessage = chatDao.getTempMessageForConversation(internalConversationId, referenceId).first() val failedMessage = chatDao.getTempMessageForConversation(internalConversationId, referenceId).first()
failedMessage.sendingFailed = true failedMessage.sendingFailed = true
chatDao.updateChatMessage(failedMessage) chatDao.updateChatMessage(failedMessage)
val failedMessageModel = failedMessage.asModel() val failedMessageModel = failedMessage.asModel()
_removeMessageFlow.emit(failedMessageModel) _removeMessageFlow.emit(failedMessageModel)
val tripleChatMessages = Triple(true, false, listOf(failedMessageModel)) val tripleChatMessages = Triple(true, false, listOf(failedMessageModel))
_messageFlow.emit(tripleChatMessages) _messageFlow.emit(tripleChatMessages)
emit(Result.failure(e)) emit(Result.failure(e))
} }
override suspend fun resendChatMessage( override suspend fun resendChatMessage(
credentials: String, credentials: String,
@ -873,7 +873,6 @@ class OfflineFirstChatRepository @Inject constructor(
) )
} }
override suspend fun editChatMessage( override suspend fun editChatMessage(
credentials: String, credentials: String,
url: String, url: String,
@ -897,12 +896,13 @@ class OfflineFirstChatRepository @Inject constructor(
): Flow<Boolean> = ): Flow<Boolean> =
flow { flow {
try { try {
val messageToEdit = chatDao.getChatMessageForConversation(internalConversationId, message.jsonMessageId val messageToEdit = chatDao.getChatMessageForConversation(
.toLong()).first() internalConversationId, message.jsonMessageId
.toLong()
).first()
messageToEdit.message = editedMessageText messageToEdit.message = editedMessageText
chatDao.upsertChatMessage(messageToEdit) chatDao.upsertChatMessage(messageToEdit)
val editedMessageModel = messageToEdit.asModel() val editedMessageModel = messageToEdit.asModel()
_removeMessageFlow.emit(editedMessageModel) _removeMessageFlow.emit(editedMessageModel)
@ -938,7 +938,6 @@ class OfflineFirstChatRepository @Inject constructor(
} }
} }
} }
} }
override suspend fun deleteTempMessage(chatMessage: ChatMessage) { override suspend fun deleteTempMessage(chatMessage: ChatMessage) {
@ -1018,5 +1017,7 @@ class OfflineFirstChatRepository @Inject constructor(
private const val DELAY_TO_ENSURE_MESSAGES_ARE_ADDED: Long = 100 private const val DELAY_TO_ENSURE_MESSAGES_ARE_ADDED: Long = 100
private const val DEFAULT_MESSAGES_LIMIT = 100 private const val DEFAULT_MESSAGES_LIMIT = 100
private const val MILLIES = 1000 private const val MILLIES = 1000
private const val SEND_MESSAGE_RETRY_ATTEMPTS = 3
private const val SEND_MESSAGE_RETRY_DELAY: Long = 2000
} }
} }

View File

@ -20,12 +20,12 @@ import com.nextcloud.talk.chat.ChatActivity
import com.nextcloud.talk.chat.data.model.ChatMessage import com.nextcloud.talk.chat.data.model.ChatMessage
import com.nextcloud.talk.data.network.NetworkMonitor import com.nextcloud.talk.data.network.NetworkMonitor
import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.DialogMessageActionsBinding
import com.nextcloud.talk.databinding.DialogTempMessageActionsBinding import com.nextcloud.talk.databinding.DialogTempMessageActionsBinding
import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.domain.ConversationModel
import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DateUtils import com.nextcloud.talk.utils.DateUtils
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@ -68,7 +68,7 @@ class TempMessageActionsDialog(
private fun initMenuItems() { private fun initMenuItems() {
this.lifecycleScope.launch { this.lifecycleScope.launch {
initResendMessage(true) initResendMessage(networkMonitor.isOnline.first())
initMenuEditMessage(true) initMenuEditMessage(true)
initMenuDeleteMessage(true) initMenuDeleteMessage(true)
} }
@ -84,8 +84,6 @@ class TempMessageActionsDialog(
private fun initResendMessage(visible: Boolean) { private fun initResendMessage(visible: Boolean) {
if (visible) { if (visible) {
binding.menuResendMessage.setOnClickListener { binding.menuResendMessage.setOnClickListener {
chatActivity.chatViewModel.resendMessage( chatActivity.chatViewModel.resendMessage(
chatActivity.conversationUser!!.getCredentials(), chatActivity.conversationUser!!.getCredentials(),
ApiUtils.getUrlForChat( ApiUtils.getUrlForChat(
@ -95,7 +93,6 @@ class TempMessageActionsDialog(
), ),
message message
) )
dismiss() dismiss()
} }
} }