commit 0e4667603a5130185f34222914bf719b0f23dd93
parent e7df5d1edfabb6dc624af1f8c1c0596d1e0b28c3
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Fri, 19 Apr 2024 00:33:25 +0200

feat(core): relationship notifier

Diffstat:
Mcommon/src/main/assets/lang/en_US.json | 11+++++++++++
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/MessagingTweaks.kt | 1+
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/FriendMutationObserver.kt | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json @@ -538,6 +538,10 @@ "name": "Instant Delete", "description": "Removes the confirmation dialog when deleting messages" }, + "relationship_notifier": { + "name": "Relationship Notifier", + "description": "Notifies you when someone removes you as a friend" + }, "better_notifications": { "name": "Better Notifications", "description": "Adds more information in received notifications" @@ -1376,6 +1380,13 @@ "notification_content": "{count} Snaps opened" }, + "friend_mutation_observer": { + "notification_channel_name": "Friend Mutation Observer", + "removed_friend_notification_title": "Friend Removed", + "removed_friend_notification_content": "{username} has removed you as a friend", + "removed_friend_notification_content_with_display_name": "{displayName} ({username}) has removed you as a friend" + }, + "suspend_location_updates": { "switch_text": "Suspend Location Updates" }, diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/MessagingTweaks.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/MessagingTweaks.kt @@ -73,6 +73,7 @@ class MessagingTweaks : ConfigContainer() { nativeHooks() } val instantDelete = boolean("instant_delete") { requireRestart() } + val relationshipNotifier = boolean("relationship_notifier") { requireRestart() } val betterNotifications = multiple("better_notifications", "chat_preview", "media_preview", diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/FriendMutationObserver.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/FriendMutationObserver.kt @@ -1,6 +1,12 @@ package me.rhunk.snapenhance.core.features.impl +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.WarningAmber import com.google.gson.JsonObject +import me.rhunk.snapenhance.common.data.FriendLinkType import me.rhunk.snapenhance.core.event.events.impl.NetworkApiRequestEvent import me.rhunk.snapenhance.core.features.Feature import me.rhunk.snapenhance.core.features.FeatureLoadParams @@ -8,12 +14,46 @@ import me.rhunk.snapenhance.core.util.EvictingMap import java.io.InputStreamReader class FriendMutationObserver: Feature("FriendMutationObserver", loadParams = FeatureLoadParams.INIT_SYNC) { + private val translation by lazy { context.translation.getCategory("friend_mutation_observer") } private val addSourceCache = EvictingMap<String, String>(500) + private val notificationManager get() = context.androidContext.getSystemService(NotificationManager::class.java) + private val channelId = "friend_mutation_observer".also { + notificationManager.createNotificationChannel( + NotificationChannel( + it, + translation["notification_channel_name"], + NotificationManager.IMPORTANCE_HIGH + ) + ) + } + fun getFriendAddSource(userId: String): String? { return addSourceCache[userId] } + private fun sendFriendRemoveNotification(displayName: String?, username: String) { + val contentText = (if (displayName != null) + translation.format("removed_friend_notification_content_with_display_name", "displayName" to displayName, "username" to username) + else translation.format("removed_friend_notification_content", "username" to username)) + + notificationManager.notify(System.nanoTime().toInt(), + Notification.Builder(context.androidContext, channelId) + .setSmallIcon(android.R.drawable.ic_dialog_alert) + .setContentTitle(translation["removed_friend_notification_title"]) + .setContentText(contentText) + .setShowWhen(true) + .setWhen(System.currentTimeMillis()) + .build() + ) + + context.inAppOverlay.showStatusToast( + Icons.Default.WarningAmber, + contentText, + durationMs = 6000 + ) + } + override fun init() { context.event.subscribe(NetworkApiRequestEvent::class) { event -> if (!event.url.contains("ami/friends")) return@subscribe @@ -31,6 +71,23 @@ class FriendMutationObserver: Feature("FriendMutationObserver", loadParams = Fea addSourceCache[userId] = it } } + + if (context.config.messaging.relationshipNotifier.get()) { + jsonObject.getAsJsonArray("friends").map { it.asJsonObject }.forEach { friend -> + val userId = friend.get("user_id")?.asString + if (userId == context.database.myUserId) return@forEach + val direction = friend.get("direction")?.asString + if (direction != "OUTGOING") return@forEach + + val databaseFriend = context.database.getFriendInfo(userId ?: return@forEach) ?: return@forEach + val mutableUsername = friend.get("mutable_username").asString + val databaseLinkType = FriendLinkType.fromValue(databaseFriend.friendLinkType) + + if (databaseLinkType == FriendLinkType.MUTUAL && !friend.has("fidelius_info")) { + sendFriendRemoveNotification(databaseFriend.displayName, mutableUsername) + } + } + } }.onFailure { context.log.error("Failed to process friends", it) }