Skip to content

Commit

Permalink
Merge pull request #4157 from nextcloud/backport/4069/offline-support…
Browse files Browse the repository at this point in the history
…-bug-fixes

Follow up bug fixes for offline support
  • Loading branch information
mahibi authored Sep 5, 2024
2 parents b079160 + 9ae6d62 commit 6526908
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 18 deletions.
13 changes: 8 additions & 5 deletions app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ class ChatActivity :

private val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
chatViewModel.handleChatOnBackPress()
if (currentlyPlayedVoiceMessage != null) {
stopMediaPlayer(currentlyPlayedVoiceMessage!!)
}
Expand Down Expand Up @@ -600,10 +601,12 @@ class ChatActivity :

val urlForChatting = ApiUtils.getUrlForChat(chatApiVersion, conversationUser?.baseUrl, roomToken)

chatViewModel.loadMessages(
withCredentials = credentials!!,
withUrl = urlForChatting
)
if (adapter?.isEmpty == true) {
chatViewModel.loadMessages(
withCredentials = credentials!!,
withUrl = urlForChatting
)
}
}

is ChatViewModel.GetCapabilitiesErrorState -> {
Expand Down Expand Up @@ -2718,7 +2721,7 @@ class ChatActivity :
withUrl = urlForChatting,
withCredentials = credentials!!,
withMessageLimit = MESSAGE_PULL_LIMIT,
roomToken = currentConversation!!.token!!
roomToken = currentConversation!!.token
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,9 @@ interface ChatMessageRepository : LifecycleAwareManager {
* Gets a individual message.
*/
suspend fun getMessage(messageId: Long, bundle: Bundle): Flow<ChatMessage>

/**
* Destroys unused resources.
*/
fun handleChatOnBackPress()
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
Expand Down Expand Up @@ -201,8 +202,8 @@ class OfflineFirstChatRepository @Inject constructor(

val networkParams = Bundle()

while (!itIsPaused) {
if (!monitor.isOnline.first()) Thread.sleep(500)
while (true) {
if (!monitor.isOnline.first() || itIsPaused) Thread.sleep(HALF_SECOND)

// sync database with server (This is a long blocking call because long polling (lookIntoFuture) is set)
networkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap)
Expand Down Expand Up @@ -464,9 +465,11 @@ class OfflineFirstChatRepository @Inject constructor(
// the parent message is always the newest state, no matter how old the system message is.
// that's why we can just take the parent, update it in DB and update the UI
messageJson.parentMessage?.let { parentMessageJson ->
val parentMessageEntity = parentMessageJson.asEntity(currentUser.id!!)
chatDao.upsertChatMessage(parentMessageEntity)
_updateMessageFlow.emit(parentMessageEntity.asModel())
parentMessageJson.message?.let {
val parentMessageEntity = parentMessageJson.asEntity(currentUser.id!!)
chatDao.upsertChatMessage(parentMessageEntity)
_updateMessageFlow.emit(parentMessageEntity.asModel())
}
}
}

Expand Down Expand Up @@ -629,11 +632,16 @@ class OfflineFirstChatRepository @Inject constructor(
// unused atm
}

override fun handleChatOnBackPress() {
scope.cancel()
}

companion object {
val TAG = OfflineFirstChatRepository::class.simpleName
private const val HTTP_CODE_OK: Int = 200
private const val HTTP_CODE_NOT_MODIFIED = 304
private const val HTTP_CODE_PRECONDITION_FAILED = 412
private const val HALF_SECOND = 500L
private const val DELAY_TO_ENSURE_MESSAGES_ARE_ADDED: Long = 100
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,10 @@ class ChatViewModel @Inject constructor(
_getCapabilitiesViewState.value = GetCapabilitiesStartState
}

fun handleChatOnBackPress() {
chatRepository.handleChatOnBackPress()
}

suspend fun getMessageById(url: String, conversationModel: ConversationModel, messageId: Long): Flow<ChatMessage> =
flow {
val bundle = Bundle()
Expand All @@ -642,7 +646,7 @@ class ChatViewModel @Inject constructor(
BundleKeys.KEY_CREDENTIALS,
userProvider.currentUser.blockingGet().getCredentials()
)
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversationModel.token!!)
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversationModel.token)

val message = chatRepository.getMessage(messageId, bundle)
emit(message.first())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,8 @@ class ConversationsListActivity :
conversationsListViewModel.getRoomsFlow
.onEach { list ->
// Update Conversations
conversationItems.clear()
conversationItemsWithHeader.clear()
conversationItems.clear() // fixme remove this
for (conversation in list) {
addToConversationItems(conversation)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package com.nextcloud.talk.conversationlist.data.network

import android.util.Log
import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource
import com.nextcloud.talk.chat.data.network.OfflineFirstChatRepository
import com.nextcloud.talk.conversationlist.data.OfflineConversationsRepository
import com.nextcloud.talk.data.database.dao.ConversationsDao
Expand All @@ -19,7 +20,9 @@ import com.nextcloud.talk.data.network.NetworkMonitor
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.models.domain.ConversationModel
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -29,11 +32,13 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import javax.inject.Inject

class OfflineFirstConversationsRepository @Inject constructor(
private val dao: ConversationsDao,
private val network: ConversationsNetworkDataSource,
private val chatNetworkDataSource: ChatNetworkDataSource,
private val monitor: NetworkMonitor,
private val currentUserProviderNew: CurrentUserProviderNew
) : OfflineConversationsRepository {
Expand Down Expand Up @@ -64,7 +69,34 @@ class OfflineFirstConversationsRepository @Inject constructor(
scope.launch {
val id = user.id!!
val model = getConversation(id, roomToken)
model.let { _conversationFlow.emit(model) }
if (model != null) {
_conversationFlow.emit(model)
} else {
chatNetworkDataSource.getRoom(user, roomToken)
.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<ConversationModel> {
override fun onSubscribe(p0: Disposable) {
// unused atm
}

override fun onError(e: Throwable) {
// unused atm
}

override fun onComplete() {
// unused atm
}

override fun onNext(model: ConversationModel) {
runBlocking {
_conversationFlow.emit(model)
val entityList = listOf(model.asEntity())
dao.upsertConversations(entityList)
}
}
})
}
}

private suspend fun sync(): List<ConversationEntity>? {
Expand Down Expand Up @@ -107,9 +139,9 @@ class OfflineFirstConversationsRepository @Inject constructor(
it.map(ConversationEntity::asModel)
}.first()

private suspend fun getConversation(accountId: Long, token: String): ConversationModel {
private suspend fun getConversation(accountId: Long, token: String): ConversationModel? {
val entity = dao.getConversationForUser(accountId, token).first()
return entity.asModel()
return entity?.asModel()
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
package com.nextcloud.talk.dagger.modules

import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.api.NcApiCoroutines
import com.nextcloud.talk.chat.data.ChatMessageRepository
import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource
import com.nextcloud.talk.chat.data.network.OfflineFirstChatRepository
import com.nextcloud.talk.chat.data.network.RetrofitChatNetwork
import com.nextcloud.talk.api.NcApiCoroutines
import com.nextcloud.talk.contacts.ContactsRepository
import com.nextcloud.talk.contacts.ContactsRepositoryImpl
import com.nextcloud.talk.conversation.repository.ConversationRepository
Expand Down Expand Up @@ -191,10 +191,17 @@ class RepositoryModule {
fun provideOfflineFirstConversationsRepository(
dao: ConversationsDao,
dataSource: ConversationsNetworkDataSource,
chatNetworkDataSource: ChatNetworkDataSource,
networkMonitor: NetworkMonitor,
currentUserProviderNew: CurrentUserProviderNew
): OfflineConversationsRepository {
return OfflineFirstConversationsRepository(dao, dataSource, networkMonitor, currentUserProviderNew)
return OfflineFirstConversationsRepository(
dao,
dataSource,
chatNetworkDataSource,
networkMonitor,
currentUserProviderNew
)
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface ConversationsDao {
fun getConversationsForUser(accountId: Long): Flow<List<ConversationEntity>>

@Query("SELECT * FROM Conversations where accountId = :accountId AND token = :token")
fun getConversationForUser(accountId: Long, token: String): Flow<ConversationEntity>
fun getConversationForUser(accountId: Long, token: String): Flow<ConversationEntity?>

@Upsert
fun upsertConversations(conversationEntities: List<ConversationEntity>)
Expand Down

0 comments on commit 6526908

Please sign in to comment.