mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-05-29 13:00:17 +02:00
feat: friend mutation observer
- bitmoji, birthday changes
This commit is contained in:
parent
343159ee5b
commit
95eb4e89f6
@ -538,9 +538,9 @@
|
|||||||
"name": "Instant Delete",
|
"name": "Instant Delete",
|
||||||
"description": "Removes the confirmation dialog when deleting messages"
|
"description": "Removes the confirmation dialog when deleting messages"
|
||||||
},
|
},
|
||||||
"relationship_notifier": {
|
"friend_mutation_notifier": {
|
||||||
"name": "Relationship Notifier",
|
"name": "Friend Mutation Notifier",
|
||||||
"description": "Notifies you when someone removes you as a friend"
|
"description": "Notifies you when something changes in a friend's profile"
|
||||||
},
|
},
|
||||||
"better_notifications": {
|
"better_notifications": {
|
||||||
"name": "Better Notifications",
|
"name": "Better Notifications",
|
||||||
@ -1114,6 +1114,14 @@
|
|||||||
"auto_mark_as_read": {
|
"auto_mark_as_read": {
|
||||||
"conversation_read": "Mark conversation as read when sending a message",
|
"conversation_read": "Mark conversation as read when sending a message",
|
||||||
"snap_reply": "Mark snaps as read when replying to them"
|
"snap_reply": "Mark snaps as read when replying to them"
|
||||||
|
},
|
||||||
|
"friend_mutation_observer": {
|
||||||
|
"remove_friend": "Notify when someone removes you as a friend",
|
||||||
|
"birthday_changes": "Notify when someone changes their birthday",
|
||||||
|
"bitmoji_selfie_changes": "Notify when someone changes their Bitmoji selfie",
|
||||||
|
"bitmoji_avatar_changes": "Notify when someone changes their Bitmoji avatar",
|
||||||
|
"bitmoji_background_changes": "Notify when someone changes their Bitmoji background",
|
||||||
|
"bitmoji_scene_changes": "Notify when someone changes their Bitmoji scene"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1382,9 +1390,14 @@
|
|||||||
|
|
||||||
"friend_mutation_observer": {
|
"friend_mutation_observer": {
|
||||||
"notification_channel_name": "Friend Mutation Observer",
|
"notification_channel_name": "Friend Mutation Observer",
|
||||||
"removed_friend_notification_title": "Friend Removed",
|
"friend_removed": "{username} has removed you as a friend",
|
||||||
"removed_friend_notification_content": "{username} has removed you as a friend",
|
"birthday_removed": "{username} has removed their birthday ({birthday})",
|
||||||
"removed_friend_notification_content_with_display_name": "{displayName} ({username}) has removed you as a friend"
|
"birthday_added": "{username} has added their birthday ({birthday})",
|
||||||
|
"birthday_changed": "{username} has changed their birthday from {oldBirthday} to {newBirthday}",
|
||||||
|
"bitmoji_selfie_changed": "{username} has changed their Bitmoji selfie",
|
||||||
|
"bitmoji_avatar_changed": "{username} has changed their Bitmoji avatar",
|
||||||
|
"bitmoji_background_changed": "{username} has changed their Bitmoji background",
|
||||||
|
"bitmoji_scene_changed": "{username} has changed their Bitmoji scene"
|
||||||
},
|
},
|
||||||
|
|
||||||
"suspend_location_updates": {
|
"suspend_location_updates": {
|
||||||
|
@ -73,7 +73,14 @@ class MessagingTweaks : ConfigContainer() {
|
|||||||
nativeHooks()
|
nativeHooks()
|
||||||
}
|
}
|
||||||
val instantDelete = boolean("instant_delete") { requireRestart() }
|
val instantDelete = boolean("instant_delete") { requireRestart() }
|
||||||
val relationshipNotifier = boolean("relationship_notifier") { requireRestart() }
|
val friendMutationObserver = multiple("friend_mutation_observer",
|
||||||
|
"remove_friend",
|
||||||
|
"birthday_changes",
|
||||||
|
"bitmoji_selfie_changes",
|
||||||
|
"bitmoji_avatar_changes",
|
||||||
|
"bitmoji_background_changes",
|
||||||
|
"bitmoji_scene_changes",
|
||||||
|
) { requireRestart() }
|
||||||
val betterNotifications = multiple("better_notifications",
|
val betterNotifications = multiple("better_notifications",
|
||||||
"chat_preview",
|
"chat_preview",
|
||||||
"media_preview",
|
"media_preview",
|
||||||
|
@ -7,11 +7,13 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.WarningAmber
|
import androidx.compose.material.icons.filled.WarningAmber
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import me.rhunk.snapenhance.common.data.FriendLinkType
|
import me.rhunk.snapenhance.common.data.FriendLinkType
|
||||||
|
import me.rhunk.snapenhance.common.database.impl.FriendInfo
|
||||||
import me.rhunk.snapenhance.core.event.events.impl.NetworkApiRequestEvent
|
import me.rhunk.snapenhance.core.event.events.impl.NetworkApiRequestEvent
|
||||||
import me.rhunk.snapenhance.core.features.Feature
|
import me.rhunk.snapenhance.core.features.Feature
|
||||||
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
||||||
import me.rhunk.snapenhance.core.util.EvictingMap
|
import me.rhunk.snapenhance.core.util.EvictingMap
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
class FriendMutationObserver: Feature("FriendMutationObserver", loadParams = FeatureLoadParams.INIT_SYNC) {
|
class FriendMutationObserver: Feature("FriendMutationObserver", loadParams = FeatureLoadParams.INIT_SYNC) {
|
||||||
private val translation by lazy { context.translation.getCategory("friend_mutation_observer") }
|
private val translation by lazy { context.translation.getCategory("friend_mutation_observer") }
|
||||||
@ -34,29 +36,45 @@ class FriendMutationObserver: Feature("FriendMutationObserver", loadParams = Fea
|
|||||||
return addSourceCache[userId]
|
return addSourceCache[userId]
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendFriendRemoveNotification(displayName: String?, username: String) {
|
private fun sendWarnNotification(
|
||||||
val contentText = (if (displayName != null)
|
contentText: String
|
||||||
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(),
|
notificationManager.notify(System.nanoTime().toInt(),
|
||||||
Notification.Builder(context.androidContext, channelId)
|
Notification.Builder(context.androidContext, channelId)
|
||||||
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
||||||
.setContentTitle(translation["removed_friend_notification_title"])
|
.setContentTitle(translation["notification_channel_name"])
|
||||||
.setContentText(contentText)
|
.setContentText(contentText)
|
||||||
.setShowWhen(true)
|
.setShowWhen(true)
|
||||||
.setWhen(System.currentTimeMillis())
|
.setWhen(System.currentTimeMillis())
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
|
|
||||||
context.inAppOverlay.showStatusToast(
|
context.inAppOverlay.showStatusToast(
|
||||||
Icons.Default.WarningAmber,
|
Icons.Default.WarningAmber,
|
||||||
contentText,
|
contentText,
|
||||||
durationMs = 6000
|
durationMs = 7000
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun formatUsername(friendInfo: FriendInfo): String {
|
||||||
|
return friendInfo.displayName?.takeIf { it.isNotBlank() }?.let {
|
||||||
|
"$it (${friendInfo.mutableUsername})"
|
||||||
|
} ?: friendInfo.mutableUsername ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prettyPrintBirthday(month: Int, day: Int): String {
|
||||||
|
val calendar = Calendar.getInstance()
|
||||||
|
calendar[Calendar.MONTH] = month
|
||||||
|
return calendar.getDisplayName(
|
||||||
|
Calendar.MONTH,
|
||||||
|
Calendar.LONG,
|
||||||
|
context.translation.loadedLocale
|
||||||
|
)?.toString() + " " + day
|
||||||
|
}
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
|
val config by context.config.messaging.friendMutationObserver
|
||||||
|
|
||||||
context.event.subscribe(NetworkApiRequestEvent::class) { event ->
|
context.event.subscribe(NetworkApiRequestEvent::class) { event ->
|
||||||
if (!event.url.contains("ami/friends")) return@subscribe
|
if (!event.url.contains("ami/friends")) return@subscribe
|
||||||
event.onSuccess { buffer ->
|
event.onSuccess { buffer ->
|
||||||
@ -74,20 +92,60 @@ class FriendMutationObserver: Feature("FriendMutationObserver", loadParams = Fea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.config.messaging.relationshipNotifier.get()) {
|
if (config.isEmpty()) return@runCatching
|
||||||
jsonObject.getAsJsonArray("friends").map { it.asJsonObject }.forEach { friend ->
|
|
||||||
|
jsonObject.getAsJsonArray("friends").map { it.asJsonObject }.forEach { friend ->
|
||||||
|
runCatching {
|
||||||
val userId = friend.get("user_id")?.asString
|
val userId = friend.get("user_id")?.asString
|
||||||
if (userId == context.database.myUserId) return@forEach
|
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 databaseFriend = context.database.getFriendInfo(userId ?: return@forEach) ?: return@forEach
|
||||||
val mutableUsername = friend.get("mutable_username").asString
|
if (FriendLinkType.fromValue(databaseFriend.friendLinkType) != FriendLinkType.MUTUAL) return@forEach
|
||||||
val databaseLinkType = FriendLinkType.fromValue(databaseFriend.friendLinkType)
|
|
||||||
|
|
||||||
if (databaseLinkType == FriendLinkType.MUTUAL && !friend.has("fidelius_info")) {
|
if (config.contains("remove_friend") && friend.get("direction")?.asString == "OUTGOING" && !friend.has("fidelius_info")) {
|
||||||
sendFriendRemoveNotification(databaseFriend.displayName, mutableUsername)
|
sendWarnNotification(translation.format("friend_removed", "username" to formatUsername(databaseFriend)))
|
||||||
|
return@forEach
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.contains("birthday_changes") &&
|
||||||
|
databaseFriend.birthday.takeIf { it != 0L }?.let {
|
||||||
|
((it shr 32).toInt()).toString().padStart(2, '0') + "-" + (it.toInt()).toString().padStart(2, '0')
|
||||||
|
} != friend.get("birthday")?.asString
|
||||||
|
) {
|
||||||
|
val oldBirthday = databaseFriend.birthday.takeIf { it != 0L }?.let {
|
||||||
|
prettyPrintBirthday((it shr 32).toInt(), it.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!friend.has("birthday")) {
|
||||||
|
sendWarnNotification(translation.format("birthday_removed", "username" to formatUsername(databaseFriend), "birthday" to oldBirthday.orEmpty()))
|
||||||
|
} else {
|
||||||
|
val newBirthday = friend.get("birthday")?.asString?.split("-")?.let {
|
||||||
|
prettyPrintBirthday(it[0].toInt(), it[1].toInt())
|
||||||
|
}
|
||||||
|
if (oldBirthday == null) {
|
||||||
|
sendWarnNotification(translation.format("birthday_added", "username" to formatUsername(databaseFriend), "birthday" to newBirthday.orEmpty()))
|
||||||
|
} else {
|
||||||
|
sendWarnNotification(translation.format("birthday_changed", "username" to formatUsername(databaseFriend), "oldBirthday" to oldBirthday, "newBirthday" to newBirthday.orEmpty()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.contains("bitmoji_avatar_changes") && databaseFriend.bitmojiSelfieId != friend.get("bitmoji_avatar_id")?.asString) {
|
||||||
|
sendWarnNotification(translation.format("bitmoji_avatar_changed", "username" to formatUsername(databaseFriend)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.contains("bitmoji_selfie_changes") && databaseFriend.bitmojiAvatarId != friend.get("bitmoji_selfie_id")?.asString) {
|
||||||
|
sendWarnNotification(translation.format("bitmoji_selfie_changed", "username" to formatUsername(databaseFriend)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.contains("bitmoji_background_changes") && databaseFriend.bitmojiBackgroundId != friend.get("bitmoji_background_id")?.asString) {
|
||||||
|
sendWarnNotification(translation.format("bitmoji_background_changed", "username" to formatUsername(databaseFriend)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.contains("bitmoji_scene_changes") && databaseFriend.bitmojiSceneId != friend.get("bitmoji_scene_id")?.asString) {
|
||||||
|
sendWarnNotification(translation.format("bitmoji_scene_changed", "username" to formatUsername(databaseFriend)))
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
context.log.error("Failed to process friend", it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user