mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 19:49:33 +01:00
show x when sending failed
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
a78c9e1c08
commit
e1c1574d6c
@ -114,7 +114,19 @@ class OutcomingTextMessageViewHolder(itemView: View) :
|
|||||||
binding.messageQuote.quotedChatMessageView.visibility = View.GONE
|
binding.messageQuote.quotedChatMessageView.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
setReadStatus(message.readStatus)
|
|
||||||
|
when (message.readStatus) {
|
||||||
|
ReadStatus.READ -> updateReadStatus(R.drawable.ic_check_all, context.resources?.getString(R.string.nc_message_read))
|
||||||
|
ReadStatus.SENT -> updateReadStatus(R.drawable.ic_check, context.resources?.getString(R.string.nc_message_sent))
|
||||||
|
ReadStatus.SENDING -> updateSendingStatus()
|
||||||
|
ReadStatus.FAILED -> updateReadStatus(
|
||||||
|
R.drawable.ic_baseline_close_24,
|
||||||
|
"failed"
|
||||||
|
)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
itemView.setTag(R.string.replyable_message_view_tag, message.replyable)
|
itemView.setTag(R.string.replyable_message_view_tag, message.replyable)
|
||||||
|
|
||||||
@ -129,29 +141,27 @@ class OutcomingTextMessageViewHolder(itemView: View) :
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setReadStatus(readStatus: Enum<ReadStatus>) {
|
private fun updateReadStatus(readStatusDrawableInt: Int, description: String?) {
|
||||||
val readStatusDrawableInt = when (readStatus) {
|
binding.sendingProgress.visibility = View.GONE
|
||||||
ReadStatus.READ -> R.drawable.ic_check_all
|
binding.checkMark.visibility = View.VISIBLE
|
||||||
ReadStatus.SENT -> R.drawable.ic_check
|
readStatusDrawableInt.let { drawableInt ->
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
val readStatusContentDescriptionString = when (readStatus) {
|
|
||||||
ReadStatus.READ -> context.resources?.getString(R.string.nc_message_read)
|
|
||||||
ReadStatus.SENT -> context.resources?.getString(R.string.nc_message_sent)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
readStatusDrawableInt?.let { drawableInt ->
|
|
||||||
ResourcesCompat.getDrawable(context.resources, drawableInt, null)?.let {
|
ResourcesCompat.getDrawable(context.resources, drawableInt, null)?.let {
|
||||||
binding.checkMark.setImageDrawable(it)
|
binding.checkMark.setImageDrawable(it)
|
||||||
viewThemeUtils.talk.themeMessageCheckMark(binding.checkMark)
|
viewThemeUtils.talk.themeMessageCheckMark(binding.checkMark)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
binding.checkMark.contentDescription = description
|
||||||
binding.checkMark.contentDescription = readStatusContentDescriptionString
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateSendingStatus() {
|
||||||
|
binding.sendingProgress.visibility = View.VISIBLE
|
||||||
|
binding.checkMark.visibility = View.GONE
|
||||||
|
|
||||||
|
viewThemeUtils.material.colorProgressBar(binding.sendingProgress)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun longClickOnReaction(chatMessage: ChatMessage) {
|
private fun longClickOnReaction(chatMessage: ChatMessage) {
|
||||||
commonMessageInterface.onLongClickReactions(chatMessage)
|
commonMessageInterface.onLongClickReactions(chatMessage)
|
||||||
}
|
}
|
||||||
|
@ -587,7 +587,7 @@ class ChatActivity :
|
|||||||
list.forEachIndexed { _, qMsg ->
|
list.forEachIndexed { _, qMsg ->
|
||||||
val temporaryChatMessage = ChatMessage()
|
val temporaryChatMessage = ChatMessage()
|
||||||
temporaryChatMessage.jsonMessageId = TEMPORARY_MESSAGE_ID_INT
|
temporaryChatMessage.jsonMessageId = TEMPORARY_MESSAGE_ID_INT
|
||||||
temporaryChatMessage.actorId = "-3"
|
temporaryChatMessage.actorId = TEMPORARY_MESSAGE_ID_STRING
|
||||||
temporaryChatMessage.timestamp = System.currentTimeMillis() / ONE_SECOND_IN_MILLIS
|
temporaryChatMessage.timestamp = System.currentTimeMillis() / ONE_SECOND_IN_MILLIS
|
||||||
temporaryChatMessage.message = qMsg.message.toString()
|
temporaryChatMessage.message = qMsg.message.toString()
|
||||||
temporaryChatMessage.tempMessageId = qMsg.id
|
temporaryChatMessage.tempMessageId = qMsg.id
|
||||||
@ -813,6 +813,8 @@ class ChatActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
is MessageInputViewModel.SendChatMessageErrorState -> {
|
is MessageInputViewModel.SendChatMessageErrorState -> {
|
||||||
|
binding.messagesListView.smoothScrollToPosition(0)
|
||||||
|
|
||||||
// if (state.e is HttpException) {
|
// if (state.e is HttpException) {
|
||||||
// val code = state.e.code()
|
// val code = state.e.code()
|
||||||
// if (code.toString().startsWith("2")) {
|
// if (code.toString().startsWith("2")) {
|
||||||
@ -2933,7 +2935,11 @@ class ChatActivity :
|
|||||||
if (message.item is ChatMessage) {
|
if (message.item is ChatMessage) {
|
||||||
val chatMessage = message.item as ChatMessage
|
val chatMessage = message.item as ChatMessage
|
||||||
|
|
||||||
if (chatMessage.jsonMessageId <= xChatLastCommonRead) {
|
if (chatMessage.sendingFailed) {
|
||||||
|
chatMessage.readStatus = ReadStatus.FAILED
|
||||||
|
} else if (chatMessage.isTempMessage) {
|
||||||
|
chatMessage.readStatus = ReadStatus.SENDING
|
||||||
|
} else if (chatMessage.jsonMessageId <= xChatLastCommonRead) {
|
||||||
chatMessage.readStatus = ReadStatus.READ
|
chatMessage.readStatus = ReadStatus.READ
|
||||||
} else {
|
} else {
|
||||||
chatMessage.readStatus = ReadStatus.SENT
|
chatMessage.readStatus = ReadStatus.SENT
|
||||||
@ -3439,7 +3445,7 @@ class ChatActivity :
|
|||||||
val message = iMessage as ChatMessage
|
val message = iMessage as ChatMessage
|
||||||
if (hasVisibleItems(message) &&
|
if (hasVisibleItems(message) &&
|
||||||
!isSystemMessage(message) &&
|
!isSystemMessage(message) &&
|
||||||
message.id != "-3"
|
message.id != TEMPORARY_MESSAGE_ID_STRING
|
||||||
) {
|
) {
|
||||||
MessageActionsDialog(
|
MessageActionsDialog(
|
||||||
this,
|
this,
|
||||||
@ -3863,7 +3869,7 @@ class ChatActivity :
|
|||||||
CONTENT_TYPE_SYSTEM_MESSAGE -> !TextUtils.isEmpty(message.systemMessage)
|
CONTENT_TYPE_SYSTEM_MESSAGE -> !TextUtils.isEmpty(message.systemMessage)
|
||||||
CONTENT_TYPE_UNREAD_NOTICE_MESSAGE -> message.id == UNREAD_MESSAGES_MARKER_ID.toString()
|
CONTENT_TYPE_UNREAD_NOTICE_MESSAGE -> message.id == UNREAD_MESSAGES_MARKER_ID.toString()
|
||||||
CONTENT_TYPE_CALL_STARTED -> message.id == "-2"
|
CONTENT_TYPE_CALL_STARTED -> message.id == "-2"
|
||||||
CONTENT_TYPE_TEMP -> message.id == "-3"
|
CONTENT_TYPE_TEMP -> message.id == TEMPORARY_MESSAGE_ID_STRING
|
||||||
CONTENT_TYPE_DECK_CARD -> message.isDeckCard()
|
CONTENT_TYPE_DECK_CARD -> message.isDeckCard()
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
|
@ -115,11 +115,13 @@ data class ChatMessage(
|
|||||||
|
|
||||||
var openWhenDownloaded: Boolean = true,
|
var openWhenDownloaded: Boolean = true,
|
||||||
|
|
||||||
var isTempMessage: Boolean = false,
|
var isTempMessage: Boolean = false, // TODO: replace logic from message drafts with logic from temp message sending
|
||||||
|
|
||||||
var tempMessageId: Int = -1,
|
var tempMessageId: Int = -1, // TODO: replace logic from message drafts with logic from temp message sending
|
||||||
|
|
||||||
var referenceId: String? = null
|
var referenceId: String? = null,
|
||||||
|
|
||||||
|
var sendingFailed: Boolean = true
|
||||||
|
|
||||||
) : MessageContentType,
|
) : MessageContentType,
|
||||||
MessageContentType.Image {
|
MessageContentType.Image {
|
||||||
|
@ -186,7 +186,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
if (list.isNotEmpty()) {
|
if (list.isNotEmpty()) {
|
||||||
updateUiMessages(
|
updateUiMessages(
|
||||||
chatMessages = list,
|
receivedChatMessages = list,
|
||||||
lookIntoFuture = false,
|
lookIntoFuture = false,
|
||||||
showUnreadMessagesMarker = false
|
showUnreadMessagesMarker = false
|
||||||
)
|
)
|
||||||
@ -308,7 +308,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
showUnreadMessagesMarker = showUnreadMessagesMarker && !weHaveMessagesFromOurself
|
showUnreadMessagesMarker = showUnreadMessagesMarker && !weHaveMessagesFromOurself
|
||||||
|
|
||||||
updateUiMessages(
|
updateUiMessages(
|
||||||
chatMessages = chatMessages,
|
receivedChatMessages = chatMessages,
|
||||||
lookIntoFuture = true,
|
lookIntoFuture = true,
|
||||||
showUnreadMessagesMarker = showUnreadMessagesMarker
|
showUnreadMessagesMarker = showUnreadMessagesMarker
|
||||||
)
|
)
|
||||||
@ -335,7 +335,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun updateUiMessages(
|
private suspend fun updateUiMessages(
|
||||||
chatMessages : List<ChatMessage>,
|
receivedChatMessages : List<ChatMessage>,
|
||||||
lookIntoFuture: Boolean,
|
lookIntoFuture: Boolean,
|
||||||
showUnreadMessagesMarker: Boolean
|
showUnreadMessagesMarker: Boolean
|
||||||
) {
|
) {
|
||||||
@ -346,11 +346,11 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
oldTempMessages.forEach { _removeMessageFlow.emit(it) }
|
oldTempMessages.forEach { _removeMessageFlow.emit(it) }
|
||||||
|
|
||||||
// add new messages to UI
|
// add new messages to UI
|
||||||
val tripleChatMessages = Triple(lookIntoFuture, showUnreadMessagesMarker, chatMessages)
|
val tripleChatMessages = Triple(lookIntoFuture, showUnreadMessagesMarker, receivedChatMessages)
|
||||||
_messageFlow.emit(tripleChatMessages)
|
_messageFlow.emit(tripleChatMessages)
|
||||||
|
|
||||||
// remove temp messages from DB that are now found in the new messages
|
// remove temp messages from DB that are now found in the new messages
|
||||||
val chatMessagesReferenceIds = chatMessages.mapTo(HashSet(chatMessages.size)) { it.referenceId }
|
val chatMessagesReferenceIds = receivedChatMessages.mapTo(HashSet(receivedChatMessages.size)) { it.referenceId }
|
||||||
val tempChatMessagesThatCanBeReplaced = oldTempMessages.filter { it.referenceId in chatMessagesReferenceIds }
|
val tempChatMessagesThatCanBeReplaced = oldTempMessages.filter { it.referenceId in chatMessagesReferenceIds }
|
||||||
chatDao.deleteTempChatMessages(
|
chatDao.deleteTempChatMessages(
|
||||||
internalConversationId,
|
internalConversationId,
|
||||||
@ -815,6 +815,17 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
emit(Result.success(chatMessageModel))
|
emit(Result.success(chatMessageModel))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error when sending message", e)
|
Log.e(TAG, "Error when sending message", e)
|
||||||
|
|
||||||
|
val failedMessage = chatDao.getTempMessageForConversation(internalConversationId, referenceId).first()
|
||||||
|
failedMessage.sendingFailed = true
|
||||||
|
chatDao.updateChatMessage(failedMessage)
|
||||||
|
|
||||||
|
val failedMessageModel = failedMessage.asModel()
|
||||||
|
_removeMessageFlow.emit(failedMessageModel)
|
||||||
|
|
||||||
|
val tripleChatMessages = Triple(true, false, listOf(failedMessageModel))
|
||||||
|
_messageFlow.emit(tripleChatMessages)
|
||||||
|
|
||||||
emit(Result.failure(e))
|
emit(Result.failure(e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -877,7 +888,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
internalId = internalConversationId + "@_temp_" + currentTimeMillies,
|
internalId = internalConversationId + "@_temp_" + currentTimeMillies,
|
||||||
internalConversationId = internalConversationId,
|
internalConversationId = internalConversationId,
|
||||||
id = currentTimeMillies,
|
id = currentTimeMillies,
|
||||||
message = message + " (temp)",
|
message = message,
|
||||||
deleted = false,
|
deleted = false,
|
||||||
token = conversationModel.token,
|
token = conversationModel.token,
|
||||||
actorId = currentUser.userId!!,
|
actorId = currentUser.userId!!,
|
||||||
|
@ -48,6 +48,18 @@ interface ChatMessagesDao {
|
|||||||
)
|
)
|
||||||
fun getTempMessagesForConversation(internalConversationId: String): Flow<List<ChatMessageEntity>>
|
fun getTempMessagesForConversation(internalConversationId: String): Flow<List<ChatMessageEntity>>
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT *
|
||||||
|
FROM ChatMessages
|
||||||
|
WHERE internalConversationId = :internalConversationId
|
||||||
|
AND referenceId = :referenceId
|
||||||
|
AND isTemporary = 1
|
||||||
|
ORDER BY timestamp DESC, id DESC
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun getTempMessageForConversation(internalConversationId: String, referenceId: String): Flow<ChatMessageEntity>
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun upsertChatMessages(chatMessages: List<ChatMessageEntity>)
|
suspend fun upsertChatMessages(chatMessages: List<ChatMessageEntity>)
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ package com.nextcloud.talk.data.database.mappers
|
|||||||
import com.nextcloud.talk.models.json.chat.ChatMessageJson
|
import com.nextcloud.talk.models.json.chat.ChatMessageJson
|
||||||
import com.nextcloud.talk.data.database.model.ChatMessageEntity
|
import com.nextcloud.talk.data.database.model.ChatMessageEntity
|
||||||
import com.nextcloud.talk.chat.data.model.ChatMessage
|
import com.nextcloud.talk.chat.data.model.ChatMessage
|
||||||
|
import com.nextcloud.talk.models.json.chat.ReadStatus
|
||||||
|
|
||||||
fun ChatMessageJson.asEntity(accountId: Long) =
|
fun ChatMessageJson.asEntity(accountId: Long) =
|
||||||
ChatMessageEntity(
|
ChatMessageEntity(
|
||||||
@ -64,9 +65,22 @@ fun ChatMessageEntity.asModel() =
|
|||||||
lastEditActorType = lastEditActorType,
|
lastEditActorType = lastEditActorType,
|
||||||
lastEditTimestamp = lastEditTimestamp,
|
lastEditTimestamp = lastEditTimestamp,
|
||||||
isDeleted = deleted,
|
isDeleted = deleted,
|
||||||
referenceId = referenceId
|
referenceId = referenceId,
|
||||||
|
isTempMessage = isTemporary,
|
||||||
|
sendingFailed = sendingFailed,
|
||||||
|
readStatus = setStatus(isTemporary, sendingFailed)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun setStatus(isTemporary: Boolean, sendingFailed: Boolean): ReadStatus {
|
||||||
|
return if (sendingFailed) {
|
||||||
|
ReadStatus.FAILED
|
||||||
|
} else if (isTemporary) {
|
||||||
|
ReadStatus.SENDING
|
||||||
|
} else {
|
||||||
|
ReadStatus.NONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun ChatMessageJson.asModel() =
|
fun ChatMessageJson.asModel() =
|
||||||
ChatMessage(
|
ChatMessage(
|
||||||
jsonMessageId = id.toInt(),
|
jsonMessageId = id.toInt(),
|
||||||
|
@ -9,5 +9,7 @@ package com.nextcloud.talk.models.json.chat
|
|||||||
enum class ReadStatus {
|
enum class ReadStatus {
|
||||||
NONE,
|
NONE,
|
||||||
SENT,
|
SENT,
|
||||||
READ
|
READ,
|
||||||
|
SENDING,
|
||||||
|
FAILED
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,32 @@
|
|||||||
app:layout_alignSelf="center"
|
app:layout_alignSelf="center"
|
||||||
app:tint="@color/high_emphasis_text" />
|
app:tint="@color/high_emphasis_text" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/sending_failed"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/message_bubble_checkmark_height"
|
||||||
|
android:layout_below="@id/messageTime"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
app:layout_alignSelf="center"
|
||||||
|
app:tint="@color/high_emphasis_text" />
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||||
|
android:id="@+id/sending_progress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/message_bubble_checkmark_height"
|
||||||
|
android:layout_below="@id/messageTime"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:indicatorColor="@color/colorPrimary"
|
||||||
|
app:indicatorSize="14dp"
|
||||||
|
app:trackColor="@color/colorPrimary"
|
||||||
|
app:trackThickness="2dp"
|
||||||
|
tools:visibility="visible"
|
||||||
|
/>
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/reactions"
|
android:id="@+id/reactions"
|
||||||
layout="@layout/reactions_inside_message" />
|
layout="@layout/reactions_inside_message" />
|
||||||
|
Loading…
Reference in New Issue
Block a user