mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 03:29:28 +01:00
implement lastCommonRead handling
contains one workaround for now, see TODO in updateUiForLastCommonRead method Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
5bccdada7c
commit
0390c93ed2
@ -2,7 +2,7 @@
|
|||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 10,
|
"version": 10,
|
||||||
"identityHash": "234cdb754d42d9ebf2349763a58a4578",
|
"identityHash": "1b97b7e937102e4087f8534f1204fe94",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "User",
|
"tableName": "User",
|
||||||
@ -138,7 +138,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "Conversations",
|
"tableName": "Conversations",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER, `token` TEXT, `name` TEXT, `displayName` TEXT, `description` TEXT, `type` TEXT, `lastPing` INTEGER NOT NULL, `participantType` TEXT, `hasPassword` INTEGER NOT NULL, `sessionId` TEXT, `actorId` TEXT, `actorType` TEXT, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, `unreadMention` INTEGER NOT NULL, `lastMessageJson` TEXT, `objectType` TEXT, `notificationLevel` TEXT, `readOnly` TEXT, `lobbyState` TEXT, `lobbyTimer` INTEGER, `lastReadMessage` INTEGER NOT NULL, `hasCall` INTEGER NOT NULL, `callFlag` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `canLeaveConversation` INTEGER, `canDeleteConversation` INTEGER, `unreadMentionDirect` INTEGER, `notificationCalls` INTEGER, `permissions` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `status` TEXT, `statusIcon` TEXT, `statusMessage` TEXT, `statusClearAt` INTEGER, `callRecording` INTEGER NOT NULL, `avatarVersion` TEXT, `isCustomAvatar` INTEGER, `callStartTime` INTEGER, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER, `token` TEXT, `name` TEXT, `displayName` TEXT, `description` TEXT, `type` TEXT, `lastPing` INTEGER NOT NULL, `participantType` TEXT, `hasPassword` INTEGER NOT NULL, `sessionId` TEXT, `actorId` TEXT, `actorType` TEXT, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, `unreadMention` INTEGER NOT NULL, `lastMessageJson` TEXT, `objectType` TEXT, `notificationLevel` TEXT, `readOnly` TEXT, `lobbyState` TEXT, `lobbyTimer` INTEGER, `lastReadMessage` INTEGER NOT NULL, `lastCommonReadMessage` INTEGER NOT NULL, `hasCall` INTEGER NOT NULL, `callFlag` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `canLeaveConversation` INTEGER, `canDeleteConversation` INTEGER, `unreadMentionDirect` INTEGER, `notificationCalls` INTEGER, `permissions` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `status` TEXT, `statusIcon` TEXT, `statusMessage` TEXT, `statusClearAt` INTEGER, `callRecording` INTEGER NOT NULL, `avatarVersion` TEXT, `isCustomAvatar` INTEGER, `callStartTime` INTEGER, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "internalId",
|
"fieldPath": "internalId",
|
||||||
@ -284,6 +284,12 @@
|
|||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastCommonReadMessage",
|
||||||
|
"columnName": "lastCommonReadMessage",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "hasCall",
|
"fieldPath": "hasCall",
|
||||||
"columnName": "hasCall",
|
"columnName": "hasCall",
|
||||||
@ -673,7 +679,7 @@
|
|||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"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, '234cdb754d42d9ebf2349763a58a4578')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1b97b7e937102e4087f8534f1204fe94')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -834,6 +834,14 @@ class ChatActivity :
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.lifecycleScope.launch {
|
||||||
|
chatViewModel.getLastCommonReadFlow
|
||||||
|
.onEach {
|
||||||
|
updateReadStatusOfAllMessages(it)
|
||||||
|
}
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
chatViewModel.reactionDeletedViewState.observe(this) { state ->
|
chatViewModel.reactionDeletedViewState.observe(this) { state ->
|
||||||
when (state) {
|
when (state) {
|
||||||
is ChatViewModel.ReactionDeletedSuccessState -> {
|
is ChatViewModel.ReactionDeletedSuccessState -> {
|
||||||
@ -2526,6 +2534,7 @@ class ChatActivity :
|
|||||||
updateReadStatusOfMessage(message, it)
|
updateReadStatusOfMessage(message, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
adapter!!.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ interface ChatMessageRepository : LifecycleAwareManager {
|
|||||||
|
|
||||||
val updateMessageFlow: Flow<ChatMessage>
|
val updateMessageFlow: Flow<ChatMessage>
|
||||||
|
|
||||||
|
val lastCommonReadFlow: Flow<Int>
|
||||||
|
|
||||||
fun setData(
|
fun setData(
|
||||||
conversationModel: ConversationModel,
|
conversationModel: ConversationModel,
|
||||||
credentials: String,
|
credentials: String,
|
||||||
|
@ -30,6 +30,7 @@ import io.reactivex.schedulers.Schedulers
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
@ -72,6 +73,13 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
private val _updateMessageFlow:
|
private val _updateMessageFlow:
|
||||||
MutableSharedFlow<ChatMessage> = MutableSharedFlow()
|
MutableSharedFlow<ChatMessage> = MutableSharedFlow()
|
||||||
|
|
||||||
|
override val lastCommonReadFlow:
|
||||||
|
Flow<Int>
|
||||||
|
get() = _lastCommonReadFlow
|
||||||
|
|
||||||
|
private val _lastCommonReadFlow:
|
||||||
|
MutableSharedFlow<Int> = MutableSharedFlow()
|
||||||
|
|
||||||
private var newXChatLastCommonRead: Int? = null
|
private var newXChatLastCommonRead: Int? = null
|
||||||
private var itIsPaused = false
|
private var itIsPaused = false
|
||||||
private val scope = CoroutineScope(Dispatchers.IO)
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
@ -96,6 +104,8 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
scope.launch {
|
scope.launch {
|
||||||
Log.d(TAG, "---- loadInitialMessages ------------")
|
Log.d(TAG, "---- loadInitialMessages ------------")
|
||||||
|
|
||||||
|
newXChatLastCommonRead = conversationModel.lastCommonReadMessage
|
||||||
|
|
||||||
val fieldMap = getFieldMap(
|
val fieldMap = getFieldMap(
|
||||||
lookIntoFuture = false,
|
lookIntoFuture = false,
|
||||||
includeLastKnown = true,
|
includeLastKnown = true,
|
||||||
@ -113,10 +123,24 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
internalConversationId,
|
internalConversationId,
|
||||||
chatDao.getNewestMessageId(internalConversationId)
|
chatDao.getNewestMessageId(internalConversationId)
|
||||||
)
|
)
|
||||||
|
updateUiForLastCommonRead()
|
||||||
|
|
||||||
initMessagePolling()
|
initMessagePolling()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateUiForLastCommonRead(){
|
||||||
|
scope.launch {
|
||||||
|
// TODO improve...
|
||||||
|
// delay is a dirty workaround to make sure messages are added to adapter on initial load before setting
|
||||||
|
// their read status.
|
||||||
|
// This workaround causes that the checkmarks seem to switch whenever sending a message
|
||||||
|
delay(200)
|
||||||
|
newXChatLastCommonRead?.let {
|
||||||
|
_lastCommonReadFlow.emit(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun loadMoreMessages(
|
override fun loadMoreMessages(
|
||||||
beforeMessageId: Long,
|
beforeMessageId: Long,
|
||||||
roomToken: String,
|
roomToken: String,
|
||||||
@ -141,6 +165,7 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
showLast100MessagesBefore(internalConversationId, beforeMessageId)
|
showLast100MessagesBefore(internalConversationId, beforeMessageId)
|
||||||
|
updateUiForLastCommonRead()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initMessagePolling(): Job =
|
override fun initMessagePolling(): Job =
|
||||||
@ -174,6 +199,8 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
_messageFlow.emit(pair)
|
_messageFlow.emit(pair)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateUiForLastCommonRead()
|
||||||
|
|
||||||
// Process read status if not null
|
// Process read status if not null
|
||||||
// val lastKnown = datastore.getLastKnownId(internalConversationId, 0)
|
// val lastKnown = datastore.getLastKnownId(internalConversationId, 0)
|
||||||
// list = list.map { chatMessage ->
|
// list = list.map { chatMessage ->
|
||||||
@ -245,9 +272,9 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
fieldMap["lastKnownMessageId"] = lastKnown
|
fieldMap["lastKnownMessageId"] = lastKnown
|
||||||
}
|
}
|
||||||
|
|
||||||
// newXChatLastCommonRead?.let {
|
newXChatLastCommonRead?.let {
|
||||||
// fieldMap["lastCommonReadId"] = if (it > 0) it else lastKnown
|
fieldMap["lastCommonReadId"] = it
|
||||||
// }
|
}
|
||||||
|
|
||||||
fieldMap["timeout"] = if (lookIntoFuture) 30 else 0
|
fieldMap["timeout"] = if (lookIntoFuture) 30 else 0
|
||||||
fieldMap["limit"] = 100
|
fieldMap["limit"] = 100
|
||||||
@ -291,26 +318,13 @@ class OfflineFirstChatRepository @Inject constructor(
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
// .timeout(3, TimeUnit.SECONDS)
|
// .timeout(3, TimeUnit.SECONDS)
|
||||||
.map {
|
.map { it ->
|
||||||
when (it.code()) {
|
when (it.code()) {
|
||||||
HTTP_CODE_OK -> {
|
HTTP_CODE_OK -> {
|
||||||
Log.d(TAG, "getMessagesFromServer HTTP_CODE_OK")
|
Log.d(TAG, "getMessagesFromServer HTTP_CODE_OK")
|
||||||
// newXChatLastCommonRead = it.headers()["X-Chat-Last-Common-Read"]?.let {
|
newXChatLastCommonRead = it.headers()["X-Chat-Last-Common-Read"]?.let {
|
||||||
// Integer.parseInt(it)
|
Integer.parseInt(it)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// val xChatLastGivenHeader: String? = it.headers()["X-Chat-Last-Given"]
|
|
||||||
// val lastKnownId = if (it.headers().size > 0 &&
|
|
||||||
// xChatLastGivenHeader?.isNotEmpty() == true
|
|
||||||
// ) {
|
|
||||||
// xChatLastGivenHeader.toInt()
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // if (lastKnownId > 0) {
|
|
||||||
// datastore.saveLastKnownId(internalConversationId, lastKnownId)
|
|
||||||
// // }
|
|
||||||
|
|
||||||
return@map Pair(
|
return@map Pair(
|
||||||
HTTP_CODE_OK,
|
HTTP_CODE_OK,
|
||||||
|
@ -120,6 +120,8 @@ class ChatViewModel @Inject constructor(
|
|||||||
|
|
||||||
val getUpdateMessageFlow = chatRepository.updateMessageFlow
|
val getUpdateMessageFlow = chatRepository.updateMessageFlow
|
||||||
|
|
||||||
|
val getLastCommonReadFlow = chatRepository.lastCommonReadFlow
|
||||||
|
|
||||||
val getConversationFlow = conversationRepository.conversationFlow
|
val getConversationFlow = conversationRepository.conversationFlow
|
||||||
.onEach {
|
.onEach {
|
||||||
_getRoomViewState.value = GetRoomSuccessState
|
_getRoomViewState.value = GetRoomSuccessState
|
||||||
|
@ -38,6 +38,7 @@ fun ConversationModel.asEntity() =
|
|||||||
lobbyState = lobbyState,
|
lobbyState = lobbyState,
|
||||||
lobbyTimer = lobbyTimer,
|
lobbyTimer = lobbyTimer,
|
||||||
lastReadMessage = lastReadMessage,
|
lastReadMessage = lastReadMessage,
|
||||||
|
lastCommonReadMessage = lastCommonReadMessage,
|
||||||
hasCall = hasCall,
|
hasCall = hasCall,
|
||||||
callFlag = callFlag,
|
callFlag = callFlag,
|
||||||
canStartCall = canStartCall,
|
canStartCall = canStartCall,
|
||||||
@ -86,6 +87,7 @@ fun ConversationEntity.asModel() =
|
|||||||
lobbyState = lobbyState,
|
lobbyState = lobbyState,
|
||||||
lobbyTimer = lobbyTimer,
|
lobbyTimer = lobbyTimer,
|
||||||
lastReadMessage = lastReadMessage,
|
lastReadMessage = lastReadMessage,
|
||||||
|
lastCommonReadMessage = lastCommonReadMessage,
|
||||||
hasCall = hasCall,
|
hasCall = hasCall,
|
||||||
callFlag = callFlag,
|
callFlag = callFlag,
|
||||||
canStartCall = canStartCall,
|
canStartCall = canStartCall,
|
||||||
@ -134,6 +136,7 @@ fun Conversation.asEntity(accountId: Long) =
|
|||||||
lobbyState = lobbyState,
|
lobbyState = lobbyState,
|
||||||
lobbyTimer = lobbyTimer,
|
lobbyTimer = lobbyTimer,
|
||||||
lastReadMessage = lastReadMessage,
|
lastReadMessage = lastReadMessage,
|
||||||
|
lastCommonReadMessage = lastCommonReadMessage,
|
||||||
hasCall = hasCall,
|
hasCall = hasCall,
|
||||||
callFlag = callFlag,
|
callFlag = callFlag,
|
||||||
canStartCall = canStartCall,
|
canStartCall = canStartCall,
|
||||||
|
@ -68,6 +68,7 @@ data class ConversationEntity(
|
|||||||
@ColumnInfo(name = "lobbyState") var lobbyState: ConversationEnums.LobbyState? = null,
|
@ColumnInfo(name = "lobbyState") var lobbyState: ConversationEnums.LobbyState? = null,
|
||||||
@ColumnInfo(name = "lobbyTimer") var lobbyTimer: Long? = null,
|
@ColumnInfo(name = "lobbyTimer") var lobbyTimer: Long? = null,
|
||||||
@ColumnInfo(name = "lastReadMessage") var lastReadMessage: Int = 0,
|
@ColumnInfo(name = "lastReadMessage") var lastReadMessage: Int = 0,
|
||||||
|
@ColumnInfo(name = "lastCommonReadMessage") var lastCommonReadMessage: Int = 0,
|
||||||
@ColumnInfo(name = "hasCall") var hasCall: Boolean = false,
|
@ColumnInfo(name = "hasCall") var hasCall: Boolean = false,
|
||||||
@ColumnInfo(name = "callFlag") var callFlag: Int = 0,
|
@ColumnInfo(name = "callFlag") var callFlag: Int = 0,
|
||||||
@ColumnInfo(name = "canStartCall") var canStartCall: Boolean = false,
|
@ColumnInfo(name = "canStartCall") var canStartCall: Boolean = false,
|
||||||
|
@ -41,6 +41,7 @@ class ConversationModel(
|
|||||||
var lobbyState: ConversationEnums.LobbyState? = null,
|
var lobbyState: ConversationEnums.LobbyState? = null,
|
||||||
var lobbyTimer: Long? = null,
|
var lobbyTimer: Long? = null,
|
||||||
var lastReadMessage: Int = 0,
|
var lastReadMessage: Int = 0,
|
||||||
|
var lastCommonReadMessage: Int = 0,
|
||||||
var hasCall: Boolean = false,
|
var hasCall: Boolean = false,
|
||||||
var callFlag: Int = 0,
|
var callFlag: Int = 0,
|
||||||
var canStartCall: Boolean = false,
|
var canStartCall: Boolean = false,
|
||||||
@ -101,6 +102,7 @@ class ConversationModel(
|
|||||||
lobbyState = conversation.lobbyState?.let { ConversationEnums.LobbyState.valueOf(it.name) },
|
lobbyState = conversation.lobbyState?.let { ConversationEnums.LobbyState.valueOf(it.name) },
|
||||||
lobbyTimer = conversation.lobbyTimer,
|
lobbyTimer = conversation.lobbyTimer,
|
||||||
lastReadMessage = conversation.lastReadMessage,
|
lastReadMessage = conversation.lastReadMessage,
|
||||||
|
lastCommonReadMessage = conversation.lastCommonReadMessage,
|
||||||
hasCall = conversation.hasCall,
|
hasCall = conversation.hasCall,
|
||||||
callFlag = conversation.callFlag,
|
callFlag = conversation.callFlag,
|
||||||
canStartCall = conversation.canStartCall,
|
canStartCall = conversation.canStartCall,
|
||||||
|
@ -90,6 +90,9 @@ data class Conversation(
|
|||||||
@JsonField(name = ["lastReadMessage"])
|
@JsonField(name = ["lastReadMessage"])
|
||||||
var lastReadMessage: Int = 0,
|
var lastReadMessage: Int = 0,
|
||||||
|
|
||||||
|
@JsonField(name = ["lastCommonReadMessage"])
|
||||||
|
var lastCommonReadMessage: Int = 0,
|
||||||
|
|
||||||
@JsonField(name = ["hasCall"])
|
@JsonField(name = ["hasCall"])
|
||||||
var hasCall: Boolean = false,
|
var hasCall: Boolean = false,
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user