Merge pull request #2046 from vitorpamplona/claude/add-reaction-notifications-NzyLO
Add push notifications for post reactions
This commit is contained in:
+78
@@ -31,6 +31,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendChessNotification
|
||||
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendDMNotification
|
||||
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendReactionNotification
|
||||
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendZapNotification
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
@@ -44,6 +45,7 @@ import com.vitorpamplona.quartz.nip17Dm.files.ChatMessageEncryptedFileHeaderEven
|
||||
import com.vitorpamplona.quartz.nip17Dm.messages.ChatMessageEvent
|
||||
import com.vitorpamplona.quartz.nip19Bech32.toNpub
|
||||
import com.vitorpamplona.quartz.nip21UriScheme.toNostrUri
|
||||
import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent
|
||||
@@ -123,6 +125,10 @@ class EventNotificationConsumer(
|
||||
is ChatMessageEncryptedFileHeaderEvent -> {
|
||||
notify(innerEvent, account)
|
||||
}
|
||||
|
||||
is ReactionEvent -> {
|
||||
notify(innerEvent, account)
|
||||
}
|
||||
|
||||
is LiveChessGameAcceptEvent -> {
|
||||
notifyChessEvent(innerEvent, account, R.string.app_notification_chess_challenge_accepted)
|
||||
@@ -504,6 +510,78 @@ class EventNotificationConsumer(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun notify(
|
||||
event: ReactionEvent,
|
||||
account: Account,
|
||||
) {
|
||||
Log.d(TAG, "New Reaction to Notify")
|
||||
|
||||
// old event being re-broadcast
|
||||
if (event.createdAt < TimeUtils.fifteenMinutesAgo()) return
|
||||
|
||||
// don't notify for own reactions
|
||||
if (event.pubKey == account.signer.pubKey) return
|
||||
|
||||
// only notify if the reaction is for the current user
|
||||
if (!event.isTaggedUser(account.signer.pubKey)) return
|
||||
|
||||
val reactedPostId = event.originalPost().firstOrNull() ?: return
|
||||
val reactedNote = LocalCache.checkGetOrCreateNote(reactedPostId)
|
||||
|
||||
val author = LocalCache.getOrCreateUser(event.pubKey)
|
||||
val user = author.toBestDisplayName()
|
||||
val userPicture = author.profilePicture()
|
||||
|
||||
val reactionContent = event.content
|
||||
val reactionSymbol =
|
||||
when {
|
||||
reactionContent == ReactionEvent.LIKE || reactionContent.isBlank() -> "\uD83E\uDD19"
|
||||
reactionContent == ReactionEvent.DISLIKE -> "\uD83D\uDC4E"
|
||||
else -> reactionContent
|
||||
}
|
||||
|
||||
val title = "$reactionSymbol $user"
|
||||
|
||||
val reactedContent =
|
||||
reactedNote
|
||||
?.event
|
||||
?.content
|
||||
?.split("\n")
|
||||
?.firstOrNull() ?: ""
|
||||
|
||||
val content =
|
||||
if (reactedContent.isNotBlank()) {
|
||||
stringRes(
|
||||
applicationContext,
|
||||
R.string.app_notification_reactions_channel_message_for,
|
||||
reactedContent,
|
||||
)
|
||||
} else {
|
||||
stringRes(
|
||||
applicationContext,
|
||||
R.string.app_notification_reactions_channel_message,
|
||||
user,
|
||||
)
|
||||
}
|
||||
|
||||
val noteUri =
|
||||
"notifications$ACCOUNT_QUERY_PARAM" +
|
||||
account.signer.pubKey
|
||||
.hexToByteArray()
|
||||
.toNpub()
|
||||
|
||||
notificationManager()
|
||||
.sendReactionNotification(
|
||||
event.id,
|
||||
content,
|
||||
title,
|
||||
event.createdAt,
|
||||
userPicture,
|
||||
noteUri,
|
||||
applicationContext,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun notifyChessEvent(
|
||||
event: BaseChessEvent,
|
||||
account: Account,
|
||||
|
||||
+54
@@ -45,6 +45,10 @@ import kotlinx.coroutines.withContext
|
||||
object NotificationUtils {
|
||||
private var dmChannel: NotificationChannel? = null
|
||||
private var zapChannel: NotificationChannel? = null
|
||||
private var reactionChannel: NotificationChannel? = null
|
||||
private const val DM_GROUP_KEY = "com.vitorpamplona.amethyst.DM_NOTIFICATION"
|
||||
private const val ZAP_GROUP_KEY = "com.vitorpamplona.amethyst.ZAP_NOTIFICATION"
|
||||
private const val REACTION_GROUP_KEY = "com.vitorpamplona.amethyst.REACTION_NOTIFICATION"
|
||||
private var chessChannel: NotificationChannel? = null
|
||||
private const val DM_GROUP_KEY = "com.vitorpamplona.amethyst.DM_NOTIFICATION"
|
||||
private const val ZAP_GROUP_KEY = "com.vitorpamplona.amethyst.ZAP_NOTIFICATION"
|
||||
@@ -58,6 +62,7 @@ object NotificationUtils {
|
||||
|
||||
private const val DM_SUMMARY_ID = 0x10000
|
||||
private const val ZAP_SUMMARY_ID = 0x20000
|
||||
private const val REACTION_SUMMARY_ID = 0x40000
|
||||
private const val CHESS_SUMMARY_ID = 0x30000
|
||||
|
||||
fun getOrCreateDMChannel(applicationContext: Context): NotificationChannel {
|
||||
@@ -102,6 +107,27 @@ object NotificationUtils {
|
||||
return zapChannel!!
|
||||
}
|
||||
|
||||
fun getOrCreateReactionChannel(applicationContext: Context): NotificationChannel {
|
||||
if (reactionChannel != null) return reactionChannel!!
|
||||
|
||||
reactionChannel =
|
||||
NotificationChannel(
|
||||
stringRes(applicationContext, R.string.app_notification_reactions_channel_id),
|
||||
stringRes(applicationContext, R.string.app_notification_reactions_channel_name),
|
||||
NotificationManager.IMPORTANCE_DEFAULT,
|
||||
).apply {
|
||||
description =
|
||||
stringRes(applicationContext, R.string.app_notification_reactions_channel_description)
|
||||
}
|
||||
|
||||
val notificationManager: NotificationManager =
|
||||
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
notificationManager.createNotificationChannel(reactionChannel!!)
|
||||
|
||||
return reactionChannel!!
|
||||
}
|
||||
|
||||
fun getOrCreateChessChannel(applicationContext: Context): NotificationChannel {
|
||||
if (chessChannel != null) return chessChannel!!
|
||||
|
||||
@@ -122,7 +148,35 @@ object NotificationUtils {
|
||||
|
||||
return chessChannel!!
|
||||
}
|
||||
|
||||
suspend fun NotificationManager.sendChessNotification(
|
||||
id: String,
|
||||
messageBody: String,
|
||||
messageTitle: String,
|
||||
time: Long,
|
||||
pictureUrl: String?,
|
||||
uri: String,
|
||||
applicationContext: Context,
|
||||
) {
|
||||
getOrCreateReactionChannel(applicationContext)
|
||||
val channelId = stringRes(applicationContext, R.string.app_notification_reactions_channel_id)
|
||||
|
||||
sendNotification(
|
||||
id = id,
|
||||
messageBody = messageBody,
|
||||
messageTitle = messageTitle,
|
||||
time = time,
|
||||
pictureUrl = pictureUrl,
|
||||
uri = uri,
|
||||
channelId = channelId,
|
||||
notificationGroupKey = REACTION_GROUP_KEY,
|
||||
category = NotificationCompat.CATEGORY_SOCIAL,
|
||||
summaryId = REACTION_SUMMARY_ID,
|
||||
summaryText = stringRes(applicationContext, R.string.app_notification_reactions_summary),
|
||||
applicationContext = applicationContext,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun NotificationManager.sendChessNotification(
|
||||
id: String,
|
||||
messageBody: String,
|
||||
|
||||
@@ -751,6 +751,12 @@
|
||||
<string name="app_notification_dms_summary">New messages</string>
|
||||
<string name="app_notification_zaps_summary">New zaps</string>
|
||||
|
||||
<string name="app_notification_reactions_channel_id" translatable="false">ReactionsID</string>
|
||||
<string name="app_notification_reactions_channel_name">Reactions</string>
|
||||
<string name="app_notification_reactions_channel_description">Notifies you when somebody reacts to your post</string>
|
||||
<string name="app_notification_reactions_channel_message">%1$s reacted to your post</string>
|
||||
<string name="app_notification_reactions_channel_message_for">for %1$s</string>
|
||||
<string name="app_notification_reactions_summary">New reactions</string>
|
||||
<string name="app_notification_chess_channel_id" translatable="false">ChessID</string>
|
||||
<string name="app_notification_chess_channel_name">Chess</string>
|
||||
<string name="app_notification_chess_channel_description">Notifies you about chess game events</string>
|
||||
|
||||
Reference in New Issue
Block a user