瀏覽代碼

implement lastCommonRead handling

contains one workaround for now, see TODO in updateUiForLastCommonRead method

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Marcel Hibbe 10 月之前
父節點
當前提交
0390c93ed2

+ 9 - 3
app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/10.json

@@ -2,7 +2,7 @@
   "formatVersion": 1,
   "database": {
     "version": 10,
-    "identityHash": "234cdb754d42d9ebf2349763a58a4578",
+    "identityHash": "1b97b7e937102e4087f8534f1204fe94",
     "entities": [
       {
         "tableName": "User",
@@ -138,7 +138,7 @@
       },
       {
         "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": [
           {
             "fieldPath": "internalId",
@@ -284,6 +284,12 @@
             "affinity": "INTEGER",
             "notNull": true
           },
+          {
+            "fieldPath": "lastCommonReadMessage",
+            "columnName": "lastCommonReadMessage",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
           {
             "fieldPath": "hasCall",
             "columnName": "hasCall",
@@ -673,7 +679,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, '234cdb754d42d9ebf2349763a58a4578')"
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1b97b7e937102e4087f8534f1204fe94')"
     ]
   }
 }

+ 9 - 0
app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

@@ -834,6 +834,14 @@ class ChatActivity :
                 .collect()
         }
 
+        this.lifecycleScope.launch {
+            chatViewModel.getLastCommonReadFlow
+                .onEach {
+                    updateReadStatusOfAllMessages(it)
+                }
+                .collect()
+        }
+
         chatViewModel.reactionDeletedViewState.observe(this) { state ->
             when (state) {
                 is ChatViewModel.ReactionDeletedSuccessState -> {
@@ -2526,6 +2534,7 @@ class ChatActivity :
                     updateReadStatusOfMessage(message, it)
                 }
             }
+            adapter!!.notifyDataSetChanged()
         }
     }
 

+ 2 - 0
app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt

