Current scope: Kover HTML Report| all classes
|
release.com.greybox.projectmesh.messaging.ui.viewmodels
Coverage Summary for Class: ConversationsHomeScreenViewModel (release.com.greybox.projectmesh.messaging.ui.viewmodels)
| Class | Method, % | Branch, % | Line, % | Instruction, % |
|---|---|---|---|---|
| ConversationsHomeScreenViewModel$1 | 0% (0/1) | 0% (0/2) | 0% (0/3) | 0% (0/37) |
| ConversationsHomeScreenViewModel$1$1 | 0% (0/1) | 0% (0/1) | 0% (0/4) | |
| ConversationsHomeScreenViewModel$loadConversations$1 | 0% (0/1) | |||
| ConversationsHomeScreenViewModel$loadConversations$1$2 | 0% (0/1) | |||
| ConversationsHomeScreenViewModel$markConversationAsRead$1 | 0% (0/1) | 0% (0/2) | 0% (0/3) | 0% (0/38) |
| ConversationsHomeScreenViewModel$special$$inlined$instance$1 | 0% (0/1) | |||
| ConversationsHomeScreenViewModel$special$$inlined$instance$default$1 | 0% (0/1) | |||
| ConversationsHomeScreenViewModel$updateConversationStatuses$1 | 0% (0/1) | |||
| Total | 0% (0/13) | 0% (0/4) | 0% (0/7) | 0% (0/79) |
package com.greybox.projectmesh.messaging.ui.viewmodels
import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.greybox.projectmesh.DeviceStatusManager
import com.greybox.projectmesh.GlobalApp
import com.greybox.projectmesh.messaging.repository.ConversationRepository
import com.greybox.projectmesh.messaging.ui.models.ConversationsHomeScreenModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.kodein.di.DI
import org.kodein.di.instance
/**
* ViewModel for the Conversations Home Screen.
*
* Manages the list of conversations, updates device online/offline statuses,
* and provides functions for refreshing and marking conversations as read.
*
* @param di Dependency Injection container to provide required repositories and settings.
*/
class ConversationsHomeScreenViewModel(
di: DI
) : ViewModel() {
//keep track of UI state
private val _uiState = MutableStateFlow(ConversationsHomeScreenModel(isLoading = true))
val uiState: Flow<ConversationsHomeScreenModel> = _uiState.asStateFlow()
//get repository instances
private val conversationRepository: ConversationRepository by di.instance()
// Get access to SharedPreferences for the local UUID
private val sharedPrefs: SharedPreferences by di.instance(tag = "settings")
init {
loadConversations()
viewModelScope.launch {
DeviceStatusManager.deviceStatusMap
.collect { deviceStatusMap ->
// Process immediately without debouncing
updateConversationStatuses(deviceStatusMap)
}
}
}
//Update conversations Status based on device status
private fun updateConversationStatuses(deviceStatusMap: Map<String, Boolean>) {
viewModelScope.launch(Dispatchers.IO) { // Use IO dispatcher for database operations
try {
// Get current conversations once
val currentConversations = _uiState.value.conversations
// Create a list to track conversations needing updates
val conversationsToUpdate = mutableListOf<Pair<String, Boolean>>()
// Check which conversations need updates
currentConversations.forEach { conversation ->
conversation.userAddress?.let { ipAddress ->
val isOnline = deviceStatusMap[ipAddress] ?: false
if (conversation.isOnline != isOnline) {
conversationsToUpdate.add(Pair(conversation.userUuid, isOnline))
}
}
}
// Batch update all needed conversations
conversationsToUpdate.forEach { (userUuid, isOnline) ->
// Update conversation status in database
conversationRepository.updateUserStatus(
userUuid = userUuid,
isOnline = isOnline,
userAddress = if (isOnline)
currentConversations.find { it.userUuid == userUuid }?.userAddress
else null
)
Log.d("ConversationsViewModel",
"Updated conversation status for ${currentConversations.find { it.userUuid == userUuid }?.userName}: online=$isOnline")
}
// If we made any updates, force a refresh of the list
if (conversationsToUpdate.isNotEmpty()) {
refreshConversations()
}
} catch (e: Exception) {
Log.e("ConversationsViewModel", "Error updating conversation statuses", e)
}
}
}
private fun loadConversations() {
viewModelScope.launch {
try {
//start with loading state
_uiState.update { it.copy (isLoading = true, error = null )}
//get local device id
val localUuid = sharedPrefs.getString("UUID", null) ?: "local-user"
Log.d("ConversationsViewModel", "Local UUID: $localUuid")
//collect conversations from repository
conversationRepository.getAllConversations().collect { conversations ->
Log.d("ConversationsViewModel", "Loaded ${conversations.size} conversations")
//filter out conversations with self
val filteredConversations = conversations.filter { conversation ->
conversation.userUuid != localUuid
}
conversations.forEach { conversation ->
Log.d("ConversationsViewModel", "Conversation: ID=${conversation.id}, UserUUID=${conversation.userUuid}, Name=${conversation.userName}")
}
Log.d("ConversationsViewModel", "Filtering out conversations with UUID: $localUuid")
Log.d("ConversationsViewModel", "After filtering self: ${filteredConversations.size} conversations")
//update the UI state with the conversations
_uiState.update {
it.copy(
isLoading = false,
conversations = filteredConversations,
error = null
)
}
}
}catch (e: Exception) {
Log.e("ConversationsViewModel", "Error loading conversations", e)
_uiState.update {
it.copy (
isLoading = false,
error = "Failed to load conversations: ${e.message}"
)
}
}
}
}
/**
* Refreshes the conversations list manually.
*
* Reloads the conversations from the repository.
*/
fun refreshConversations(){
loadConversations()
}
/**
* Marks a conversation as read.
*
* @param conversationId The ID of the conversation to mark as read.
*/
fun markConversationAsRead(conversationId: String) {
viewModelScope.launch {
try {
conversationRepository.markAsRead(conversationId)
} catch (e: Exception) {
Log.e("ConversationsViewModel", "Error marking conversation as read", e)
}
}
}
}