handle special system messages in ChatRepo instead in UI

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2024-08-07 21:35:12 +02:00
Родитель db8d7b91d4
Коммит 85f4d8cd92
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: C793F8B59F43CE7B
7 изменённых файлов: 38 добавлений и 71 удалений

Просмотреть файл

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 10,
"identityHash": "93ef64fac7a9a811c4a3c2f5a6406f87",
"identityHash": "234cdb754d42d9ebf2349763a58a4578",
"entities": [
{
"tableName": "User",
@ -438,7 +438,7 @@
},
{
"tableName": "ChatMessages",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER, `token` TEXT, `id` INTEGER NOT NULL, `internalConversationId` TEXT, `actorType` TEXT, `actorId` TEXT, `actorDisplayName` TEXT, `timestamp` INTEGER NOT NULL, `systemMessage` TEXT, `messageType` TEXT, `isReplyable` INTEGER NOT NULL, `message` TEXT, `messageParameters` TEXT, `expirationTimestamp` INTEGER NOT NULL, `parent` INTEGER, `reactions` TEXT, `reactionsSelf` TEXT, `markdown` INTEGER, `lastEditActorType` TEXT, `lastEditActorId` TEXT, `lastEditActorDisplayName` TEXT, `lastEditTimestamp` INTEGER, PRIMARY KEY(`internalId`), FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER, `token` TEXT, `id` INTEGER NOT NULL, `internalConversationId` TEXT, `actorType` TEXT, `actorId` TEXT, `actorDisplayName` TEXT, `timestamp` INTEGER NOT NULL, `systemMessage` TEXT, `messageType` TEXT, `isReplyable` INTEGER NOT NULL, `message` TEXT, `messageParameters` TEXT, `expirationTimestamp` INTEGER NOT NULL, `parent` INTEGER, `reactions` TEXT, `reactionsSelf` TEXT, `markdown` INTEGER, `lastEditActorType` TEXT, `lastEditActorId` TEXT, `lastEditActorDisplayName` TEXT, `lastEditTimestamp` INTEGER, `deleted` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "internalId",
@ -577,6 +577,12 @@
"columnName": "lastEditTimestamp",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
@ -667,7 +673,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '93ef64fac7a9a811c4a3c2f5a6406f87')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '234cdb754d42d9ebf2349763a58a4578')"
]
}
}

Просмотреть файл

