Implement queued messages for offline support

Signed-off-by: rapterjet2004 <juliuslinus1@gmail.com>
This commit is contained in:
rapterjet2004 2024-09-10 07:38:12 -05:00 committed by Marcel Hibbe
parent 3d2df9bb94
commit 569be55395
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
4 changed files with 43 additions and 17 deletions

View File

@ -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
}
}

View File

@ -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,8 @@ 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 javax.inject.Inject
class MessageInputViewModel @Inject constructor(
@ -51,7 +54,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)
@ -119,6 +122,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 +139,7 @@ class MessageInputViewModel @Inject constructor(
if (isQueueing) {
messageQueue.add(QueuedMessage(message, displayName, replyTo, sendWithoutNotification))
dataStore.saveMessageQueue(roomToken, messageQueue)
_messageQueueSizeFlow.update { messageQueue.size }
return
}
@ -259,4 +267,9 @@ class MessageInputViewModel @Inject constructor(
fun switchToMessageQueue(shouldQueue: Boolean) {
isQueueing = shouldQueue
}
fun restoreMessageQueue(roomToken: String) {
messageQueue = dataStore.getMessageQueue(roomToken)
_messageQueueSizeFlow.tryEmit(messageQueue.size)
}
}

View File

@ -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()
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)
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")
}
}

View File

@ -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>