Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fixes for offline support #4069

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -323,6 +323,7 @@ class ChatActivity :

private val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
chatViewModel.handleChatOnBackPress()
if (currentlyPlayedVoiceMessage != null) {
stopMediaPlayer(currentlyPlayedVoiceMessage!!)
}
Expand Down Expand Up @@ -601,10 +602,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 @@ -2717,7 +2720,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 @@ -65,4 +65,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 @@ -197,8 +198,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 @@ -457,9 +458,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 @@ -622,11 +625,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 @@ -626,6 +626,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 @@ -634,7 +638,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 @@ -373,8 +373,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
Loading