浏览代码

Merge pull request #4183 from nextcloud/issue-4167-send-messages-offline

Queuing offline messages to be sent online
Marcel Hibbe 8 月之前
父节点
当前提交
4517ca5893

+ 16 - 6
app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt

@@ -73,6 +73,7 @@ import com.nextcloud.talk.utils.text.Spans
 import com.otaliastudios.autocomplete.Autocomplete
 import com.stfalcon.chatkit.commons.models.IMessage
 import com.vanniktech.emoji.EmojiPopup
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
@@ -141,6 +142,11 @@ class MessageInputFragment : Fragment() {
         saveState()
     }
 
+    override fun onResume() {
+        super.onResume()
+        chatActivity.messageInputViewModel.restoreMessageQueue(chatActivity.roomToken)
+    }
+
     override fun onDestroyView() {
         super.onDestroyView()
         if (mentionAutocomplete != null && mentionAutocomplete!!.isPopupShowing) {
@@ -178,12 +184,19 @@ class MessageInputFragment : Fragment() {
                 val connectionGained = (!wasOnline && isOnline)
                 wasOnline = !binding.fragmentMessageInputView.isShown
                 Log.d(TAG, "isOnline: $isOnline\nwasOnline: $wasOnline\nconnectionGained: $connectionGained")
-
-                // FIXME timeout exception - maybe something to do with the room?
-                // handleMessageQueue(isOnline)
+                delay(500)
+                handleMessageQueue(isOnline)
                 handleUI(isOnline, connectionGained)
             }.collect()
         }
+
+        chatActivity.messageInputViewModel.messageQueueSizeFlow.observe(viewLifecycleOwner) { size ->
+            if (size > 0) {
+                binding.fragmentConnectionLost.text = getString(R.string.connection_lost_queued, size)
+            } else {
+                binding.fragmentConnectionLost.text = getString(R.string.connection_lost_sent_messages_are_queued)
+            }
+        }
     }
 
     private fun handleUI(isOnline: Boolean, connectionGained: Boolean) {
@@ -220,12 +233,9 @@ class MessageInputFragment : Fragment() {
             binding.fragmentConnectionLost.clearAnimation()
             binding.fragmentConnectionLost.visibility = View.GONE
             binding.fragmentConnectionLost.setBackgroundColor(resources.getColor(R.color.hwSecurityRed))
-            binding.fragmentConnectionLost.text =
-                getString(R.string.connection_lost_sent_messages_are_queued)
             binding.fragmentConnectionLost.visibility = View.VISIBLE
             binding.fragmentMessageInputView.attachmentButton.isEnabled = false
             binding.fragmentMessageInputView.recordAudioButton.isEnabled = false
-            binding.fragmentMessageInputView.messageInput.isEnabled = false
         }
     }
 

+ 21 - 4
app/src/main/java/com/nextcloud/talk/chat/viewmodels/MessageInputViewModel.kt

@@ -14,6 +14,7 @@ import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
+import androidx.lifecycle.asLiveData
 import com.nextcloud.talk.chat.data.io.AudioFocusRequestManager
 import com.nextcloud.talk.chat.data.io.AudioRecorderManager
 import com.nextcloud.talk.chat.data.io.MediaPlayerManager
@@ -26,6 +27,9 @@ import io.reactivex.Observer
 import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.disposables.Disposable
 import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.update
