157 lines
5.8 KiB
Kotlin
157 lines
5.8 KiB
Kotlin
package chats.presentation.chat_list
|
|
|
|
import androidx.lifecycle.ViewModel
|
|
import androidx.lifecycle.viewModelScope
|
|
import chats.domain.model.Chat
|
|
import chats.domain.repository.ChatRepository
|
|
import chats.data.remote.signalr.ChatHubClient
|
|
import chats.data.remote.signalr.ChatEvent
|
|
import core.network.ServerConfig
|
|
import core.security.TokenManager
|
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
import kotlinx.coroutines.flow.*
|
|
import kotlinx.coroutines.launch
|
|
import javax.inject.Inject
|
|
import chats.data.repository.toDomain
|
|
|
|
data class ChatListState(
|
|
val chats: List<Chat> = emptyList(),
|
|
val isLoading: Boolean = false,
|
|
val error: String? = null,
|
|
val isStoriesEnabled: Boolean = true
|
|
)
|
|
|
|
@HiltViewModel
|
|
class ChatListViewModel @Inject constructor(
|
|
private val repository: ChatRepository,
|
|
private val authRepository: auth.domain.repository.AuthRepository,
|
|
private val signalrClient: ChatHubClient,
|
|
private val serverConfig: ServerConfig,
|
|
private val tokenManager: TokenManager
|
|
) : ViewModel() {
|
|
|
|
private val _state = MutableStateFlow(ChatListState())
|
|
val state: StateFlow<ChatListState> = _state.asStateFlow()
|
|
|
|
init {
|
|
updatePushToken()
|
|
|
|
val isStoriesEnabled = try {
|
|
serverConfig.getServerConfig().features.stories
|
|
} catch (e: Exception) {
|
|
true
|
|
}
|
|
_state.update { it.copy(isStoriesEnabled = isStoriesEnabled) }
|
|
|
|
val token = tokenManager.getToken()
|
|
val baseUrl = serverConfig.getBaseUrl()
|
|
|
|
// Подключаемся к SignalR только если есть токен И введён URL сервера
|
|
if (token != null && baseUrl.isNotBlank()) {
|
|
signalrClient.connect(baseUrl.removeSuffix("/api/"), token)
|
|
}
|
|
|
|
loadChats()
|
|
observeSignalREvents()
|
|
}
|
|
|
|
private fun updatePushToken() {
|
|
com.google.firebase.messaging.FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
|
|
if (task.isSuccessful) {
|
|
val token = task.result
|
|
viewModelScope.launch {
|
|
try {
|
|
authRepository.updatePushToken(token)
|
|
} catch (e: Exception) {
|
|
android.util.Log.e("ChatListVM", "Failed to update push token: ${e.message}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private fun getCurrentUserId(): String = tokenManager.getUserId() ?: ""
|
|
|
|
fun loadChats() {
|
|
viewModelScope.launch {
|
|
_state.update { it.copy(isLoading = true) }
|
|
try {
|
|
val chats = repository.getChats()
|
|
_state.update { it.copy(chats = sortChats(chats), isLoading = false) }
|
|
} catch (e: Exception) {
|
|
_state.update { it.copy(isLoading = false, error = e.message) }
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun sortChats(chats: List<Chat>): List<Chat> {
|
|
return chats.sortedWith(compareByDescending<Chat> {
|
|
it.name.equals("Избранное", ignoreCase = true) || it.name.equals("Saved Messages", ignoreCase = true)
|
|
}.thenByDescending { it.lastMessage?.createdAt })
|
|
}
|
|
|
|
private fun observeSignalREvents() {
|
|
signalrClient.events
|
|
.onEach { event ->
|
|
when (event) {
|
|
is ChatEvent.NewMessage -> {
|
|
updateChatsWithNewMessage(event)
|
|
}
|
|
is ChatEvent.NewChat -> {
|
|
val currentUserId = getCurrentUserId()
|
|
val baseUrl = serverConfig.getBaseUrl().removeSuffix("/api/")
|
|
_state.update { it.copy(chats = listOf(event.chat.toDomain(currentUserId, baseUrl)) + it.chats) }
|
|
}
|
|
is ChatEvent.MessagesRead -> {
|
|
if (event.userId == getCurrentUserId()) {
|
|
_state.update { currentState ->
|
|
val updatedChats = currentState.chats.map { chat ->
|
|
if (chat.id == event.chatId) {
|
|
chat.copy(unreadCount = 0)
|
|
} else chat
|
|
}
|
|
currentState.copy(chats = sortChats(updatedChats))
|
|
}
|
|
}
|
|
}
|
|
else -> Unit
|
|
}
|
|
}
|
|
.launchIn(viewModelScope)
|
|
}
|
|
|
|
|
|
private fun updateChatsWithNewMessage(event: ChatEvent.NewMessage) {
|
|
val baseUrl = serverConfig.getBaseUrl().removeSuffix("/api/")
|
|
val currentUserId = getCurrentUserId()
|
|
|
|
_state.update { currentState ->
|
|
val updatedChats = currentState.chats.map { chat ->
|
|
if (chat.id.equals(event.message.chatId, ignoreCase = true)) {
|
|
val isMyMessage = event.message.senderId == currentUserId
|
|
val isAlreadySeen = chat.lastMessage?.id == event.message.id
|
|
|
|
val lastMsgDomain = event.message.toDomain(currentUserId, baseUrl)
|
|
val newCount = if (isMyMessage || isAlreadySeen) {
|
|
chat.unreadCount
|
|
} else {
|
|
chat.unreadCount + 1
|
|
}
|
|
|
|
if (!isAlreadySeen) {
|
|
android.util.Log.d("ChatListVM", "Message ${event.message.id} -> Count ${chat.unreadCount} -> $newCount")
|
|
}
|
|
|
|
chat.copy(
|
|
lastMessage = lastMsgDomain,
|
|
unreadCount = newCount
|
|
)
|
|
} else chat
|
|
}
|
|
|
|
currentState.copy(chats = sortChats(updatedChats))
|
|
}
|
|
}
|
|
}
|