kopia lustrzana https://github.com/vitorpamplona/amethyst
181 wiersze
8.1 KiB
Kotlin
181 wiersze
8.1 KiB
Kotlin
package com.vitorpamplona.amethyst.service.notifications
|
|
|
|
import android.app.NotificationManager
|
|
import android.content.Context
|
|
import androidx.core.content.ContextCompat
|
|
import com.vitorpamplona.amethyst.LocalPreferences
|
|
import com.vitorpamplona.amethyst.R
|
|
import com.vitorpamplona.amethyst.model.Account
|
|
import com.vitorpamplona.amethyst.model.LocalCache
|
|
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendDMNotification
|
|
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendZapNotification
|
|
import com.vitorpamplona.amethyst.ui.note.showAmount
|
|
import com.vitorpamplona.quartz.encoders.toHexKey
|
|
import com.vitorpamplona.quartz.events.ChatMessageEvent
|
|
import com.vitorpamplona.quartz.events.ChatroomKey
|
|
import com.vitorpamplona.quartz.events.Event
|
|
import com.vitorpamplona.quartz.events.GiftWrapEvent
|
|
import com.vitorpamplona.quartz.events.LnZapEvent
|
|
import com.vitorpamplona.quartz.events.LnZapRequestEvent
|
|
import com.vitorpamplona.quartz.events.PrivateDmEvent
|
|
import com.vitorpamplona.quartz.events.SealedGossipEvent
|
|
import kotlinx.collections.immutable.persistentSetOf
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.Job
|
|
import kotlinx.coroutines.launch
|
|
|
|
class EventNotificationConsumer(private val applicationContext: Context) {
|
|
fun consume(event: Event) {
|
|
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
|
scope.launch {
|
|
if (LocalCache.notes[event.id] == null) {
|
|
if (LocalCache.justVerify(event)) {
|
|
LocalCache.justConsume(event, null)
|
|
|
|
val manager = notificationManager()
|
|
if (manager.areNotificationsEnabled()) {
|
|
when (event) {
|
|
is PrivateDmEvent -> notify(event)
|
|
is LnZapEvent -> notify(event)
|
|
is GiftWrapEvent -> unwrapAndNotify(event)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun unwrapAndConsume(event: Event, account: Account): Event? {
|
|
if (!LocalCache.justVerify(event)) return null
|
|
|
|
return when (event) {
|
|
is GiftWrapEvent -> {
|
|
val key = account.keyPair.privKey ?: return null
|
|
event.cachedGift(key)?.let {
|
|
unwrapAndConsume(it, account)
|
|
}
|
|
}
|
|
is SealedGossipEvent -> {
|
|
val key = account.keyPair.privKey ?: return null
|
|
event.cachedGossip(key)?.let {
|
|
// this is not verifiable
|
|
LocalCache.justConsume(it, null)
|
|
it
|
|
}
|
|
}
|
|
else -> {
|
|
LocalCache.justConsume(event, null)
|
|
event
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun unwrapAndNotify(giftWrap: GiftWrapEvent) {
|
|
val giftWrapNote = LocalCache.notes[giftWrap.id] ?: return
|
|
|
|
LocalPreferences.allSavedAccounts().forEach {
|
|
val acc = LocalPreferences.loadFromEncryptedStorage(it.npub)
|
|
|
|
if (acc != null && acc.userProfile().pubkeyHex == giftWrap.recipientPubKey()) {
|
|
val chatEvent = unwrapAndConsume(giftWrap, account = acc)
|
|
|
|
if (chatEvent is ChatMessageEvent && acc.keyPair.privKey != null) {
|
|
val chatNote = LocalCache.notes[chatEvent.id] ?: return
|
|
val chatRoom = chatEvent.chatroomKey(acc.keyPair.pubKey.toHexKey())
|
|
|
|
val followingKeySet = acc.followingKeySet()
|
|
|
|
val isKnownRoom = (
|
|
acc.userProfile().privateChatrooms[chatRoom]?.senderIntersects(followingKeySet) == true ||
|
|
acc.userProfile().hasSentMessagesTo(chatRoom)
|
|
) && !acc.isAllHidden(chatRoom.users)
|
|
|
|
if (isKnownRoom) {
|
|
val content = chatNote.event?.content() ?: ""
|
|
val user = chatNote.author?.toBestDisplayName() ?: ""
|
|
val userPicture = chatNote.author?.profilePicture()
|
|
val noteUri = chatNote.toNEvent()
|
|
notificationManager().sendDMNotification(chatEvent.id, content, user, userPicture, noteUri, applicationContext)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun notify(event: PrivateDmEvent) {
|
|
val note = LocalCache.notes[event.id] ?: return
|
|
|
|
LocalPreferences.allSavedAccounts().forEach {
|
|
val acc = LocalPreferences.loadFromEncryptedStorage(it.npub)
|
|
|
|
if (acc != null && acc.userProfile().pubkeyHex == event.verifiedRecipientPubKey()) {
|
|
val followingKeySet = acc.followingKeySet()
|
|
|
|
val knownChatrooms = acc.userProfile().privateChatrooms.keys.filter {
|
|
(
|
|
acc.userProfile().privateChatrooms[it]?.senderIntersects(followingKeySet) == true ||
|
|
acc.userProfile().hasSentMessagesTo(it)
|
|
) && !acc.isAllHidden(it.users)
|
|
}.toSet()
|
|
|
|
note.author?.let {
|
|
if (ChatroomKey(persistentSetOf(it.pubkeyHex)) in knownChatrooms) {
|
|
val content = acc.decryptContent(note) ?: ""
|
|
val user = note.author?.toBestDisplayName() ?: ""
|
|
val userPicture = note.author?.profilePicture()
|
|
val noteUri = note.toNEvent()
|
|
notificationManager().sendDMNotification(event.id, content, user, userPicture, noteUri, applicationContext)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun notify(event: LnZapEvent) {
|
|
val noteZapEvent = LocalCache.notes[event.id] ?: return
|
|
|
|
val noteZapRequest = event.zapRequest?.id?.let { LocalCache.checkGetOrCreateNote(it) }
|
|
val noteZapped = event.zappedPost().firstOrNull()?.let { LocalCache.checkGetOrCreateNote(it) }
|
|
|
|
LocalPreferences.allSavedAccounts().forEach {
|
|
val acc = LocalPreferences.loadFromEncryptedStorage(it.npub)
|
|
|
|
if (acc != null && acc.userProfile().pubkeyHex == event.zappedAuthor().firstOrNull()) {
|
|
val amount = showAmount(event.amount)
|
|
val senderInfo = (noteZapRequest?.event as? LnZapRequestEvent)?.let {
|
|
val decryptedContent = acc.decryptZapContentAuthor(noteZapRequest)
|
|
if (decryptedContent != null) {
|
|
val author = LocalCache.getOrCreateUser(decryptedContent.pubKey)
|
|
Pair(author, decryptedContent.content)
|
|
} else if (!noteZapRequest.event?.content().isNullOrBlank()) {
|
|
Pair(noteZapRequest.author, noteZapRequest.event?.content())
|
|
} else {
|
|
Pair(noteZapRequest.author, null)
|
|
}
|
|
}
|
|
|
|
val zappedContent =
|
|
noteZapped?.let { it1 -> acc.decryptContent(it1)?.split("\n")?.get(0) }
|
|
|
|
val user = senderInfo?.first?.toBestDisplayName() ?: ""
|
|
var title = applicationContext.getString(R.string.app_notification_zaps_channel_message, amount)
|
|
senderInfo?.second?.ifBlank { null }?.let {
|
|
title += " ($it)"
|
|
}
|
|
var content = applicationContext.getString(R.string.app_notification_zaps_channel_message_from, user)
|
|
zappedContent?.let {
|
|
content += " " + applicationContext.getString(R.string.app_notification_zaps_channel_message_for, zappedContent)
|
|
}
|
|
val userPicture = senderInfo?.first?.profilePicture()
|
|
val noteUri = "nostr:Notifications"
|
|
notificationManager().sendZapNotification(event.id, content, title, userPicture, noteUri, applicationContext)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun notificationManager(): NotificationManager {
|
|
return ContextCompat.getSystemService(applicationContext, NotificationManager::class.java) as NotificationManager
|
|
}
|
|
}
|