mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-05-19 07:37:09 +02:00
feat: instant delete
This commit is contained in:
parent
17f81eb682
commit
a63bca9782
@ -344,6 +344,10 @@
|
|||||||
"name": "Prevent Message Sending",
|
"name": "Prevent Message Sending",
|
||||||
"description": "Prevents sending certain types of messages"
|
"description": "Prevents sending certain types of messages"
|
||||||
},
|
},
|
||||||
|
"instant_delete": {
|
||||||
|
"name": "Instant Delete",
|
||||||
|
"description": "Removes the confirmation dialog when deleting messages"
|
||||||
|
},
|
||||||
"better_notifications": {
|
"better_notifications": {
|
||||||
"name": "Better Notifications",
|
"name": "Better Notifications",
|
||||||
"description": "Adds more information in received notifications"
|
"description": "Adds more information in received notifications"
|
||||||
|
@ -23,6 +23,7 @@ class MessagingTweaks : ConfigContainer() {
|
|||||||
customOptionTranslationPath = "features.options.notifications"
|
customOptionTranslationPath = "features.options.notifications"
|
||||||
nativeHooks()
|
nativeHooks()
|
||||||
}
|
}
|
||||||
|
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", "snap", "chat", "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"
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
package me.rhunk.snapenhance.core.features.impl.messaging
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import me.rhunk.snapenhance.common.data.MessageUpdate
|
||||||
|
import me.rhunk.snapenhance.core.event.events.impl.BindViewEvent
|
||||||
|
import me.rhunk.snapenhance.core.features.Feature
|
||||||
|
import me.rhunk.snapenhance.core.features.FeatureLoadParams
|
||||||
|
import me.rhunk.snapenhance.core.ui.iterateParent
|
||||||
|
import me.rhunk.snapenhance.core.ui.triggerCloseTouchEvent
|
||||||
|
import me.rhunk.snapenhance.core.util.ktx.getId
|
||||||
|
import me.rhunk.snapenhance.core.util.ktx.getIdentifier
|
||||||
|
import me.rhunk.snapenhance.core.util.ktx.setObjectField
|
||||||
|
import me.rhunk.snapenhance.core.wrapper.impl.CallbackResult
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
|
||||||
|
class InstantDelete : Feature("InstantDelete", loadParams = FeatureLoadParams.ACTIVITY_CREATE_ASYNC) {
|
||||||
|
override fun asyncOnActivityCreate() {
|
||||||
|
if (!context.config.messaging.instantDelete.get()) return
|
||||||
|
val chatActionMenuOptions = listOf(
|
||||||
|
"chat_action_menu_erase_messages",
|
||||||
|
"chat_action_menu_erase_quote",
|
||||||
|
"chat_action_menu_erase_reply",
|
||||||
|
).associateWith { context.resources.getString(context.resources.getIdentifier(it, "string")) }
|
||||||
|
|
||||||
|
val chatActionMenuContainerID = context.resources.getId("chat_action_menu_container")
|
||||||
|
val actionMenuOptionId = context.resources.getId("action_menu_option")
|
||||||
|
val actionMenuOptionTextId = context.resources.getId("action_menu_option_text")
|
||||||
|
|
||||||
|
context.event.subscribe(BindViewEvent::class) { event ->
|
||||||
|
if (event.view.id != actionMenuOptionId) return@subscribe
|
||||||
|
|
||||||
|
val menuOptionText = event.view.findViewById<TextView>(actionMenuOptionTextId) ?: return@subscribe
|
||||||
|
if (!chatActionMenuOptions.values.contains(menuOptionText.text)) return@subscribe
|
||||||
|
|
||||||
|
val viewModel = event.prevModel
|
||||||
|
|
||||||
|
val nestedViewOnClickListenerField = viewModel::class.java.fields.find {
|
||||||
|
it.type == View.OnClickListener::class.java
|
||||||
|
} ?: return@subscribe
|
||||||
|
|
||||||
|
val nestedViewOnClickListener = nestedViewOnClickListenerField.get(viewModel) as? View.OnClickListener ?: return@subscribe
|
||||||
|
|
||||||
|
val chatViewModel = nestedViewOnClickListener::class.java.fields.find {
|
||||||
|
Modifier.isAbstract(it.type.modifiers) && runCatching {
|
||||||
|
it.get(nestedViewOnClickListener)
|
||||||
|
}.getOrNull().toString().startsWith("ChatViewModel")
|
||||||
|
}?.get(nestedViewOnClickListener) ?: return@subscribe
|
||||||
|
|
||||||
|
//[convId]:arroyo-id:[messageId]
|
||||||
|
val (conversationId, messageId) = chatViewModel.toString().substringAfter("messageId=").substringBefore(",").split(":").let {
|
||||||
|
if (it.size != 3) return@let null
|
||||||
|
it[0] to it[2]
|
||||||
|
} ?: return@subscribe
|
||||||
|
|
||||||
|
viewModel.setObjectField(nestedViewOnClickListenerField.name, View.OnClickListener { view ->
|
||||||
|
val onCallbackResult: CallbackResult = callbackResult@{
|
||||||
|
if (it == null || it == "DUPLICATEREQUEST") return@callbackResult
|
||||||
|
context.log.error("Error deleting message $messageId: $it")
|
||||||
|
context.shortToast("Error deleting message $messageId: $it. Using fallback method")
|
||||||
|
context.runOnUiThread {
|
||||||
|
nestedViewOnClickListener.onClick(view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runCatching {
|
||||||
|
val conversationManager = context.feature(Messaging::class).conversationManager ?: return@runCatching
|
||||||
|
|
||||||
|
if (chatActionMenuOptions["chat_action_menu_erase_quote"] == menuOptionText.text) {
|
||||||
|
conversationManager.fetchMessage(conversationId, messageId.toLong(), onSuccess = { message ->
|
||||||
|
val quotedMessage = message.messageContent.quotedMessage.takeIf { it.isPresent() }!!
|
||||||
|
|
||||||
|
conversationManager.updateMessage(
|
||||||
|
conversationId,
|
||||||
|
quotedMessage.content.messageId,
|
||||||
|
MessageUpdate.ERASE,
|
||||||
|
onResult = onCallbackResult
|
||||||
|
)
|
||||||
|
}, onError = {
|
||||||
|
onCallbackResult(it)
|
||||||
|
})
|
||||||
|
return@runCatching
|
||||||
|
}
|
||||||
|
|
||||||
|
conversationManager.updateMessage(
|
||||||
|
conversationId,
|
||||||
|
messageId.toLong(),
|
||||||
|
MessageUpdate.ERASE,
|
||||||
|
onResult = onCallbackResult
|
||||||
|
)
|
||||||
|
}.onFailure {
|
||||||
|
context.log.error("Error deleting message $messageId", it)
|
||||||
|
onCallbackResult(it.message)
|
||||||
|
return@OnClickListener
|
||||||
|
}
|
||||||
|
|
||||||
|
view.iterateParent {
|
||||||
|
if (it.id != chatActionMenuContainerID) return@iterateParent false
|
||||||
|
it.triggerCloseTouchEvent()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,6 @@ import me.rhunk.snapenhance.core.features.impl.experiments.*
|
|||||||
import me.rhunk.snapenhance.core.features.impl.global.*
|
import me.rhunk.snapenhance.core.features.impl.global.*
|
||||||
import me.rhunk.snapenhance.core.features.impl.messaging.*
|
import me.rhunk.snapenhance.core.features.impl.messaging.*
|
||||||
import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger
|
import me.rhunk.snapenhance.core.features.impl.spying.MessageLogger
|
||||||
import me.rhunk.snapenhance.core.features.impl.experiments.SnapToChatMedia
|
|
||||||
import me.rhunk.snapenhance.core.features.impl.spying.StealthMode
|
import me.rhunk.snapenhance.core.features.impl.spying.StealthMode
|
||||||
import me.rhunk.snapenhance.core.features.impl.tweaks.CameraTweaks
|
import me.rhunk.snapenhance.core.features.impl.tweaks.CameraTweaks
|
||||||
import me.rhunk.snapenhance.core.features.impl.ui.*
|
import me.rhunk.snapenhance.core.features.impl.ui.*
|
||||||
@ -103,6 +102,7 @@ class FeatureManager(
|
|||||||
HideQuickAddFriendFeed::class,
|
HideQuickAddFriendFeed::class,
|
||||||
CallStartConfirmation::class,
|
CallStartConfirmation::class,
|
||||||
SnapPreview::class,
|
SnapPreview::class,
|
||||||
|
InstantDelete::class,
|
||||||
)
|
)
|
||||||
|
|
||||||
initializeFeatures()
|
initializeFeatures()
|
||||||
|
@ -74,10 +74,9 @@ class ConversationManager(val context: ModContext, obj: Any) : AbstractWrapper(o
|
|||||||
conversationId.toSnapUUID().instanceNonNull(),
|
conversationId.toSnapUUID().instanceNonNull(),
|
||||||
messageId,
|
messageId,
|
||||||
CallbackBuilder(context.mappings.getMappedClass("callbacks", "FetchMessageCallback"))
|
CallbackBuilder(context.mappings.getMappedClass("callbacks", "FetchMessageCallback"))
|
||||||
.override("onSuccess") { param ->
|
.override("onFetchMessageComplete") { param ->
|
||||||
onSuccess(Message(param.arg(0)))
|
onSuccess(Message(param.arg(0)))
|
||||||
}
|
}
|
||||||
.override("onServerRequest", shouldUnhook = false) {}
|
|
||||||
.override("onError") {
|
.override("onError") {
|
||||||
onError(it.arg<Any>(0).toString())
|
onError(it.arg<Any>(0).toString())
|
||||||
}.build()
|
}.build()
|
||||||
@ -96,7 +95,6 @@ class ConversationManager(val context: ModContext, obj: Any) : AbstractWrapper(o
|
|||||||
.override("onFetchMessageComplete") { param ->
|
.override("onFetchMessageComplete") { param ->
|
||||||
onSuccess(Message(param.arg(1)))
|
onSuccess(Message(param.arg(1)))
|
||||||
}
|
}
|
||||||
.override("onServerRequest", shouldUnhook = false) {}
|
|
||||||
.override("onError") {
|
.override("onError") {
|
||||||
onError(it.arg<Any>(0).toString())
|
onError(it.arg<Any>(0).toString())
|
||||||
}.build()
|
}.build()
|
||||||
|
@ -9,5 +9,7 @@ class MessageContent(obj: Any?) : AbstractWrapper(obj) {
|
|||||||
var content
|
var content
|
||||||
get() = instanceNonNull().getObjectField("mContent") as ByteArray
|
get() = instanceNonNull().getObjectField("mContent") as ByteArray
|
||||||
set(value) = instanceNonNull().setObjectField("mContent", value)
|
set(value) = instanceNonNull().setObjectField("mContent", value)
|
||||||
|
val quotedMessage
|
||||||
|
get() = QuotedMessage(instanceNonNull().getObjectField("mQuotedMessage"))
|
||||||
var contentType by enum("mContentType", ContentType.UNKNOWN)
|
var contentType by enum("mContentType", ContentType.UNKNOWN)
|
||||||
}
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package me.rhunk.snapenhance.core.wrapper.impl
|
||||||
|
|
||||||
|
import me.rhunk.snapenhance.core.util.ktx.getObjectField
|
||||||
|
import me.rhunk.snapenhance.core.wrapper.AbstractWrapper
|
||||||
|
|
||||||
|
class QuotedMessage(obj: Any?) : AbstractWrapper(obj) {
|
||||||
|
val content get() = QuotedMessageContent(instanceNonNull().getObjectField("mContent"))
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package me.rhunk.snapenhance.core.wrapper.impl
|
||||||
|
|
||||||
|
import me.rhunk.snapenhance.core.util.ktx.getObjectField
|
||||||
|
import me.rhunk.snapenhance.core.util.ktx.setObjectField
|
||||||
|
import me.rhunk.snapenhance.core.wrapper.AbstractWrapper
|
||||||
|
|
||||||
|
class QuotedMessageContent(obj: Any?) : AbstractWrapper(obj) {
|
||||||
|
var messageId get() = instanceNonNull().getObjectField("mMessageId") as Long
|
||||||
|
set(value) = instanceNonNull().setObjectField("mMessageId", value)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user