@ -829,7 +829,7 @@ class ChatActivity :
this.lifecycleScope.launch {
chatViewModel.getUpdateMessageFlow
.onEach {
updateAdapterForReaction(it)
updateMessageInsideAdapter(it)
}
.collect()
}
@ -2923,42 +2923,17 @@ class ChatActivity :
private fun handleSystemMessages(chatMessageList: List<ChatMessage>): List<ChatMessage> {
val chatMessageMap = chatMessageList.map { it.id to it }.toMap().toMutableMap()
val chatMessageIterator = chatMessageMap.iterator()
while (chatMessageIterator.hasNext()) {
val currentMessage = chatMessageIterator.next()
// setDeletionFlagsAndRemoveInfomessages
if (isInfoMessageAboutDeletion(currentMessage)) {
if (!chatMessageMap.containsKey(currentMessage.value.parentMessageId.toString())) {
// if chatMessageMap doesn't contain message to delete (this happens when lookingIntoFuture),
// the message to delete has to be modified directly inside the adapter
val id = currentMessage.value.parentMessageId.toString()
val index = adapter?.getMessagePositionById(id) ?: 0
if (index > 0) {
val message = adapter?.items?.get(index)?.item as ChatMessage
setMessageAsDeleted(message)
}
} else {
chatMessageMap[currentMessage.value.parentMessageId.toString()]!!.isDeleted = true
}
chatMessageIterator.remove()
} else if (isReactionsMessage(currentMessage)) {
// delete reactions system messages
if (!chatMessageMap.containsKey(currentMessage.value.parentMessageId.toString())) {
// updateAdapterForReaction(currentMessage.value.parentMessage) TODO
}
chatMessageIterator.remove()
} else if (isPollVotedMessage(currentMessage)) {
// delete poll system messages
chatMessageIterator.remove()
} else if (isEditMessage(currentMessage)) {
if (!chatMessageMap.containsKey(currentMessage.value.parentMessageId.toString())) {
// setMessageAsEdited(currentMessage.value.parentMessage) TODO
}
if (isInfoMessageAboutDeletion(currentMessage) ||
isReactionsMessage(currentMessage) ||
isPollVotedMessage(currentMessage) ||
isEditMessage(currentMessage)
) {
chatMessageIterator.remove()
}
}
@ -3401,10 +3376,11 @@ class ChatActivity :
adapter?.update(messageTemp)
}
private fun updateAdapterForReaction(message: IMessage?) {
private fun updateMessageInsideAdapter(message: IMessage?) {
message?.let {
val messageTemp = message as ChatMessage
// TODO is this needed?
messageTemp.isOneToOneConversation =
currentConversation?.type == ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL
messageTemp.activeUser = conversationUser

Просмотреть файл

@ -9,8 +9,6 @@ package com.nextcloud.talk.chat.data
import android.os.Bundle
import com.nextcloud.talk.chat.data.io.LifecycleAwareManager
import com.nextcloud.talk.models.json.chat.ChatMessageJson
import com.nextcloud.talk.data.sync.Syncable
import com.nextcloud.talk.chat.data.model.ChatMessage
import com.nextcloud.talk.models.domain.ConversationModel
import kotlinx.coroutines.Job

Просмотреть файл

@ -415,9 +415,7 @@ class OfflineFirstChatRepository @Inject constructor(
if (result.second.isNotEmpty()) {
val chatMessagesJson = result.second
if (lookIntoFuture) {
handleUpdateMessages(chatMessagesJson)
}
handleUpdateMessages(chatMessagesJson)
chatMessagesFromSync = chatMessagesJson.map {
it.asEntity(currentUser.id!!)
@ -467,7 +465,14 @@ class OfflineFirstChatRepository @Inject constructor(
private suspend fun handleUpdateMessages(messagesJson: List<ChatMessageJson>) {
messagesJson.forEach { messageJson ->
when (messageJson.systemMessageType) {
ChatMessage.SystemMessageType.REACTION -> {
ChatMessage.SystemMessageType.REACTION,
ChatMessage.SystemMessageType.REACTION_REVOKED,
ChatMessage.SystemMessageType.REACTION_DELETED,
ChatMessage.SystemMessageType.MESSAGE_DELETED,
ChatMessage.SystemMessageType.POLL_VOTED,
ChatMessage.SystemMessageType.MESSAGE_EDITED -> {
// the parent message is always the newest state, no matter how old the system message is.
// that's why we can just take the parent, update it in DB and update the UI
messageJson.parentMessage?.let { parentMessageJson ->
val parentMessageEntity = parentMessageJson.asEntity(currentUser.id!!)
chatDao.upsertChatMessage(parentMessageEntity)
@ -475,26 +480,6 @@ class OfflineFirstChatRepository @Inject constructor(
}
}
ChatMessage.SystemMessageType.REACTION_REVOKED -> {
// TODO
}
ChatMessage.SystemMessageType.REACTION_DELETED -> {
// TODO
}
ChatMessage.SystemMessageType.MESSAGE_DELETED -> {
// TODO
}
ChatMessage.SystemMessageType.POLL_VOTED -> {
// TODO
}
ChatMessage.SystemMessageType.MESSAGE_EDITED -> {
// TODO
}
ChatMessage.SystemMessageType.CLEARED_CHAT -> {
val pattern = "$internalConversationId%" // LIKE "<accountId>@<conversationId>@%"
chatDao.clearAllMessagesForUser(pattern)

Просмотреть файл

@ -38,7 +38,8 @@ fun ChatMessageJson.asEntity(accountId: Long) =
lastEditActorDisplayName = lastEditActorDisplayName,
lastEditActorId = lastEditActorId,
lastEditActorType = lastEditActorType,
lastEditTimestamp = lastEditTimestamp
lastEditTimestamp = lastEditTimestamp,
deleted = deleted
)
fun ChatMessageEntity.asModel() =
@ -62,7 +63,8 @@ fun ChatMessageEntity.asModel() =
lastEditActorDisplayName = lastEditActorDisplayName,
lastEditActorId = lastEditActorId,
lastEditActorType = lastEditActorType,
lastEditTimestamp = lastEditTimestamp
lastEditTimestamp = lastEditTimestamp,
isDeleted = deleted
)
fun ChatMessageJson.asModel() =
@ -86,5 +88,6 @@ fun ChatMessageJson.asModel() =
lastEditActorDisplayName = lastEditActorDisplayName,
lastEditActorId = lastEditActorId,
lastEditActorType = lastEditActorType,
lastEditTimestamp = lastEditTimestamp
lastEditTimestamp = lastEditTimestamp,
isDeleted = deleted
)

Просмотреть файл

@ -58,6 +58,7 @@ data class ChatMessageEntity(
@ColumnInfo(name = "lastEditActorType") var lastEditActorType: String? = null,
@ColumnInfo(name = "lastEditActorId") var lastEditActorId: String? = null,
@ColumnInfo(name = "lastEditActorDisplayName") var lastEditActorDisplayName: String? = null,
@ColumnInfo(name = "lastEditTimestamp") var lastEditTimestamp: Long? = 0
@ColumnInfo(name = "lastEditTimestamp") var lastEditTimestamp: Long? = 0,
@ColumnInfo(name = "deleted") var deleted: Boolean = false,
// TODO: add "silent"
)

Просмотреть файл

@ -18,7 +18,7 @@ import kotlinx.parcelize.Parcelize
@Parcelize
@JsonObject
data class ChatMessageJson(
@JsonField(name = ["id"]) override var id: Long = 0,
@JsonField(name = ["id"]) var id: Long = 0,
@JsonField(name = ["token"]) var token: String? = null,
@JsonField(name = ["actorType"]) var actorType: String? = null,
@JsonField(name = ["actorId"]) var actorId: String? = null,
@ -43,7 +43,5 @@ data class ChatMessageJson(
@JsonField(name = ["lastEditActorId"]) var lastEditActorId: String? = null,
@JsonField(name = ["lastEditActorType"]) var lastEditActorType: String? = null,
@JsonField(name = ["lastEditTimestamp"]) var lastEditTimestamp: Long? = 0,
// override var markedForDeletion: Boolean = "comment_deleted" == messageType
override var markedForDeletion: Boolean = false
) : Parcelable, SyncableModel
@JsonField(name = ["deleted"]) var deleted: Boolean = false,
) : Parcelable