Files
forkmessager/client-mobile/chats/data/remote/signalr/SignalRNotificationObserver.kt
2026-04-16 15:41:22 +03:00

95 lines
3.7 KiB
Kotlin

package chats.data.remote.signalr
import android.content.Context
import core.notifications.data.ActiveChatTracker
import core.notifications.data.NotificationHelper
import core.security.TokenManager
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SignalRNotificationObserver @Inject constructor(
private val signalrClient: ChatHubClient,
private val activeChatTracker: ActiveChatTracker,
private val tokenManager: TokenManager,
private val chatRepository: chats.domain.repository.ChatRepository,
@ApplicationContext private val context: Context
) {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private var isStarted = false
private val processedMessageIds = mutableSetOf<String>()
fun refresh() {
scope.launch {
try {
val chats = chatRepository.getChats()
val total = chats.sumOf { it.unreadCount }
activeChatTracker.setTotalUnreadCount(total)
} catch (e: Exception) {
// Ignore load error
}
}
}
fun start() {
if (isStarted) return
isStarted = true
// Initial count load
refresh()
signalrClient.events
.onEach { event ->
when (event) {
is ChatEvent.NewMessage -> {
val currentUserId = tokenManager.getUserId()
val message = event.message
// Don't show if it's our message or already processed
if (message.senderId == currentUserId) return@onEach
if (processedMessageIds.contains(message.id)) return@onEach
// Mark as processed
processedMessageIds.add(message.id)
if (processedMessageIds.size > 200) {
processedMessageIds.remove(processedMessageIds.first())
}
// Increment immediately for UI feedback
activeChatTracker.incrementUnreadCount()
// Refresh total count from source of truth in background
refresh()
// Don't show if this chat is currently open
if (activeChatTracker.currentChatId.value == message.chatId) return@onEach
NotificationHelper.showNotification(
context = context,
title = message.sender?.displayName ?: "Новое сообщение",
body = message.content ?: "Вам прислали вложение",
type = "chat",
chatId = message.chatId,
notificationId = message.id.hashCode(),
totalCount = activeChatTracker.totalUnreadCount.value
)
}
is ChatEvent.MessagesRead -> {
// If anyone read messages, sync our total count
refresh()
}
else -> Unit
}
}
.launchIn(scope)
}
}