Второй этап выхода из офлайн режима
This commit is contained in:
@@ -5,7 +5,9 @@ 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.ConnectionStatus
|
||||
import chats.data.remote.signalr.ChatEvent
|
||||
import core.network.NetworkManager
|
||||
import core.network.ServerConfig
|
||||
import core.security.TokenManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
@@ -26,53 +28,35 @@ data class ChatListState(
|
||||
@HiltViewModel
|
||||
class ChatListViewModel @Inject constructor(
|
||||
private val repository: ChatRepository,
|
||||
private val authRepository: auth.domain.repository.AuthRepository,
|
||||
private val signalrClient: ChatHubClient,
|
||||
private val hubClient: ChatHubClient,
|
||||
private val serverConfig: ServerConfig,
|
||||
private val tokenManager: TokenManager
|
||||
private val tokenManager: TokenManager,
|
||||
private val networkManager: NetworkManager
|
||||
) : 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()
|
||||
observeSignalRStatus()
|
||||
observeSignalREvents()
|
||||
observeNetworkStatus()
|
||||
}
|
||||
|
||||
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 observeNetworkStatus() {
|
||||
// При восстановлении сети обновляем чаты
|
||||
networkManager.isOnline
|
||||
.filter { it } // Только переход в онлайн
|
||||
.distinctUntilChanged()
|
||||
.onEach {
|
||||
android.util.Log.d(TAG, "Network restored in chat list, refreshing chats")
|
||||
kotlinx.coroutines.delay(1000) // Дадим сети стабилизироваться
|
||||
repository.getChats()
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
|
||||
private fun getCurrentUserId(): String = tokenManager.getUserId() ?: ""
|
||||
|
||||
fun loadChats() {
|
||||
@@ -102,6 +86,19 @@ class ChatListViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeSignalRStatus() {
|
||||
// Наблюдаем за статусом подключения SignalR и обновляем чаты при переподключении
|
||||
hubClient.status
|
||||
.filter { it == ConnectionStatus.CONNECTED }
|
||||
.distinctUntilChanged()
|
||||
.onEach {
|
||||
android.util.Log.d(TAG, "SignalR connected, refreshing chats")
|
||||
// При переподключении обновляем чаты из сети
|
||||
repository.getChats()
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -109,15 +106,17 @@ class ChatListViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun observeSignalREvents() {
|
||||
signalrClient.events
|
||||
val baseUrl = serverConfig.getBaseUrl().removeSuffix("/api/")
|
||||
android.util.Log.d(TAG, "Starting to observe SignalR events")
|
||||
hubClient.events
|
||||
.onEach { event ->
|
||||
android.util.Log.d(TAG, ">>> ChatListVM received event: ${event::class.simpleName}")
|
||||
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 -> {
|
||||
@@ -144,30 +143,47 @@ class ChatListViewModel @Inject constructor(
|
||||
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
|
||||
val chatIndex = currentState.chats.indexOfFirst {
|
||||
it.id.equals(event.message.chatId, ignoreCase = true)
|
||||
}
|
||||
|
||||
currentState.copy(chats = sortChats(updatedChats))
|
||||
if (chatIndex >= 0) {
|
||||
// Чат есть в списке - обновляем его
|
||||
val chat = currentState.chats[chatIndex]
|
||||
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")
|
||||
}
|
||||
|
||||
val updatedChat = chat.copy(
|
||||
lastMessage = lastMsgDomain,
|
||||
unreadCount = newCount
|
||||
)
|
||||
|
||||
val updatedChats = currentState.chats.toMutableList()
|
||||
updatedChats[chatIndex] = updatedChat
|
||||
currentState.copy(chats = sortChats(updatedChats))
|
||||
} else {
|
||||
// Чата нет в списке - обновляем весь список из репозитория
|
||||
android.util.Log.d("ChatListVM", "Chat ${event.message.chatId} not found in list, refreshing from repository")
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
repository.getChats() // Это обновит Room и Flow
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("ChatListVM", "Failed to refresh chats", e)
|
||||
}
|
||||
}
|
||||
currentState
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user