fix(core/better_notifications): handle status message

- add new content types
This commit is contained in:
rhunk
2023-11-08 19:24:15 +01:00
parent 81f626cc3b
commit 4bf421441b
4 changed files with 66 additions and 26 deletions

View File

@ -605,8 +605,8 @@
"always_dark": "Always Dark" "always_dark": "Always Dark"
}, },
"better_notifications": { "better_notifications": {
"chat": "Show chat messages", "chat_preview": "Show a preview of chat",
"snap": "Show media", "media_preview": "Show a preview of media",
"reply_button": "Add reply button", "reply_button": "Add reply button",
"download_button": "Add download button", "download_button": "Add download button",
"mark_as_read_button": "Mark as Read button", "mark_as_read_button": "Mark as Read button",
@ -722,6 +722,29 @@
"anti_auto_save": "Anti Auto Save" "anti_auto_save": "Anti Auto Save"
}, },
"content_type": {
"CHAT": "Chat",
"SNAP": "Snap",
"EXTERNAL_MEDIA": "External Media",
"NOTE": "Audio Note",
"STICKER": "Sticker",
"STATUS": "Status",
"LOCATION": "Location",
"STATUS_SAVE_TO_CAMERA_ROLL": "Saved to Camera Roll",
"STATUS_CONVERSATION_CAPTURE_SCREENSHOT": "Screenshot",
"STATUS_CONVERSATION_CAPTURE_RECORD": "Screen Record",
"STATUS_CALL_MISSED_VIDEO": "Missed Video Call",
"STATUS_CALL_MISSED_AUDIO": "Missed Audio Call",
"LIVE_LOCATION_SHARE": "Live Location Share",
"CREATIVE_TOOL_ITEM": "Creative Tool Item",
"FAMILY_CENTER_INVITE": "Family Center Invite",
"FAMILY_CENTER_ACCEPT": "Family Center Accept",
"FAMILY_CENTER_LEAVE": "Family Center Leave",
"STATUS_PLUS_GIFT": "Status Plus Gift",
"TINY_SNAP": "Tiny Snap",
"STATUS_COUNTDOWN": "Countdown"
},
"chat_action_menu": { "chat_action_menu": {
"preview_button": "Preview", "preview_button": "Preview",
"download_button": "Download", "download_button": "Download",

View File

@ -24,7 +24,7 @@ class MessagingTweaks : ConfigContainer() {
nativeHooks() nativeHooks()
} }
val instantDelete = boolean("instant_delete") { requireRestart() } val instantDelete = boolean("instant_delete") { requireRestart() }
val betterNotifications = multiple("better_notifications", "snap", "chat", "reply_button", "download_button", "mark_as_read_button", "group") { requireRestart() } val betterNotifications = multiple("better_notifications", "chat_preview", "media_preview", "reply_button", "download_button", "mark_as_read_button", "group") { requireRestart() }
val notificationBlacklist = multiple("notification_blacklist", *NotificationType.getIncomingValues().map { it.key }.toTypedArray()) { val notificationBlacklist = multiple("notification_blacklist", *NotificationType.getIncomingValues().map { it.key }.toTypedArray()) {
customOptionTranslationPath = "features.options.notifications" customOptionTranslationPath = "features.options.notifications"
} }

View File

@ -71,7 +71,9 @@ enum class ContentType(val id: Int) {
FAMILY_CENTER_INVITE(15), FAMILY_CENTER_INVITE(15),
FAMILY_CENTER_ACCEPT(16), FAMILY_CENTER_ACCEPT(16),
FAMILY_CENTER_LEAVE(17), FAMILY_CENTER_LEAVE(17),
STATUS_PLUS_GIFT(18); STATUS_PLUS_GIFT(18),
TINY_SNAP(19),
STATUS_COUNTDOWN(20);
companion object { companion object {
fun fromId(i: Int): ContentType { fun fromId(i: Int): ContentType {

View File

@ -94,7 +94,7 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
notification notification
) as Notification.Builder ) as Notification.Builder
private fun setNotificationText(notification: Notification, conversationId: String) { private fun computeNotificationMessages(notification: Notification, conversationId: String) {
val messageText = StringBuilder().apply { val messageText = StringBuilder().apply {
cachedMessages.computeIfAbsent(conversationId) { sortedMapOf() }.forEach { cachedMessages.computeIfAbsent(conversationId) { sortedMapOf() }.forEach {
if (isNotEmpty()) append("\n") if (isNotEmpty()) append("\n")
@ -147,7 +147,7 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
} }
newAction(translations["button.download"], ACTION_DOWNLOAD, { newAction(translations["button.download"], ACTION_DOWNLOAD, {
betterNotificationFilter.contains("download_button") && (contentType == ContentType.EXTERNAL_MEDIA || contentType == ContentType.SNAP) betterNotificationFilter.contains("download_button") && betterNotificationFilter.contains("media_preview") && (contentType == ContentType.EXTERNAL_MEDIA || contentType == ContentType.SNAP)
}) {} }) {}
newAction(translations["button.mark_as_read"], ACTION_MARK_AS_READ, { newAction(translations["button.mark_as_read"], ACTION_MARK_AS_READ, {
@ -182,7 +182,7 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
updateNotification(notificationId) { notification -> updateNotification(notificationId) { notification ->
notification.flags = notification.flags or Notification.FLAG_ONLY_ALERT_ONCE notification.flags = notification.flags or Notification.FLAG_ONLY_ALERT_ONCE
setNotificationText(notification, conversationId) computeNotificationMessages(notification, conversationId)
} }
} }
} }
@ -256,7 +256,7 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
private fun sendNotification(message: Message, notificationData: NotificationData, forceCreate: Boolean) { private fun sendNotification(message: Message, notificationData: NotificationData, forceCreate: Boolean) {
val conversationId = message.messageDescriptor?.conversationId.toString() val conversationId = message.messageDescriptor?.conversationId.toString()
val notificationId = if (forceCreate) System.nanoTime().toInt() else notificationData.id val notificationId = if (forceCreate) System.nanoTime().toInt() else message.messageDescriptor?.conversationId?.toBytes().contentHashCode()
sentNotifications.computeIfAbsent(notificationId) { conversationId } sentNotifications.computeIfAbsent(notificationId) { conversationId }
if (betterNotificationFilter.contains("group")) { if (betterNotificationFilter.contains("group")) {
@ -286,7 +286,7 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
}.send() }.send()
} }
private fun onMessageReceived(data: NotificationData, message: Message) { private fun onMessageReceived(data: NotificationData, notificationType: String, message: Message) {
val conversationId = message.messageDescriptor?.conversationId.toString() val conversationId = message.messageDescriptor?.conversationId.toString()
val orderKey = message.orderKey ?: return val orderKey = message.orderKey ?: return
val senderUsername by lazy { val senderUsername by lazy {
@ -295,21 +295,30 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
} ?: "Unknown" } ?: "Unknown"
} }
val formatUsername: (String) -> String = { "$senderUsername: $it" } val contentType = message.messageContent!!.contentType!!.let { contentType ->
val notificationCache = cachedMessages.let { it.computeIfAbsent(conversationId) { sortedMapOf() } } when {
val appendNotifications: () -> Unit = { setNotificationText(data.notification, conversationId)} notificationType.contains("screenshot") -> ContentType.STATUS_CONVERSATION_CAPTURE_SCREENSHOT
else -> contentType
when (val contentType = message.messageContent!!.contentType) {
ContentType.NOTE -> {
notificationCache[orderKey] = formatUsername("sent audio note")
appendNotifications()
} }
}
val computeMessages: () -> Unit = { computeNotificationMessages(data.notification, conversationId)}
fun setNotificationText(text: String, includeUsername: Boolean = true) {
cachedMessages.computeIfAbsent(conversationId) {
sortedMapOf()
}[orderKey] = if (includeUsername) "$senderUsername: $text" else text
}
when (
contentType.takeIf {
(it != ContentType.SNAP && it != ContentType.EXTERNAL_MEDIA) || betterNotificationFilter.contains("media_preview")
} ?: ContentType.UNKNOWN
) {
ContentType.CHAT -> { ContentType.CHAT -> {
ProtoReader(message.messageContent!!.content!!).getString(2, 1)?.trim()?.let { ProtoReader(message.messageContent!!.content!!).getString(2, 1)?.trim()?.let {
notificationCache[orderKey] = formatUsername(it) setNotificationText(it)
} }
appendNotifications() computeMessages()
} }
ContentType.SNAP, ContentType.EXTERNAL_MEDIA -> { ContentType.SNAP, ContentType.EXTERNAL_MEDIA -> {
val mediaReferences = MessageDecoder.getMediaReferences( val mediaReferences = MessageDecoder.getMediaReferences(
@ -353,10 +362,11 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
} }
} }
else -> { else -> {
notificationCache[orderKey] = formatUsername("sent ${contentType?.name?.lowercase()}") setNotificationText("[" + context.translation.getCategory("content_type")[contentType.name] + "]")
appendNotifications() computeMessages()
} }
} }
if (!betterNotificationFilter.contains("chat_preview")) return
sendNotification(message, data, false) sendNotification(message, data, false)
} }
@ -377,9 +387,8 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
} ?: return@hook } ?: return@hook
val serverMessageId = extras.getString("message_id") ?: return@hook val serverMessageId = extras.getString("message_id") ?: return@hook
val notificationType = extras.getString("notification_type") ?: return@hook val notificationType = extras.getString("notification_type")?.lowercase() ?: return@hook
if (!betterNotificationFilter.contains("chat_preview") && !betterNotificationFilter.contains("media_preview")) return@hook
if (betterNotificationFilter.none { notificationType.contains(it, ignoreCase = true) }) return@hook
param.setResult(null) param.setResult(null)
val conversationManager = context.feature(Messaging::class).conversationManager ?: return@hook val conversationManager = context.feature(Messaging::class).conversationManager ?: return@hook
@ -387,10 +396,16 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN
context.coroutineScope.launch(coroutineDispatcher) { context.coroutineScope.launch(coroutineDispatcher) {
suspendCoroutine { continuation -> suspendCoroutine { continuation ->
conversationManager.fetchMessageByServerId(conversationId, serverMessageId, onSuccess = { conversationManager.fetchMessageByServerId(conversationId, serverMessageId, onSuccess = {
onMessageReceived(notificationData, it) if (it.senderId.toString() == context.database.myUserId) {
param.invokeOriginal()
continuation.resumeWith(Result.success(Unit))
return@fetchMessageByServerId
}
onMessageReceived(notificationData, notificationType, it)
continuation.resumeWith(Result.success(Unit)) continuation.resumeWith(Result.success(Unit))
}, onError = { }, onError = {
context.log.error("Failed to fetch message id ${serverMessageId}: $it") context.log.error("Failed to fetch message id ${serverMessageId}: $it")
param.invokeOriginal()
continuation.resumeWith(Result.success(Unit)) continuation.resumeWith(Result.success(Unit))
}) })
} }