Пуши: учитывать mute и имя отправителя из payload
This commit is contained in:
@@ -56,14 +56,43 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
fun cancelNotificationForChat(context: Context, senderPublicKey: String) {
|
fun cancelNotificationForChat(context: Context, senderPublicKey: String) {
|
||||||
val notificationManager =
|
val notificationManager =
|
||||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
val normalizedKey = senderPublicKey.trim()
|
val variants = buildDialogKeyVariants(senderPublicKey)
|
||||||
if (normalizedKey.isNotEmpty()) {
|
for (key in variants) {
|
||||||
notificationManager.cancel(getNotificationIdForChat(normalizedKey))
|
notificationManager.cancel(getNotificationIdForChat(key))
|
||||||
}
|
}
|
||||||
// Fallback: некоторые серверные payload могут прийти без sender key.
|
// Fallback: некоторые серверные payload могут прийти без sender key.
|
||||||
// Для них используется ID от пустой строки — тоже очищаем при входе в диалог.
|
// Для них используется ID от пустой строки — тоже очищаем при входе в диалог.
|
||||||
notificationManager.cancel(getNotificationIdForChat(""))
|
notificationManager.cancel(getNotificationIdForChat(""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun buildDialogKeyVariants(rawKey: String): Set<String> {
|
||||||
|
val trimmed = rawKey.trim()
|
||||||
|
if (trimmed.isBlank()) return emptySet()
|
||||||
|
|
||||||
|
val variants = linkedSetOf(trimmed)
|
||||||
|
val lower = trimmed.lowercase(Locale.ROOT)
|
||||||
|
when {
|
||||||
|
lower.startsWith("#group:") -> {
|
||||||
|
val groupId = trimmed.substringAfter(':').trim()
|
||||||
|
if (groupId.isNotBlank()) {
|
||||||
|
variants.add("group:$groupId")
|
||||||
|
variants.add(groupId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lower.startsWith("group:") -> {
|
||||||
|
val groupId = trimmed.substringAfter(':').trim()
|
||||||
|
if (groupId.isNotBlank()) {
|
||||||
|
variants.add("#group:$groupId")
|
||||||
|
variants.add(groupId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
variants.add("#group:$trimmed")
|
||||||
|
variants.add("group:$trimmed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return variants
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Вызывается когда получен новый FCM токен Отправляем его на сервер через протокол */
|
/** Вызывается когда получен новый FCM токен Отправляем его на сервер через протокол */
|
||||||
@@ -90,6 +119,8 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
// Обрабатываем data payload
|
// Обрабатываем data payload
|
||||||
if (remoteMessage.data.isNotEmpty()) {
|
if (remoteMessage.data.isNotEmpty()) {
|
||||||
val data = remoteMessage.data
|
val data = remoteMessage.data
|
||||||
|
val notificationTitle = remoteMessage.notification?.title?.trim().orEmpty()
|
||||||
|
val notificationBody = remoteMessage.notification?.body?.trim().orEmpty()
|
||||||
val type =
|
val type =
|
||||||
firstNonBlank(data, "type", "event", "action")
|
firstNonBlank(data, "type", "event", "action")
|
||||||
?.lowercase(Locale.ROOT)
|
?.lowercase(Locale.ROOT)
|
||||||
@@ -100,15 +131,26 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
"sender_public_key",
|
"sender_public_key",
|
||||||
"from_public_key",
|
"from_public_key",
|
||||||
"fromPublicKey",
|
"fromPublicKey",
|
||||||
|
"from",
|
||||||
"public_key",
|
"public_key",
|
||||||
"publicKey"
|
"publicKey"
|
||||||
)
|
)
|
||||||
val senderName =
|
val senderName =
|
||||||
firstNonBlank(data, "sender_name", "from_title", "sender", "title", "name")
|
firstNonBlank(
|
||||||
|
data,
|
||||||
|
"sender_name",
|
||||||
|
"sender_title",
|
||||||
|
"from_title",
|
||||||
|
"sender",
|
||||||
|
"title",
|
||||||
|
"name"
|
||||||
|
)
|
||||||
|
?: notificationTitle.takeIf { it.isNotBlank() }
|
||||||
?: senderPublicKey?.take(10)
|
?: senderPublicKey?.take(10)
|
||||||
?: "Rosetta"
|
?: "Rosetta"
|
||||||
val messagePreview =
|
val messagePreview =
|
||||||
firstNonBlank(data, "message_preview", "message", "text", "body")
|
firstNonBlank(data, "message_preview", "message", "text", "body")
|
||||||
|
?: notificationBody.takeIf { it.isNotBlank() }
|
||||||
?: "New message"
|
?: "New message"
|
||||||
|
|
||||||
val isReadEvent = type == "message_read" || type == "read"
|
val isReadEvent = type == "message_read" || type == "read"
|
||||||
@@ -152,7 +194,21 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
// с неуправляемым notification id.
|
// с неуправляемым notification id.
|
||||||
remoteMessage.notification?.let {
|
remoteMessage.notification?.let {
|
||||||
if (!handledMessageData) {
|
if (!handledMessageData) {
|
||||||
showSimpleNotification(it.title ?: "Rosetta", it.body ?: "New message")
|
val senderPublicKey =
|
||||||
|
firstNonBlank(
|
||||||
|
remoteMessage.data,
|
||||||
|
"sender_public_key",
|
||||||
|
"from_public_key",
|
||||||
|
"fromPublicKey",
|
||||||
|
"from",
|
||||||
|
"public_key",
|
||||||
|
"publicKey"
|
||||||
|
)
|
||||||
|
showSimpleNotification(
|
||||||
|
it.title ?: "Rosetta",
|
||||||
|
it.body ?: "New message",
|
||||||
|
senderPublicKey
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,8 +279,12 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
if (isAppInForeground || !areNotificationsEnabled()) {
|
if (isAppInForeground || !areNotificationsEnabled()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val senderKey = senderPublicKey?.trim().orEmpty()
|
||||||
|
if (senderKey.isNotEmpty() && isDialogMuted(senderKey)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// Dedup: suppress duplicate pushes within DEDUP_WINDOW_MS
|
// Dedup: suppress duplicate pushes within DEDUP_WINDOW_MS
|
||||||
val dedupKey = senderPublicKey?.trim()?.ifEmpty { null } ?: "__simple__"
|
val dedupKey = senderKey.ifEmpty { "__simple__" }
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
val lastTs = lastNotifTimestamps[dedupKey]
|
val lastTs = lastNotifTimestamps[dedupKey]
|
||||||
if (lastTs != null && now - lastTs < DEDUP_WINDOW_MS) {
|
if (lastTs != null && now - lastTs < DEDUP_WINDOW_MS) {
|
||||||
@@ -235,8 +295,8 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
createNotificationChannel()
|
createNotificationChannel()
|
||||||
|
|
||||||
// Используем sender-based ID если известен ключ — чтобы cancelNotificationForChat мог убрать уведомление
|
// Используем sender-based ID если известен ключ — чтобы cancelNotificationForChat мог убрать уведомление
|
||||||
val notifId = if (!senderPublicKey.isNullOrBlank()) {
|
val notifId = if (senderKey.isNotEmpty()) {
|
||||||
getNotificationIdForChat(senderPublicKey.trim())
|
getNotificationIdForChat(senderKey)
|
||||||
} else {
|
} else {
|
||||||
(title + body).hashCode() and 0x7FFFFFFF
|
(title + body).hashCode() and 0x7FFFFFFF
|
||||||
}
|
}
|
||||||
@@ -318,7 +378,10 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
val accountManager = AccountManager(applicationContext)
|
val accountManager = AccountManager(applicationContext)
|
||||||
val currentAccount = accountManager.getLastLoggedPublicKey().orEmpty()
|
val currentAccount = accountManager.getLastLoggedPublicKey().orEmpty()
|
||||||
runBlocking(Dispatchers.IO) {
|
runBlocking(Dispatchers.IO) {
|
||||||
PreferencesManager(applicationContext).isChatMuted(currentAccount, senderPublicKey)
|
val preferences = PreferencesManager(applicationContext)
|
||||||
|
buildDialogKeyVariants(senderPublicKey).any { key ->
|
||||||
|
preferences.isChatMuted(currentAccount, key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.getOrDefault(false)
|
}.getOrDefault(false)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user