@@ -30,6 +30,8 @@ interface ChatMessageRepository : LifecycleAwareManager {
 
     val updateMessageFlow: Flow<ChatMessage>
 
+    val lastCommonReadFlow: Flow<Int>
+
     fun setData(
         conversationModel: ConversationModel,
         credentials: String,

+ 34 - 20
app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt

@@ -30,6 +30,7 @@ import io.reactivex.schedulers.Schedulers
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.first
@@ -72,6 +73,13 @@ class OfflineFirstChatRepository @Inject constructor(
     private val _updateMessageFlow:
         MutableSharedFlow<ChatMessage> = MutableSharedFlow()
 
+    override val lastCommonReadFlow:
+        Flow<Int>
+        get() = _lastCommonReadFlow
+
+    private val _lastCommonReadFlow:
+        MutableSharedFlow<Int> = MutableSharedFlow()
+
     private var newXChatLastCommonRead: Int? = null
     private var itIsPaused = false
     private val scope = CoroutineScope(Dispatchers.IO)
@@ -96,6 +104,8 @@ class OfflineFirstChatRepository @Inject constructor(
         scope.launch {
             Log.d(TAG, "---- loadInitialMessages ------------")
 
+            newXChatLastCommonRead = conversationModel.lastCommonReadMessage
+
             val fieldMap = getFieldMap(
                 lookIntoFuture = false,
                 includeLastKnown = true,
@@ -113,10 +123,24 @@ class OfflineFirstChatRepository @Inject constructor(
                 internalConversationId,
                 chatDao.getNewestMessageId(internalConversationId)
             )
+            updateUiForLastCommonRead()
 
             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(
         beforeMessageId: Long,
         roomToken: String,
@@ -141,6 +165,7 @@ class OfflineFirstChatRepository @Inject constructor(
             }
 
             showLast100MessagesBefore(internalConversationId, beforeMessageId)
+            updateUiForLastCommonRead()
         }
 
     override fun initMessagePolling(): Job =
@@ -174,6 +199,8 @@ class OfflineFirstChatRepository @Inject constructor(
                     _messageFlow.emit(pair)
                 }
 
+                updateUiForLastCommonRead()
+
                 // Process read status if not null
                 // val lastKnown = datastore.getLastKnownId(internalConversationId, 0)
                 // list = list.map { chatMessage ->
@@ -245,9 +272,9 @@ class OfflineFirstChatRepository @Inject constructor(
             fieldMap["lastKnownMessageId"] = lastKnown
         }
 
-        // newXChatLastCommonRead?.let {
-        //     fieldMap["lastCommonReadId"] = if (it > 0) it else lastKnown
-        // }
+        newXChatLastCommonRead?.let {
+            fieldMap["lastCommonReadId"] = it
+        }
 
         fieldMap["timeout"] = if (lookIntoFuture) 30 else 0
         fieldMap["limit"] = 100
@@ -291,26 +318,13 @@ class OfflineFirstChatRepository @Inject constructor(
                 .subscribeOn(Schedulers.io())
                 .observeOn(AndroidSchedulers.mainThread())
                 // .timeout(3, TimeUnit.SECONDS)
-                .map {
+                .map { it ->
                     when (it.code()) {
                         HTTP_CODE_OK -> {
                             Log.d(TAG, "getMessagesFromServer HTTP_CODE_OK")
-                            // newXChatLastCommonRead = it.headers()["X-Chat-Last-Common-Read"]?.let {
-                            //     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)
-                            // // }
+                            newXChatLastCommonRead = it.headers()["X-Chat-Last-Common-Read"]?.let {
+                                Integer.parseInt(it)
+                            }
 
                             return@map Pair(
                                 HTTP_CODE_OK,

+ 2 - 0
app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt

@@ -120,6 +120,8 @@ class ChatViewModel @Inject constructor(
 
     val getUpdateMessageFlow = chatRepository.updateMessageFlow
 
+    val getLastCommonReadFlow = chatRepository.lastCommonReadFlow
+
     val getConversationFlow = conversationRepository.conversationFlow
         .onEach {
             _getRoomViewState.value = GetRoomSuccessState

+ 3 - 0
app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt

@@ -38,6 +38,7 @@ fun ConversationModel.asEntity() =
         lobbyState = lobbyState,
         lobbyTimer = lobbyTimer,
         lastReadMessage = lastReadMessage,
+        lastCommonReadMessage = lastCommonReadMessage,
         hasCall = hasCall,
         callFlag = callFlag,
         canStartCall = canStartCall,
@@ -86,6 +87,7 @@ fun ConversationEntity.asModel() =
         lobbyState = lobbyState,
         lobbyTimer = lobbyTimer,
         lastReadMessage = lastReadMessage,
+        lastCommonReadMessage = lastCommonReadMessage,
         hasCall = hasCall,
         callFlag = callFlag,
         canStartCall = canStartCall,
@@ -134,6 +136,7 @@ fun Conversation.asEntity(accountId: Long) =
         lobbyState = lobbyState,
         lobbyTimer = lobbyTimer,
         lastReadMessage = lastReadMessage,
+        lastCommonReadMessage = lastCommonReadMessage,
         hasCall = hasCall,
         callFlag = callFlag,
         canStartCall = canStartCall,

+ 1 - 0
app/src/main/java/com/nextcloud/talk/data/database/model/ConversationEntity.kt

@@ -68,6 +68,7 @@ data class ConversationEntity(
     @ColumnInfo(name = "lobbyState") var lobbyState: ConversationEnums.LobbyState? = null,
     @ColumnInfo(name = "lobbyTimer") var lobbyTimer: Long? = null,
     @ColumnInfo(name = "lastReadMessage") var lastReadMessage: Int = 0,
+    @ColumnInfo(name = "lastCommonReadMessage") var lastCommonReadMessage: Int = 0,
     @ColumnInfo(name = "hasCall") var hasCall: Boolean = false,
     @ColumnInfo(name = "callFlag") var callFlag: Int = 0,
     @ColumnInfo(name = "canStartCall") var canStartCall: Boolean = false,

+ 2 - 0
app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt

@@ -41,6 +41,7 @@ class ConversationModel(
     var lobbyState: ConversationEnums.LobbyState? = null,
     var lobbyTimer: Long? = null,
     var lastReadMessage: Int = 0,
+    var lastCommonReadMessage: Int = 0,
     var hasCall: Boolean = false,
     var callFlag: Int = 0,
     var canStartCall: Boolean = false,
@@ -101,6 +102,7 @@ class ConversationModel(
                 lobbyState = conversation.lobbyState?.let { ConversationEnums.LobbyState.valueOf(it.name) },
                 lobbyTimer = conversation.lobbyTimer,
                 lastReadMessage = conversation.lastReadMessage,
+                lastCommonReadMessage = conversation.lastCommonReadMessage,
                 hasCall = conversation.hasCall,
                 callFlag = conversation.callFlag,
                 canStartCall = conversation.canStartCall,

+ 3 - 0
app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt

@@ -90,6 +90,9 @@ data class Conversation(
     @JsonField(name = ["lastReadMessage"])
     var lastReadMessage: Int = 0,
 
+    @JsonField(name = ["lastCommonReadMessage"])
+    var lastCommonReadMessage: Int = 0,
+
     @JsonField(name = ["hasCall"])
     var hasCall: Boolean = false,