mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-07 21:09:46 +01:00
add chatBlock handling for threads
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
7d6cdb9e0d
commit
b04a9c49cf
@ -52,7 +52,8 @@ class ChatBlocksDaoTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testGetConnectedChatBlocks() =
|
fun testGetConnectedChatBlocks() =
|
||||||
runTest {
|
runTest {
|
||||||
usersDao.saveUser(createUserEntity("account1", "Account 1"))
|
val user = createUserEntity("account1", "Account 1")
|
||||||
|
usersDao.saveUser(user)
|
||||||
val account1 = usersDao.getUserWithUserId("account1").blockingGet()
|
val account1 = usersDao.getUserWithUserId("account1").blockingGet()
|
||||||
|
|
||||||
conversationsDao.upsertConversations(
|
conversationsDao.upsertConversations(
|
||||||
@ -77,6 +78,7 @@ class ChatBlocksDaoTest {
|
|||||||
internalConversationId = conversation1.internalId,
|
internalConversationId = conversation1.internalId,
|
||||||
accountId = conversation1.accountId,
|
accountId = conversation1.accountId,
|
||||||
token = conversation1.token,
|
token = conversation1.token,
|
||||||
|
threadId = null,
|
||||||
oldestMessageId = 50,
|
oldestMessageId = 50,
|
||||||
newestMessageId = 60,
|
newestMessageId = 60,
|
||||||
hasHistory = true
|
hasHistory = true
|
||||||
@ -86,6 +88,7 @@ class ChatBlocksDaoTest {
|
|||||||
internalConversationId = conversation1.internalId,
|
internalConversationId = conversation1.internalId,
|
||||||
accountId = conversation1.accountId,
|
accountId = conversation1.accountId,
|
||||||
token = conversation1.token,
|
token = conversation1.token,
|
||||||
|
threadId = null,
|
||||||
oldestMessageId = 10,
|
oldestMessageId = 10,
|
||||||
newestMessageId = 20,
|
newestMessageId = 20,
|
||||||
hasHistory = true
|
hasHistory = true
|
||||||
@ -95,6 +98,7 @@ class ChatBlocksDaoTest {
|
|||||||
internalConversationId = conversation1.internalId,
|
internalConversationId = conversation1.internalId,
|
||||||
accountId = conversation1.accountId,
|
accountId = conversation1.accountId,
|
||||||
token = conversation1.token,
|
token = conversation1.token,
|
||||||
|
threadId = null,
|
||||||
oldestMessageId = 45,
|
oldestMessageId = 45,
|
||||||
newestMessageId = 55,
|
newestMessageId = 55,
|
||||||
hasHistory = true
|
hasHistory = true
|
||||||
@ -104,6 +108,7 @@ class ChatBlocksDaoTest {
|
|||||||
internalConversationId = conversation1.internalId,
|
internalConversationId = conversation1.internalId,
|
||||||
accountId = conversation1.accountId,
|
accountId = conversation1.accountId,
|
||||||
token = conversation1.token,
|
token = conversation1.token,
|
||||||
|
threadId = null,
|
||||||
oldestMessageId = 52,
|
oldestMessageId = 52,
|
||||||
newestMessageId = 58,
|
newestMessageId = 58,
|
||||||
hasHistory = true
|
hasHistory = true
|
||||||
@ -113,6 +118,7 @@ class ChatBlocksDaoTest {
|
|||||||
internalConversationId = conversation1.internalId,
|
internalConversationId = conversation1.internalId,
|
||||||
accountId = conversation1.accountId,
|
accountId = conversation1.accountId,
|
||||||
token = conversation1.token,
|
token = conversation1.token,
|
||||||
|
threadId = null,
|
||||||
oldestMessageId = 1,
|
oldestMessageId = 1,
|
||||||
newestMessageId = 99,
|
newestMessageId = 99,
|
||||||
hasHistory = true
|
hasHistory = true
|
||||||
@ -122,6 +128,7 @@ class ChatBlocksDaoTest {
|
|||||||
internalConversationId = conversation1.internalId,
|
internalConversationId = conversation1.internalId,
|
||||||
accountId = conversation1.accountId,
|
accountId = conversation1.accountId,
|
||||||
token = conversation1.token,
|
token = conversation1.token,
|
||||||
|
threadId = null,
|
||||||
oldestMessageId = 59,
|
oldestMessageId = 59,
|
||||||
newestMessageId = 70,
|
newestMessageId = 70,
|
||||||
hasHistory = true
|
hasHistory = true
|
||||||
@ -131,6 +138,7 @@ class ChatBlocksDaoTest {
|
|||||||
internalConversationId = conversation1.internalId,
|
internalConversationId = conversation1.internalId,
|
||||||
accountId = conversation1.accountId,
|
accountId = conversation1.accountId,
|
||||||
token = conversation1.token,
|
token = conversation1.token,
|
||||||
|
threadId = null,
|
||||||
oldestMessageId = 80,
|
oldestMessageId = 80,
|
||||||
newestMessageId = 90,
|
newestMessageId = 90,
|
||||||
hasHistory = true
|
hasHistory = true
|
||||||
@ -140,6 +148,7 @@ class ChatBlocksDaoTest {
|
|||||||
internalConversationId = conversation2.internalId,
|
internalConversationId = conversation2.internalId,
|
||||||
accountId = conversation2.accountId,
|
accountId = conversation2.accountId,
|
||||||
token = conversation2.token,
|
token = conversation2.token,
|
||||||
|
threadId = null,
|
||||||
oldestMessageId = 53,
|
oldestMessageId = 53,
|
||||||
newestMessageId = 57,
|
newestMessageId = 57,
|
||||||
hasHistory = true
|
hasHistory = true
|
||||||
@ -156,9 +165,10 @@ class ChatBlocksDaoTest {
|
|||||||
chatBlocksDao.upsertChatBlock(chatBlockWithinButOtherConversation)
|
chatBlocksDao.upsertChatBlock(chatBlockWithinButOtherConversation)
|
||||||
|
|
||||||
val results = chatBlocksDao.getConnectedChatBlocks(
|
val results = chatBlocksDao.getConnectedChatBlocks(
|
||||||
conversation1.internalId,
|
internalConversationId = conversation1.internalId,
|
||||||
searchedChatBlock.oldestMessageId,
|
threadId = null,
|
||||||
searchedChatBlock.newestMessageId
|
oldestMessageId = searchedChatBlock.oldestMessageId,
|
||||||
|
newestMessageId = searchedChatBlock.newestMessageId
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(5, results.first().size)
|
assertEquals(5, results.first().size)
|
||||||
|
@ -140,7 +140,11 @@ class ChatMessagesDaoTest {
|
|||||||
assertEquals("are", conv1chatMessage3.message)
|
assertEquals("are", conv1chatMessage3.message)
|
||||||
|
|
||||||
val chatMessagesConv1Since =
|
val chatMessagesConv1Since =
|
||||||
chatMessagesDao.getMessagesForConversationSince(conversation1.internalId, conv1chatMessage3.id)
|
chatMessagesDao.getMessagesForConversationSince(
|
||||||
|
conversation1.internalId,
|
||||||
|
conv1chatMessage3.id,
|
||||||
|
null
|
||||||
|
)
|
||||||
assertEquals(3, chatMessagesConv1Since.first().size)
|
assertEquals(3, chatMessagesConv1Since.first().size)
|
||||||
assertEquals("are", chatMessagesConv1Since.first()[0].message)
|
assertEquals("are", chatMessagesConv1Since.first()[0].message)
|
||||||
assertEquals("some", chatMessagesConv1Since.first()[1].message)
|
assertEquals("some", chatMessagesConv1Since.first()[1].message)
|
||||||
@ -150,7 +154,8 @@ class ChatMessagesDaoTest {
|
|||||||
chatMessagesDao.getMessagesForConversationBeforeAndEqual(
|
chatMessagesDao.getMessagesForConversationBeforeAndEqual(
|
||||||
conversation1.internalId,
|
conversation1.internalId,
|
||||||
conv1chatMessage3.id,
|
conv1chatMessage3.id,
|
||||||
3
|
3,
|
||||||
|
null
|
||||||
)
|
)
|
||||||
assertEquals(3, chatMessagesConv1To.first().size)
|
assertEquals(3, chatMessagesConv1To.first().size)
|
||||||
assertEquals("hello", chatMessagesConv1To.first()[2].message)
|
assertEquals("hello", chatMessagesConv1To.first()[2].message)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
package com.nextcloud.talk.adapters.messages
|
package com.nextcloud.talk.adapters.messages
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -145,7 +146,10 @@ class IncomingTextMessageViewHolder(itemView: View, payload: Any) :
|
|||||||
binding.messageAuthor.visibility = View.GONE
|
binding.messageAuthor.visibility = View.GONE
|
||||||
}
|
}
|
||||||
binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
|
binding.messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
|
||||||
binding.messageText.text = processedMessageText
|
// binding.messageText.text = processedMessageText
|
||||||
|
// just for debugging:
|
||||||
|
binding.messageText.text =
|
||||||
|
SpannableStringBuilder(processedMessageText).append(" (" + message.jsonMessageId + ")")
|
||||||
} else {
|
} else {
|
||||||
binding.messageText.visibility = View.GONE
|
binding.messageText.visibility = View.GONE
|
||||||
binding.checkboxContainer.visibility = View.VISIBLE
|
binding.checkboxContainer.visibility = View.VISIBLE
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
package com.nextcloud.talk.adapters.messages
|
package com.nextcloud.talk.adapters.messages
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -159,7 +160,10 @@ class OutcomingTextMessageViewHolder(itemView: View) :
|
|||||||
|
|
||||||
binding.messageTime.layoutParams = layoutParams
|
binding.messageTime.layoutParams = layoutParams
|
||||||
viewThemeUtils.platform.colorTextView(binding.messageText, ColorRole.ON_SURFACE_VARIANT)
|
viewThemeUtils.platform.colorTextView(binding.messageText, ColorRole.ON_SURFACE_VARIANT)
|
||||||
binding.messageText.text = processedMessageText
|
// binding.messageText.text = processedMessageText
|
||||||
|
// just for debugging:
|
||||||
|
binding.messageText.text =
|
||||||
|
SpannableStringBuilder(processedMessageText).append(" (" + message.jsonMessageId + ")")
|
||||||
} else {
|
} else {
|
||||||
binding.messageText.visibility = View.GONE
|
binding.messageText.visibility = View.GONE
|
||||||
binding.checkboxContainer.visibility = View.VISIBLE
|
binding.checkboxContainer.visibility = View.VISIBLE
|
||||||
|
@ -557,7 +557,12 @@ class ChatActivity :
|
|||||||
val extras: Bundle? = intent.extras
|
val extras: Bundle? = intent.extras
|
||||||
|
|
||||||
roomToken = extras?.getString(KEY_ROOM_TOKEN).orEmpty()
|
roomToken = extras?.getString(KEY_ROOM_TOKEN).orEmpty()
|
||||||
threadId = extras?.getLong(KEY_THREAD_ID)
|
|
||||||
|
threadId = if (extras?.containsKey(KEY_THREAD_ID) == true) {
|
||||||
|
extras.getLong(KEY_THREAD_ID)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
sharedText = extras?.getString(BundleKeys.KEY_SHARED_TEXT).orEmpty()
|
sharedText = extras?.getString(BundleKeys.KEY_SHARED_TEXT).orEmpty()
|
||||||
|
|
||||||
|
@ -45,9 +45,11 @@ data class ChatMessage(
|
|||||||
|
|
||||||
var token: String? = null,
|
var token: String? = null,
|
||||||
|
|
||||||
var topmostParentId: Long? = null,
|
var threadId: Long? = null,
|
||||||
|
|
||||||
var childrenCount: Long? = 0,
|
var isThread: Boolean = false,
|
||||||
|
|
||||||
|
// var childrenCount: Long? = 0,
|
||||||
|
|
||||||
// guests or users
|
// guests or users
|
||||||
var actorType: String? = null,
|
var actorType: String? = null,
|
||||||
|
@ -122,16 +122,10 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
private var threadId: Long? = null
|
private var threadId: Long? = null
|
||||||
|
|
||||||
override fun initData(credentials: String, urlForChatting: String, roomToken: String, threadId: Long?) {
|
override fun initData(credentials: String, urlForChatting: String, roomToken: String, threadId: Long?) {
|
||||||
val threadIdAppendedString = if (threadId != null && threadId > 0) {
|
internalConversationId = currentUser.id.toString() + "@" + roomToken
|
||||||
"@$threadId"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
internalConversationId = currentUser.id.toString() + "@" + roomToken + threadIdAppendedString
|
|
||||||
this.credentials = credentials
|
this.credentials = credentials
|
||||||
this.urlForChatting = urlForChatting
|
this.urlForChatting = urlForChatting
|
||||||
this.threadId = threadId // use this threadId in API requests when fetching messages? +
|
this.threadId = threadId
|
||||||
// Introduce ChatBlocks for threads
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateConversation(conversationModel: ConversationModel) {
|
override fun updateConversation(conversationModel: ConversationModel) {
|
||||||
@ -151,7 +145,8 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
Log.d(TAG, "conversationModel.internalId: " + conversationModel.internalId)
|
Log.d(TAG, "conversationModel.internalId: " + conversationModel.internalId)
|
||||||
Log.d(TAG, "conversationModel.lastReadMessage:" + conversationModel.lastReadMessage)
|
Log.d(TAG, "conversationModel.lastReadMessage:" + conversationModel.lastReadMessage)
|
||||||
|
|
||||||
var newestMessageIdFromDb = chatDao.getNewestMessageId(internalConversationId)
|
// var newestMessageIdFromDb = chatDao.getNewestMessageId(internalConversationId, threadId)
|
||||||
|
var newestMessageIdFromDb = chatBlocksDao.getNewestMessageIdFromChatBlocks(internalConversationId, threadId)
|
||||||
Log.d(TAG, "newestMessageIdFromDb: $newestMessageIdFromDb")
|
Log.d(TAG, "newestMessageIdFromDb: $newestMessageIdFromDb")
|
||||||
|
|
||||||
val weAlreadyHaveSomeOfflineMessages = newestMessageIdFromDb > 0
|
val weAlreadyHaveSomeOfflineMessages = newestMessageIdFromDb > 0
|
||||||
@ -197,7 +192,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
Log.e(TAG, "initial loading of messages failed")
|
Log.e(TAG, "initial loading of messages failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
newestMessageIdFromDb = chatDao.getNewestMessageId(internalConversationId)
|
newestMessageIdFromDb = chatBlocksDao.getNewestMessageIdFromChatBlocks(internalConversationId, threadId)
|
||||||
Log.d(TAG, "newestMessageIdFromDb after sync: $newestMessageIdFromDb")
|
Log.d(TAG, "newestMessageIdFromDb after sync: $newestMessageIdFromDb")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,9 +206,9 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
val limit = getCappedMessagesAmountOfChatBlock(newestMessageIdFromDb)
|
val limit = getCappedMessagesAmountOfChatBlock(newestMessageIdFromDb)
|
||||||
|
|
||||||
val list = getMessagesBeforeAndEqual(
|
val list = getMessagesBeforeAndEqual(
|
||||||
newestMessageIdFromDb,
|
messageId = newestMessageIdFromDb,
|
||||||
internalConversationId,
|
internalConversationId = internalConversationId,
|
||||||
limit
|
messageLimit = limit
|
||||||
)
|
)
|
||||||
if (list.isNotEmpty()) {
|
if (list.isNotEmpty()) {
|
||||||
handleNewAndTempMessages(
|
handleNewAndTempMessages(
|
||||||
@ -242,7 +237,8 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
val amountBetween = chatDao.getCountBetweenMessageIds(
|
val amountBetween = chatDao.getCountBetweenMessageIds(
|
||||||
internalConversationId,
|
internalConversationId,
|
||||||
messageId,
|
messageId,
|
||||||
chatBlock.oldestMessageId
|
chatBlock.oldestMessageId,
|
||||||
|
threadId
|
||||||
)
|
)
|
||||||
|
|
||||||
Log.d(TAG, "amount of messages between newestMessageId and oldest message of same ChatBlock:$amountBetween")
|
Log.d(TAG, "amount of messages between newestMessageId and oldest message of same ChatBlock:$amountBetween")
|
||||||
@ -292,7 +288,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
withNetworkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap)
|
withNetworkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap)
|
||||||
|
|
||||||
val loadFromServer = hasToLoadPreviousMessagesFromServer(beforeMessageId)
|
val loadFromServer = hasToLoadPreviousMessagesFromServer(beforeMessageId, DEFAULT_MESSAGES_LIMIT)
|
||||||
|
|
||||||
if (loadFromServer) {
|
if (loadFromServer) {
|
||||||
Log.d(TAG, "Starting online request for loadMoreMessages")
|
Log.d(TAG, "Starting online request for loadMoreMessages")
|
||||||
@ -354,7 +350,10 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
|
|
||||||
updateUiForLastCommonRead()
|
updateUiForLastCommonRead()
|
||||||
|
|
||||||
val newestMessage = chatDao.getNewestMessageId(internalConversationId).toInt()
|
val newestMessage = chatBlocksDao.getNewestMessageIdFromChatBlocks(
|
||||||
|
internalConversationId,
|
||||||
|
threadId
|
||||||
|
).toInt()
|
||||||
|
|
||||||
// update field map vars for next cycle
|
// update field map vars for next cycle
|
||||||
fieldMap = getFieldMap(
|
fieldMap = getFieldMap(
|
||||||
@ -380,7 +379,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove all temp messages from UI
|
// remove all temp messages from UI
|
||||||
val oldTempMessages = chatDao.getTempMessagesForConversation(internalConversationId)
|
val oldTempMessages = chatDao.getTempMessagesForConversation(internalConversationId, threadId)
|
||||||
.first()
|
.first()
|
||||||
.map(ChatMessageEntity::asModel)
|
.map(ChatMessageEntity::asModel)
|
||||||
oldTempMessages.forEach {
|
oldTempMessages.forEach {
|
||||||
@ -404,7 +403,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// add the remaining temp messages to UI again
|
// add the remaining temp messages to UI again
|
||||||
val remainingTempMessages = chatDao.getTempMessagesForConversation(internalConversationId)
|
val remainingTempMessages = chatDao.getTempMessagesForConversation(internalConversationId, threadId)
|
||||||
.first()
|
.first()
|
||||||
.sortedBy { it.internalId }
|
.sortedBy { it.internalId }
|
||||||
.map(ChatMessageEntity::asModel)
|
.map(ChatMessageEntity::asModel)
|
||||||
@ -417,7 +416,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
_messageFlow.emit(triple)
|
_messageFlow.emit(triple)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun hasToLoadPreviousMessagesFromServer(beforeMessageId: Long): Boolean {
|
private suspend fun hasToLoadPreviousMessagesFromServer(beforeMessageId: Long, amountToCheck: Int): Boolean {
|
||||||
val loadFromServer: Boolean
|
val loadFromServer: Boolean
|
||||||
|
|
||||||
val blockForMessage = getBlockOfMessage(beforeMessageId.toInt())
|
val blockForMessage = getBlockOfMessage(beforeMessageId.toInt())
|
||||||
@ -429,21 +428,19 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
Log.d(TAG, "The last chatBlock is reached so we won't request server for older messages")
|
Log.d(TAG, "The last chatBlock is reached so we won't request server for older messages")
|
||||||
loadFromServer = false
|
loadFromServer = false
|
||||||
} else {
|
} else {
|
||||||
// we know that beforeMessageId and blockForMessage.oldestMessageId are in the same block.
|
|
||||||
// As we want the last DEFAULT_MESSAGES_LIMIT entries before beforeMessageId, we calculate if these
|
|
||||||
// messages are DEFAULT_MESSAGES_LIMIT entries apart from each other
|
|
||||||
|
|
||||||
val amountBetween = chatDao.getCountBetweenMessageIds(
|
val amountBetween = chatDao.getCountBetweenMessageIds(
|
||||||
internalConversationId,
|
internalConversationId,
|
||||||
beforeMessageId,
|
beforeMessageId,
|
||||||
blockForMessage.oldestMessageId
|
blockForMessage.oldestMessageId,
|
||||||
|
threadId
|
||||||
)
|
)
|
||||||
loadFromServer = amountBetween < DEFAULT_MESSAGES_LIMIT
|
loadFromServer = amountBetween < amountToCheck
|
||||||
|
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
"Amount between messageId " + beforeMessageId + " and " + blockForMessage.oldestMessageId +
|
"Amount between messageId " + beforeMessageId + " and " + blockForMessage.oldestMessageId +
|
||||||
" is: " + amountBetween + " so 'loadFromServer' is " + loadFromServer
|
" is: " + amountBetween + " and $amountToCheck were needed, so 'loadFromServer' is " +
|
||||||
|
loadFromServer
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return loadFromServer
|
return loadFromServer
|
||||||
@ -479,7 +476,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun getMessage(messageId: Long, bundle: Bundle): Flow<ChatMessage> {
|
override suspend fun getMessage(messageId: Long, bundle: Bundle): Flow<ChatMessage> {
|
||||||
Log.d(TAG, "Get message with id $messageId")
|
Log.d(TAG, "Get message with id $messageId")
|
||||||
val loadFromServer = hasToLoadPreviousMessagesFromServer(messageId)
|
val loadFromServer = hasToLoadPreviousMessagesFromServer(messageId, 1)
|
||||||
|
|
||||||
if (loadFromServer) {
|
if (loadFromServer) {
|
||||||
val fieldMap = getFieldMap(
|
val fieldMap = getFieldMap(
|
||||||
@ -495,8 +492,10 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
Log.d(TAG, "Starting online request for single message (e.g. a reply)")
|
Log.d(TAG, "Starting online request for single message (e.g. a reply)")
|
||||||
sync(bundle)
|
sync(bundle)
|
||||||
}
|
}
|
||||||
return chatDao.getChatMessageForConversation(internalConversationId, messageId)
|
return chatDao.getChatMessageForConversation(
|
||||||
.map(ChatMessageEntity::asModel)
|
internalConversationId,
|
||||||
|
messageId
|
||||||
|
).map(ChatMessageEntity::asModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST", "MagicNumber", "Detekt.TooGenericExceptionCaught")
|
@Suppress("UNCHECKED_CAST", "MagicNumber", "Detekt.TooGenericExceptionCaught")
|
||||||
@ -660,11 +659,12 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
internalConversationId = internalConversationId,
|
internalConversationId = internalConversationId,
|
||||||
accountId = conversationModel.accountId,
|
accountId = conversationModel.accountId,
|
||||||
token = conversationModel.token,
|
token = conversationModel.token,
|
||||||
|
threadId = threadId,
|
||||||
oldestMessageId = oldestMessageIdForNewChatBlock,
|
oldestMessageId = oldestMessageIdForNewChatBlock,
|
||||||
newestMessageId = newestMessageIdForNewChatBlock,
|
newestMessageId = newestMessageIdForNewChatBlock,
|
||||||
hasHistory = hasHistory
|
hasHistory = hasHistory
|
||||||
)
|
)
|
||||||
chatBlocksDao.upsertChatBlock(newChatBlock)
|
chatBlocksDao.upsertChatBlock(newChatBlock) // crash when no conversation thread exists!
|
||||||
|
|
||||||
updateBlocks(newChatBlock)
|
updateBlocks(newChatBlock)
|
||||||
return chatMessagesFromSyncToProcess
|
return chatMessagesFromSyncToProcess
|
||||||
@ -721,7 +721,11 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
var blockContainingQueriedMessage: ChatBlockEntity? = null
|
var blockContainingQueriedMessage: ChatBlockEntity? = null
|
||||||
if (queriedMessageId != null) {
|
if (queriedMessageId != null) {
|
||||||
val blocksContainingQueriedMessage =
|
val blocksContainingQueriedMessage =
|
||||||
chatBlocksDao.getChatBlocksContainingMessageId(internalConversationId, queriedMessageId.toLong())
|
chatBlocksDao.getChatBlocksContainingMessageId(
|
||||||
|
internalConversationId = internalConversationId,
|
||||||
|
threadId = threadId,
|
||||||
|
messageId = queriedMessageId.toLong()
|
||||||
|
)
|
||||||
|
|
||||||
val chatBlocks = blocksContainingQueriedMessage.first()
|
val chatBlocks = blocksContainingQueriedMessage.first()
|
||||||
if (chatBlocks.size > 1) {
|
if (chatBlocks.size > 1) {
|
||||||
@ -740,9 +744,10 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
private suspend fun updateBlocks(chatBlock: ChatBlockEntity): ChatBlockEntity? {
|
private suspend fun updateBlocks(chatBlock: ChatBlockEntity): ChatBlockEntity? {
|
||||||
val connectedChatBlocks =
|
val connectedChatBlocks =
|
||||||
chatBlocksDao.getConnectedChatBlocks(
|
chatBlocksDao.getConnectedChatBlocks(
|
||||||
internalConversationId,
|
internalConversationId = internalConversationId,
|
||||||
chatBlock.oldestMessageId,
|
threadId = threadId,
|
||||||
chatBlock.newestMessageId
|
oldestMessageId = chatBlock.oldestMessageId,
|
||||||
|
newestMessageId = chatBlock.newestMessageId
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
return if (connectedChatBlocks.size == 1) {
|
return if (connectedChatBlocks.size == 1) {
|
||||||
@ -769,7 +774,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
internalConversationId = internalConversationId,
|
internalConversationId = internalConversationId,
|
||||||
accountId = conversationModel.accountId,
|
accountId = conversationModel.accountId,
|
||||||
token = conversationModel.token,
|
token = conversationModel.token,
|
||||||
threadId = conversationModel.threadId,
|
threadId = threadId,
|
||||||
oldestMessageId = oldestIdFromDbChatBlocks,
|
oldestMessageId = oldestIdFromDbChatBlocks,
|
||||||
newestMessageId = newestIdFromDbChatBlocks,
|
newestMessageId = newestIdFromDbChatBlocks,
|
||||||
hasHistory = hasHistory
|
hasHistory = hasHistory
|
||||||
@ -793,7 +798,8 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
chatDao.getMessagesForConversationBeforeAndEqual(
|
chatDao.getMessagesForConversationBeforeAndEqual(
|
||||||
internalConversationId,
|
internalConversationId,
|
||||||
messageId,
|
messageId,
|
||||||
messageLimit
|
messageLimit,
|
||||||
|
threadId
|
||||||
).map {
|
).map {
|
||||||
it.map(ChatMessageEntity::asModel)
|
it.map(ChatMessageEntity::asModel)
|
||||||
}.first()
|
}.first()
|
||||||
@ -807,7 +813,8 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
chatDao.getMessagesForConversationBefore(
|
chatDao.getMessagesForConversationBefore(
|
||||||
internalConversationId,
|
internalConversationId,
|
||||||
messageId,
|
messageId,
|
||||||
messageLimit
|
messageLimit,
|
||||||
|
threadId
|
||||||
).map {
|
).map {
|
||||||
it.map(ChatMessageEntity::asModel)
|
it.map(ChatMessageEntity::asModel)
|
||||||
}.first()
|
}.first()
|
||||||
@ -870,7 +877,8 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
|
|
||||||
val sentMessage = chatDao.getTempMessageForConversation(
|
val sentMessage = chatDao.getTempMessageForConversation(
|
||||||
internalConversationId,
|
internalConversationId,
|
||||||
referenceId
|
referenceId,
|
||||||
|
threadId
|
||||||
).firstOrNull()
|
).firstOrNull()
|
||||||
|
|
||||||
sentMessage?.let {
|
sentMessage?.let {
|
||||||
@ -886,7 +894,8 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
|
|
||||||
val failedMessage = chatDao.getTempMessageForConversation(
|
val failedMessage = chatDao.getTempMessageForConversation(
|
||||||
internalConversationId,
|
internalConversationId,
|
||||||
referenceId
|
referenceId,
|
||||||
|
threadId
|
||||||
).firstOrNull()
|
).firstOrNull()
|
||||||
failedMessage?.let {
|
failedMessage?.let {
|
||||||
it.sendStatus = SendStatus.FAILED
|
it.sendStatus = SendStatus.FAILED
|
||||||
@ -909,7 +918,11 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
sendWithoutNotification: Boolean,
|
sendWithoutNotification: Boolean,
|
||||||
referenceId: String
|
referenceId: String
|
||||||
): Flow<Result<ChatMessage?>> {
|
): Flow<Result<ChatMessage?>> {
|
||||||
val messageToResend = chatDao.getTempMessageForConversation(internalConversationId, referenceId).firstOrNull()
|
val messageToResend = chatDao.getTempMessageForConversation(
|
||||||
|
internalConversationId,
|
||||||
|
referenceId,
|
||||||
|
threadId
|
||||||
|
).firstOrNull()
|
||||||
return if (messageToResend != null) {
|
return if (messageToResend != null) {
|
||||||
messageToResend.sendStatus = SendStatus.PENDING
|
messageToResend.sendStatus = SendStatus.PENDING
|
||||||
chatDao.updateChatMessage(messageToResend)
|
chatDao.updateChatMessage(messageToResend)
|
||||||
@ -958,8 +971,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
try {
|
try {
|
||||||
val messageToEdit = chatDao.getChatMessageForConversation(
|
val messageToEdit = chatDao.getChatMessageForConversation(
|
||||||
internalConversationId,
|
internalConversationId,
|
||||||
message.jsonMessageId
|
message.jsonMessageId.toLong()
|
||||||
.toLong()
|
|
||||||
).first()
|
).first()
|
||||||
messageToEdit.message = editedMessageText
|
messageToEdit.message = editedMessageText
|
||||||
chatDao.upsertChatMessage(messageToEdit)
|
chatDao.upsertChatMessage(messageToEdit)
|
||||||
@ -973,7 +985,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun sendUnsentChatMessages(credentials: String, url: String) {
|
override suspend fun sendUnsentChatMessages(credentials: String, url: String) {
|
||||||
val tempMessages = chatDao.getTempUnsentMessagesForConversation(internalConversationId).first()
|
val tempMessages = chatDao.getTempUnsentMessagesForConversation(internalConversationId, threadId).first()
|
||||||
tempMessages.sortedBy { it.internalId }.onEach {
|
tempMessages.sortedBy { it.internalId }.onEach {
|
||||||
sendChatMessage(
|
sendChatMessage(
|
||||||
credentials,
|
credentials,
|
||||||
|
@ -20,15 +20,17 @@ interface ChatBlocksDao {
|
|||||||
@Delete
|
@Delete
|
||||||
fun deleteChatBlocks(blocks: List<ChatBlockEntity>)
|
fun deleteChatBlocks(blocks: List<ChatBlockEntity>)
|
||||||
|
|
||||||
@Query(
|
// @Query(
|
||||||
"""
|
// """
|
||||||
SELECT *
|
// SELECT *
|
||||||
FROM ChatBlocks
|
// FROM ChatBlocks
|
||||||
WHERE internalConversationId in (:internalConversationId)
|
// WHERE internalConversationId in (:internalConversationId)
|
||||||
ORDER BY newestMessageId ASC
|
// ORDER BY newestMessageId ASC
|
||||||
"""
|
// """
|
||||||
)
|
// )
|
||||||
fun getChatBlocks(internalConversationId: String): Flow<List<ChatBlockEntity>>
|
// fun getChatBlocks(
|
||||||
|
// internalConversationId: String
|
||||||
|
// ): Flow<List<ChatBlockEntity>>
|
||||||
|
|
||||||
// @Query(
|
// @Query(
|
||||||
// """
|
// """
|
||||||
@ -50,18 +52,24 @@ interface ChatBlocksDao {
|
|||||||
SELECT *
|
SELECT *
|
||||||
FROM ChatBlocks
|
FROM ChatBlocks
|
||||||
WHERE internalConversationId in (:internalConversationId)
|
WHERE internalConversationId in (:internalConversationId)
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
AND oldestMessageId <= :messageId
|
AND oldestMessageId <= :messageId
|
||||||
AND newestMessageId >= :messageId
|
AND newestMessageId >= :messageId
|
||||||
ORDER BY newestMessageId ASC
|
ORDER BY newestMessageId ASC
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
fun getChatBlocksContainingMessageId(internalConversationId: String, messageId: Long): Flow<List<ChatBlockEntity?>>
|
fun getChatBlocksContainingMessageId(
|
||||||
|
internalConversationId: String,
|
||||||
|
threadId: Long?,
|
||||||
|
messageId: Long
|
||||||
|
): Flow<List<ChatBlockEntity?>>
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM ChatBlocks
|
FROM ChatBlocks
|
||||||
WHERE internalConversationId = :internalConversationId
|
WHERE internalConversationId = :internalConversationId
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
AND(
|
AND(
|
||||||
(oldestMessageId <= :oldestMessageId AND newestMessageId >= :oldestMessageId)
|
(oldestMessageId <= :oldestMessageId AND newestMessageId >= :oldestMessageId)
|
||||||
OR
|
OR
|
||||||
@ -74,20 +82,23 @@ interface ChatBlocksDao {
|
|||||||
)
|
)
|
||||||
fun getConnectedChatBlocks(
|
fun getConnectedChatBlocks(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
|
threadId: Long?,
|
||||||
oldestMessageId: Long,
|
oldestMessageId: Long,
|
||||||
newestMessageId: Long
|
newestMessageId: Long
|
||||||
): Flow<List<ChatBlockEntity>>
|
): Flow<List<ChatBlockEntity>>
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
|
||||||
suspend fun upsertChatBlock(chatBlock: ChatBlockEntity)
|
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
DELETE FROM ChatBlocks
|
SELECT MAX(newestMessageId) as max_items
|
||||||
WHERE internalConversationId LIKE :pattern
|
FROM ChatBlocks
|
||||||
|
WHERE internalConversationId = :internalConversationId
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
fun clearChatBlocksForUser(pattern: String)
|
fun getNewestMessageIdFromChatBlocks(internalConversationId: String, threadId: Long?): Long
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun upsertChatBlock(chatBlock: ChatBlockEntity)
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
|
@ -18,15 +18,19 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
@Dao
|
@Dao
|
||||||
@Suppress("Detekt.TooManyFunctions")
|
@Suppress("Detekt.TooManyFunctions")
|
||||||
interface ChatMessagesDao {
|
interface ChatMessagesDao {
|
||||||
@Query(
|
// @Query(
|
||||||
"""
|
// """
|
||||||
SELECT MAX(id) as max_items
|
// SELECT MAX(id) as max_items
|
||||||
FROM ChatMessages
|
// FROM ChatMessages
|
||||||
WHERE internalConversationId = :internalConversationId
|
// WHERE internalConversationId = :internalConversationId
|
||||||
AND isTemporary = 0
|
// AND isTemporary = 0
|
||||||
"""
|
// AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
)
|
// """
|
||||||
fun getNewestMessageId(internalConversationId: String): Long
|
// )
|
||||||
|
// fun getNewestMessageId(
|
||||||
|
// internalConversationId: String,
|
||||||
|
// threadId: Long?
|
||||||
|
// ): Long
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
@ -45,10 +49,11 @@ interface ChatMessagesDao {
|
|||||||
FROM ChatMessages
|
FROM ChatMessages
|
||||||
WHERE internalConversationId = :internalConversationId
|
WHERE internalConversationId = :internalConversationId
|
||||||
AND isTemporary = 1
|
AND isTemporary = 1
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
ORDER BY timestamp DESC, id DESC
|
ORDER BY timestamp DESC, id DESC
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
fun getTempMessagesForConversation(internalConversationId: String): Flow<List<ChatMessageEntity>>
|
fun getTempMessagesForConversation(internalConversationId: String, threadId: Long?): Flow<List<ChatMessageEntity>>
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
@ -57,10 +62,14 @@ interface ChatMessagesDao {
|
|||||||
WHERE internalConversationId = :internalConversationId
|
WHERE internalConversationId = :internalConversationId
|
||||||
AND isTemporary = 1
|
AND isTemporary = 1
|
||||||
AND sendStatus != 'SENT_PENDING_ACK'
|
AND sendStatus != 'SENT_PENDING_ACK'
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
ORDER BY timestamp DESC, id DESC
|
ORDER BY timestamp DESC, id DESC
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
fun getTempUnsentMessagesForConversation(internalConversationId: String): Flow<List<ChatMessageEntity>>
|
fun getTempUnsentMessagesForConversation(
|
||||||
|
internalConversationId: String,
|
||||||
|
threadId: Long?
|
||||||
|
): Flow<List<ChatMessageEntity>>
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
@ -69,10 +78,15 @@ interface ChatMessagesDao {
|
|||||||
WHERE internalConversationId = :internalConversationId
|
WHERE internalConversationId = :internalConversationId
|
||||||
AND referenceId = :referenceId
|
AND referenceId = :referenceId
|
||||||
AND isTemporary = 1
|
AND isTemporary = 1
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
ORDER BY timestamp DESC, id DESC
|
ORDER BY timestamp DESC, id DESC
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
fun getTempMessageForConversation(internalConversationId: String, referenceId: String): Flow<ChatMessageEntity?>
|
fun getTempMessageForConversation(
|
||||||
|
internalConversationId: String,
|
||||||
|
referenceId: String,
|
||||||
|
threadId: Long?
|
||||||
|
): Flow<ChatMessageEntity?>
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun upsertChatMessages(chatMessages: List<ChatMessageEntity>)
|
suspend fun upsertChatMessages(chatMessages: List<ChatMessageEntity>)
|
||||||
@ -84,7 +98,8 @@ interface ChatMessagesDao {
|
|||||||
"""
|
"""
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM ChatMessages
|
FROM ChatMessages
|
||||||
WHERE internalConversationId = :internalConversationId AND id = :messageId
|
WHERE internalConversationId = :internalConversationId
|
||||||
|
AND id = :messageId
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
fun getChatMessageForConversation(internalConversationId: String, messageId: Long): Flow<ChatMessageEntity>
|
fun getChatMessageForConversation(internalConversationId: String, messageId: Long): Flow<ChatMessageEntity>
|
||||||
@ -126,10 +141,15 @@ interface ChatMessagesDao {
|
|||||||
FROM ChatMessages
|
FROM ChatMessages
|
||||||
WHERE internalConversationId = :internalConversationId AND id >= :messageId
|
WHERE internalConversationId = :internalConversationId AND id >= :messageId
|
||||||
AND isTemporary = 0
|
AND isTemporary = 0
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
ORDER BY timestamp ASC, id ASC
|
ORDER BY timestamp ASC, id ASC
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
fun getMessagesForConversationSince(internalConversationId: String, messageId: Long): Flow<List<ChatMessageEntity>>
|
fun getMessagesForConversationSince(
|
||||||
|
internalConversationId: String,
|
||||||
|
messageId: Long,
|
||||||
|
threadId: Long?
|
||||||
|
): Flow<List<ChatMessageEntity>>
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
@ -138,6 +158,7 @@ interface ChatMessagesDao {
|
|||||||
WHERE internalConversationId = :internalConversationId
|
WHERE internalConversationId = :internalConversationId
|
||||||
AND isTemporary = 0
|
AND isTemporary = 0
|
||||||
AND id < :messageId
|
AND id < :messageId
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
ORDER BY timestamp DESC, id DESC
|
ORDER BY timestamp DESC, id DESC
|
||||||
LIMIT :limit
|
LIMIT :limit
|
||||||
"""
|
"""
|
||||||
@ -145,7 +166,8 @@ interface ChatMessagesDao {
|
|||||||
fun getMessagesForConversationBefore(
|
fun getMessagesForConversationBefore(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
messageId: Long,
|
messageId: Long,
|
||||||
limit: Int
|
limit: Int,
|
||||||
|
threadId: Long?
|
||||||
): Flow<List<ChatMessageEntity>>
|
): Flow<List<ChatMessageEntity>>
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
@ -155,6 +177,7 @@ interface ChatMessagesDao {
|
|||||||
WHERE internalConversationId = :internalConversationId
|
WHERE internalConversationId = :internalConversationId
|
||||||
AND isTemporary = 0
|
AND isTemporary = 0
|
||||||
AND id <= :messageId
|
AND id <= :messageId
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
ORDER BY timestamp DESC, id DESC
|
ORDER BY timestamp DESC, id DESC
|
||||||
LIMIT :limit
|
LIMIT :limit
|
||||||
"""
|
"""
|
||||||
@ -162,7 +185,8 @@ interface ChatMessagesDao {
|
|||||||
fun getMessagesForConversationBeforeAndEqual(
|
fun getMessagesForConversationBeforeAndEqual(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
messageId: Long,
|
messageId: Long,
|
||||||
limit: Int
|
limit: Int,
|
||||||
|
threadId: Long?
|
||||||
): Flow<List<ChatMessageEntity>>
|
): Flow<List<ChatMessageEntity>>
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
@ -171,10 +195,16 @@ interface ChatMessagesDao {
|
|||||||
FROM ChatMessages
|
FROM ChatMessages
|
||||||
WHERE internalConversationId = :internalConversationId
|
WHERE internalConversationId = :internalConversationId
|
||||||
AND isTemporary = 0
|
AND isTemporary = 0
|
||||||
|
AND (:threadId IS NULL OR threadId = :threadId)
|
||||||
AND id BETWEEN :newestMessageId AND :oldestMessageId
|
AND id BETWEEN :newestMessageId AND :oldestMessageId
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
fun getCountBetweenMessageIds(internalConversationId: String, oldestMessageId: Long, newestMessageId: Long): Int
|
fun getCountBetweenMessageIds(
|
||||||
|
internalConversationId: String,
|
||||||
|
oldestMessageId: Long,
|
||||||
|
newestMessageId: Long,
|
||||||
|
threadId: Long?
|
||||||
|
): Int
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
|
@ -19,8 +19,9 @@ fun ChatMessageJson.asEntity(accountId: Long) =
|
|||||||
accountId = accountId,
|
accountId = accountId,
|
||||||
id = id,
|
id = id,
|
||||||
internalConversationId = "$accountId@$token",
|
internalConversationId = "$accountId@$token",
|
||||||
topmostParentId = topmostParentId,
|
threadId = threadId,
|
||||||
childrenCount = childrenCount,
|
isThread = hasThread,
|
||||||
|
// childrenCount = childrenCount,
|
||||||
message = message!!,
|
message = message!!,
|
||||||
token = token!!,
|
token = token!!,
|
||||||
actorType = actorType!!,
|
actorType = actorType!!,
|
||||||
@ -50,8 +51,9 @@ fun ChatMessageEntity.asModel() =
|
|||||||
jsonMessageId = id.toInt(),
|
jsonMessageId = id.toInt(),
|
||||||
message = message,
|
message = message,
|
||||||
token = token,
|
token = token,
|
||||||
topmostParentId = topmostParentId,
|
threadId = threadId,
|
||||||
childrenCount = childrenCount,
|
isThread = isThread,
|
||||||
|
// childrenCount = childrenCount,
|
||||||
actorType = actorType,
|
actorType = actorType,
|
||||||
actorId = actorId,
|
actorId = actorId,
|
||||||
actorDisplayName = actorDisplayName,
|
actorDisplayName = actorDisplayName,
|
||||||
@ -82,8 +84,9 @@ fun ChatMessageJson.asModel() =
|
|||||||
jsonMessageId = id.toInt(),
|
jsonMessageId = id.toInt(),
|
||||||
message = message,
|
message = message,
|
||||||
token = token,
|
token = token,
|
||||||
topmostParentId = topmostParentId,
|
threadId = threadId,
|
||||||
childrenCount = childrenCount,
|
isThread = hasThread,
|
||||||
|
// childrenCount = childrenCount,
|
||||||
actorType = actorType,
|
actorType = actorType,
|
||||||
actorId = actorId,
|
actorId = actorId,
|
||||||
actorDisplayName = actorDisplayName,
|
actorDisplayName = actorDisplayName,
|
||||||
|
@ -31,7 +31,7 @@ import androidx.room.PrimaryKey
|
|||||||
data class ChatBlockEntity(
|
data class ChatBlockEntity(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
@ColumnInfo(name = "id") var id: Long = 0,
|
@ColumnInfo(name = "id") var id: Long = 0,
|
||||||
// accountId@token(@threadId)
|
// accountId@token
|
||||||
@ColumnInfo(name = "internalConversationId") var internalConversationId: String,
|
@ColumnInfo(name = "internalConversationId") var internalConversationId: String,
|
||||||
@ColumnInfo(name = "accountId") var accountId: Long? = null,
|
@ColumnInfo(name = "accountId") var accountId: Long? = null,
|
||||||
@ColumnInfo(name = "token") var token: String?,
|
@ColumnInfo(name = "token") var token: String?,
|
||||||
|
@ -41,7 +41,8 @@ data class ChatMessageEntity(
|
|||||||
@ColumnInfo(name = "id") var id: Long = 0,
|
@ColumnInfo(name = "id") var id: Long = 0,
|
||||||
// accountId@roomtoken
|
// accountId@roomtoken
|
||||||
@ColumnInfo(name = "internalConversationId") var internalConversationId: String,
|
@ColumnInfo(name = "internalConversationId") var internalConversationId: String,
|
||||||
@ColumnInfo(name = "topmostParentId") var topmostParentId: Long? = null,
|
@ColumnInfo(name = "threadId") var threadId: Long? = null,
|
||||||
|
@ColumnInfo(name = "isThread") var isThread: Boolean = false,
|
||||||
@ColumnInfo(name = "actorDisplayName") var actorDisplayName: String,
|
@ColumnInfo(name = "actorDisplayName") var actorDisplayName: String,
|
||||||
@ColumnInfo(name = "message") var message: String,
|
@ColumnInfo(name = "message") var message: String,
|
||||||
|
|
||||||
|
@ -49,8 +49,6 @@ data class ConversationEntity(
|
|||||||
// exactly what we want for this case.
|
// exactly what we want for this case.
|
||||||
@ColumnInfo(name = "token") var token: String,
|
@ColumnInfo(name = "token") var token: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "threadId") var threadId: Long? = null,
|
|
||||||
|
|
||||||
@ColumnInfo(name = "displayName") var displayName: String,
|
@ColumnInfo(name = "displayName") var displayName: String,
|
||||||
|
|
||||||
// OTHER ATTRIBUTES IN ALPHABETICAL ORDER
|
// OTHER ATTRIBUTES IN ALPHABETICAL ORDER
|
||||||
|
@ -350,18 +350,18 @@ object Migrations {
|
|||||||
|
|
||||||
db.execSQL(
|
db.execSQL(
|
||||||
"ALTER TABLE ChatMessages " +
|
"ALTER TABLE ChatMessages " +
|
||||||
"ADD COLUMN topmostParentId INTEGER DEFAULT NULL;"
|
"ADD COLUMN threadId INTEGER DEFAULT NULL;"
|
||||||
)
|
)
|
||||||
|
|
||||||
db.execSQL(
|
db.execSQL(
|
||||||
"ALTER TABLE ChatMessages " +
|
"ALTER TABLE ChatMessages " +
|
||||||
"ADD COLUMN childrenCount INTEGER DEFAULT 0;"
|
"ADD COLUMN isThread BOOLEAN DEFAULT 0;"
|
||||||
)
|
)
|
||||||
|
|
||||||
db.execSQL(
|
// db.execSQL(
|
||||||
"ALTER TABLE Conversations " +
|
// "ALTER TABLE ChatMessages " +
|
||||||
"ADD COLUMN threadId INTEGER DEFAULT NULL;"
|
// "ADD COLUMN childrenCount INTEGER DEFAULT 0;"
|
||||||
)
|
// )
|
||||||
|
|
||||||
// Foreign key constraints are not active during migration.
|
// Foreign key constraints are not active during migration.
|
||||||
// At least db.execSQL("PRAGMA foreign_keys=ON;") etc did not help.
|
// At least db.execSQL("PRAGMA foreign_keys=ON;") etc did not help.
|
||||||
|
@ -17,7 +17,6 @@ class ConversationModel(
|
|||||||
var internalId: String,
|
var internalId: String,
|
||||||
var accountId: Long,
|
var accountId: Long,
|
||||||
var token: String,
|
var token: String,
|
||||||
var threadId: Long? = null,
|
|
||||||
var name: String,
|
var name: String,
|
||||||
var displayName: String,
|
var displayName: String,
|
||||||
var description: String,
|
var description: String,
|
||||||
|
@ -19,8 +19,13 @@ import kotlinx.parcelize.Parcelize
|
|||||||
data class ChatMessageJson(
|
data class ChatMessageJson(
|
||||||
@JsonField(name = ["id"]) var id: Long = 0,
|
@JsonField(name = ["id"]) var id: Long = 0,
|
||||||
@JsonField(name = ["token"]) var token: String? = null,
|
@JsonField(name = ["token"]) var token: String? = null,
|
||||||
@JsonField(name = ["topmostParentId"]) var topmostParentId: Long? = null,
|
@JsonField(name = ["threadId"]) var threadId: Long? = null,
|
||||||
@JsonField(name = ["childrenCount"]) var childrenCount: Long? = 0,
|
|
||||||
|
// Be aware that variables with "is" at the beginning will lead to the error:
|
||||||
|
// "@JsonField annotation can only be used on private fields if both getter and setter are present."
|
||||||
|
// Instead, name it with "has" at the beginning: isThread -> hasThread
|
||||||
|
@JsonField(name = ["isThread"]) var hasThread: Boolean = false,
|
||||||
|
// @JsonField(name = ["childrenCount"]) var childrenCount: Long? = 0,
|
||||||
@JsonField(name = ["actorType"]) var actorType: String? = null,
|
@JsonField(name = ["actorType"]) var actorType: String? = null,
|
||||||
@JsonField(name = ["actorId"]) var actorId: String? = null,
|
@JsonField(name = ["actorId"]) var actorId: String? = null,
|
||||||
@JsonField(name = ["actorDisplayName"]) var actorDisplayName: String? = null,
|
@JsonField(name = ["actorDisplayName"]) var actorDisplayName: String? = null,
|
||||||
|
@ -28,9 +28,6 @@ data class Conversation(
|
|||||||
@JsonField(name = ["token"])
|
@JsonField(name = ["token"])
|
||||||
var token: String = "",
|
var token: String = "",
|
||||||
|
|
||||||
@JsonField(name = ["threadId"])
|
|
||||||
var threadId: Long? = null,
|
|
||||||
|
|
||||||
@JsonField(name = ["name"])
|
@JsonField(name = ["name"])
|
||||||
var name: String = "",
|
var name: String = "",
|
||||||
|
|
||||||
|
@ -101,7 +101,10 @@ class ReactionsRepositoryImpl @Inject constructor(
|
|||||||
val internalConversationId = "$accountId@$roomToken"
|
val internalConversationId = "$accountId@$roomToken"
|
||||||
val emoji = model.emoji
|
val emoji = model.emoji
|
||||||
|
|
||||||
val message = dao.getChatMessageForConversation(internalConversationId, id).first()
|
val message = dao.getChatMessageForConversation(
|
||||||
|
internalConversationId,
|
||||||
|
id
|
||||||
|
).first()
|
||||||
|
|
||||||
// 2. Check state of entity, create params as needed
|
// 2. Check state of entity, create params as needed
|
||||||
if (message.reactions == null) {
|
if (message.reactions == null) {
|
||||||
|
@ -23,21 +23,30 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
|
||||||
class DummyChatMessagesDaoImpl : ChatMessagesDao {
|
class DummyChatMessagesDaoImpl : ChatMessagesDao {
|
||||||
override fun getNewestMessageId(internalConversationId: String): Long = 0L
|
// override fun getNewestMessageId(
|
||||||
|
// internalConversationId: String,
|
||||||
|
// threadId: Long?
|
||||||
|
// ): Long = 0L
|
||||||
|
|
||||||
override fun getMessagesForConversation(internalConversationId: String): Flow<List<ChatMessageEntity>> = flowOf()
|
override fun getMessagesForConversation(internalConversationId: String): Flow<List<ChatMessageEntity>> = flowOf()
|
||||||
|
|
||||||
override fun getTempMessagesForConversation(internalConversationId: String): Flow<List<ChatMessageEntity>> =
|
override fun getTempMessagesForConversation(
|
||||||
flowOf()
|
internalConversationId: String,
|
||||||
|
threadId: Long?
|
||||||
|
): Flow<List<ChatMessageEntity>> = flowOf()
|
||||||
|
|
||||||
override fun getTempUnsentMessagesForConversation(internalConversationId: String): Flow<List<ChatMessageEntity>> {
|
override fun getTempUnsentMessagesForConversation(
|
||||||
|
internalConversationId: String,
|
||||||
|
threadId: Long?
|
||||||
|
): Flow<List<ChatMessageEntity>> {
|
||||||
// nothing to return here as long this class is only used for the Search window
|
// nothing to return here as long this class is only used for the Search window
|
||||||
return flowOf()
|
return flowOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTempMessageForConversation(
|
override fun getTempMessageForConversation(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
referenceId: String
|
referenceId: String,
|
||||||
|
threadId: Long?
|
||||||
): Flow<ChatMessageEntity> = flowOf()
|
): Flow<ChatMessageEntity> = flowOf()
|
||||||
|
|
||||||
override suspend fun upsertChatMessages(chatMessages: List<ChatMessageEntity>) { /* */ }
|
override suspend fun upsertChatMessages(chatMessages: List<ChatMessageEntity>) { /* */ }
|
||||||
@ -59,25 +68,29 @@ class DummyChatMessagesDaoImpl : ChatMessagesDao {
|
|||||||
|
|
||||||
override fun getMessagesForConversationSince(
|
override fun getMessagesForConversationSince(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
messageId: Long
|
messageId: Long,
|
||||||
|
threadId: Long?
|
||||||
): Flow<List<ChatMessageEntity>> = flowOf()
|
): Flow<List<ChatMessageEntity>> = flowOf()
|
||||||
|
|
||||||
override fun getMessagesForConversationBefore(
|
override fun getMessagesForConversationBefore(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
messageId: Long,
|
messageId: Long,
|
||||||
limit: Int
|
limit: Int,
|
||||||
|
threadId: Long?
|
||||||
): Flow<List<ChatMessageEntity>> = flowOf()
|
): Flow<List<ChatMessageEntity>> = flowOf()
|
||||||
|
|
||||||
override fun getMessagesForConversationBeforeAndEqual(
|
override fun getMessagesForConversationBeforeAndEqual(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
messageId: Long,
|
messageId: Long,
|
||||||
limit: Int
|
limit: Int,
|
||||||
|
threadId: Long?
|
||||||
): Flow<List<ChatMessageEntity>> = flowOf()
|
): Flow<List<ChatMessageEntity>> = flowOf()
|
||||||
|
|
||||||
override fun getCountBetweenMessageIds(
|
override fun getCountBetweenMessageIds(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
oldestMessageId: Long,
|
oldestMessageId: Long,
|
||||||
newestMessageId: Long
|
newestMessageId: Long,
|
||||||
|
threadId: Long?
|
||||||
): Int = 0
|
): Int = 0
|
||||||
|
|
||||||
override fun clearAllMessagesForUser(pattern: String) { /* */ }
|
override fun clearAllMessagesForUser(pattern: String) { /* */ }
|
||||||
@ -192,22 +205,28 @@ class DummyConversationDaoImpl : ConversationsDao {
|
|||||||
class DummyChatBlocksDaoImpl : ChatBlocksDao {
|
class DummyChatBlocksDaoImpl : ChatBlocksDao {
|
||||||
override fun deleteChatBlocks(blocks: List<ChatBlockEntity>) { /* */ }
|
override fun deleteChatBlocks(blocks: List<ChatBlockEntity>) { /* */ }
|
||||||
|
|
||||||
override fun getChatBlocks(internalConversationId: String): Flow<List<ChatBlockEntity>> = flowOf()
|
// override fun getChatBlocks(
|
||||||
|
// internalConversationId: String
|
||||||
|
// ): Flow<List<ChatBlockEntity>> = flowOf()
|
||||||
|
|
||||||
override fun getChatBlocksContainingMessageId(
|
override fun getChatBlocksContainingMessageId(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
|
threadId: Long?,
|
||||||
messageId: Long
|
messageId: Long
|
||||||
): Flow<List<ChatBlockEntity?>> = flowOf()
|
): Flow<List<ChatBlockEntity?>> = flowOf()
|
||||||
|
|
||||||
override fun getConnectedChatBlocks(
|
override fun getConnectedChatBlocks(
|
||||||
internalConversationId: String,
|
internalConversationId: String,
|
||||||
|
threadId: Long?,
|
||||||
oldestMessageId: Long,
|
oldestMessageId: Long,
|
||||||
newestMessageId: Long
|
newestMessageId: Long
|
||||||
): Flow<List<ChatBlockEntity>> = flowOf()
|
): Flow<List<ChatBlockEntity>> = flowOf()
|
||||||
|
|
||||||
|
override fun getNewestMessageIdFromChatBlocks(internalConversationId: String, threadId: Long?): Long = 0L
|
||||||
|
|
||||||
override suspend fun upsertChatBlock(chatBlock: ChatBlockEntity) { /* */ }
|
override suspend fun upsertChatBlock(chatBlock: ChatBlockEntity) { /* */ }
|
||||||
|
|
||||||
override fun clearChatBlocksForUser(pattern: String) { /* */ }
|
// override fun clearChatBlocksForUser(pattern: String) { /* */ }
|
||||||
|
|
||||||
override fun deleteChatBlocksOlderThan(internalConversationId: String, messageId: Long) { /* */ }
|
override fun deleteChatBlocksOlderThan(internalConversationId: String, messageId: Long) { /* */ }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user