+import java.lang.Thread.sleep
 import javax.inject.Inject
 
 class MessageInputViewModel @Inject constructor(
@@ -51,7 +55,7 @@ class MessageInputViewModel @Inject constructor(
     )
 
     private var isQueueing: Boolean = false
-    private val messageQueue: MutableList<QueuedMessage> = mutableListOf()
+    private var messageQueue: MutableList<QueuedMessage> = mutableListOf()
 
     override fun onResume(owner: LifecycleOwner) {
         super.onResume(owner)
@@ -76,9 +80,6 @@ class MessageInputViewModel @Inject constructor(
         mediaPlayerManager.handleOnStop()
     }
 
-    companion object {
-        private val TAG = MessageInputViewModel::class.java.simpleName
-    }
     val getAudioFocusChange: LiveData<AudioFocusRequestManager.ManagerState>
         get() = audioFocusRequestManager.getManagerState
 
@@ -119,6 +120,10 @@ class MessageInputViewModel @Inject constructor(
     val isVoicePreviewPlaying: LiveData<Boolean>
         get() = _isVoicePreviewPlaying
 
+    private val _messageQueueSizeFlow = MutableStateFlow(messageQueue.size)
+    val messageQueueSizeFlow: LiveData<Int>
+        get() = _messageQueueSizeFlow.asLiveData()
+
     @Suppress("LongParameterList")
     fun sendChatMessage(
         roomToken: String,
@@ -132,6 +137,7 @@ class MessageInputViewModel @Inject constructor(
         if (isQueueing) {
             messageQueue.add(QueuedMessage(message, displayName, replyTo, sendWithoutNotification))
             dataStore.saveMessageQueue(roomToken, messageQueue)
+            _messageQueueSizeFlow.update { messageQueue.size }
             return
         }
 
@@ -244,6 +250,7 @@ class MessageInputViewModel @Inject constructor(
         dataStore.saveMessageQueue(roomToken, null) // empties the queue
         while (queue.size > 0) {
             val msg = queue.removeFirst()
+            sleep(DELAY_BETWEEN_QUEUED_MESSAGES)
             sendChatMessage(
                 roomToken,
                 credentials,
@@ -259,4 +266,14 @@ class MessageInputViewModel @Inject constructor(
     fun switchToMessageQueue(shouldQueue: Boolean) {
         isQueueing = shouldQueue
     }
+
+    fun restoreMessageQueue(roomToken: String) {
+        messageQueue = dataStore.getMessageQueue(roomToken)
+        _messageQueueSizeFlow.tryEmit(messageQueue.size)
+    }
+
+    companion object {
+        private val TAG = MessageInputViewModel::class.java.simpleName
+        private const val DELAY_BETWEEN_QUEUED_MESSAGES: Long = 100
+    }
 }

+ 13 - 11
app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferencesImpl.kt

@@ -484,7 +484,7 @@ class AppPreferencesImpl(val context: Context) : AppPreferences {
                 var queueStr = ""
                 queue?.let {
                     for (msg in queue) {
-                        val msgStr = "[${msg.message},${msg.replyTo},${msg.displayName},${msg.sendWithoutNotification}]"
+                        val msgStr = "${msg.message},${msg.replyTo},${msg.displayName},${msg.sendWithoutNotification}^"
                         queueStr += msgStr
                     }
                 }
@@ -500,18 +500,20 @@ class AppPreferencesImpl(val context: Context) : AppPreferences {
         val queue: MutableList<MessageInputViewModel.QueuedMessage> = mutableListOf()
         if (queueStr.isEmpty()) return queue
 
-        for (msgStr in queueStr.split("]")) {
+        for (msgStr in queueStr.split("^")) {
             try {
-                val msgArray = msgStr.replace("[", "").split(",")
-                val message = msgArray[MESSAGE_INDEX]
-                val replyTo = msgArray[REPLY_TO_INDEX].toInt()
-                val displayName = msgArray[DISPLY_NAME_INDEX]
-                val silent = msgArray[SILENT_INDEX].toBoolean()
-
-                val qMsg = MessageInputViewModel.QueuedMessage(message, displayName, replyTo, silent)
-                queue.add(qMsg)
+                if (msgStr.isNotEmpty()) {
+                    val msgArray = msgStr.split(",")
+                    val message = msgArray[MESSAGE_INDEX]
+                    val replyTo = msgArray[REPLY_TO_INDEX].toInt()
+                    val displayName = msgArray[DISPLY_NAME_INDEX]
+                    val silent = msgArray[SILENT_INDEX].toBoolean()
+
+                    val qMsg = MessageInputViewModel.QueuedMessage(message, displayName, replyTo, silent)
+                    queue.add(qMsg)
+                }
             } catch (e: IndexOutOfBoundsException) {
-                Log.e(TAG, "Message string: $msgStr\n $e")
+                Log.e(TAG, "Message string: $msgStr\n Queue String: $queueStr \n$e")
             }
         }
 

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -802,6 +802,7 @@ How to translate with transifex:
     <string name="show_banned_participants">Show banned participants</string>
     <string name="bans_list">Bans list</string>
     <string name="connection_lost_sent_messages_are_queued">Connection lost - Sent messages are queued</string>
+    <string name="connection_lost_queued">Connection lost - %1$d are queued</string>
     <string name="connection_established">Connection established</string>
     <string name="message_deleted_by_you">Message deleted by you</string>
     <string name="unban">Unban</string>