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",
|
||||
"description": "Prevents sending certain types of messages"
|
||||
},
|
||||
"instant_delete": {
|
||||
"name": "Instant Delete",
|
||||
"description": "Removes the confirmation dialog when deleting messages"
|
||||
},
|
||||
"better_notifications": {
|
||||
"name": "Better Notifications",
|
||||
"description": "Adds more information in received notifications"
|
||||
|
@ -23,6 +23,7 @@ class MessagingTweaks : ConfigContainer() {
|
||||
customOptionTranslationPath = "features.options.notifications"
|
||||
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 notificationBlacklist = multiple("notification_blacklist", *NotificationType.getIncomingValues().map { it.key }.toTypedArray()) {
|
||||
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.messaging.*
|
||||
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.tweaks.CameraTweaks
|
||||
import me.rhunk.snapenhance.core.features.impl.ui.*
|
||||
@ -103,6 +102,7 @@ class FeatureManager(
|
||||
HideQuickAddFriendFeed::class,
|
||||
CallStartConfirmation::class,
|
||||
SnapPreview::class,
|
||||
InstantDelete::class,
|
||||
)
|
||||
|
||||
initializeFeatures()
|
||||
|
@ -74,10 +74,9 @@ class ConversationManager(val context: ModContext, obj: Any) : AbstractWrapper(o
|
||||
conversationId.toSnapUUID().instanceNonNull(),
|
||||
messageId,
|
||||
CallbackBuilder(context.mappings.getMappedClass("callbacks", "FetchMessageCallback"))
|
||||
.override("onSuccess") { param ->
|
||||
.override("onFetchMessageComplete") { param ->
|
||||
onSuccess(Message(param.arg(0)))
|
||||
}
|
||||
.override("onServerRequest", shouldUnhook = false) {}
|
||||
.override("onError") {
|
||||
onError(it.arg<Any>(0).toString())
|
||||
}.build()
|
||||
@ -96,7 +95,6 @@ class ConversationManager(val context: ModContext, obj: Any) : AbstractWrapper(o
|
||||
.override("onFetchMessageComplete") { param ->
|
||||
onSuccess(Message(param.arg(1)))
|
||||
}
|
||||
.override("onServerRequest", shouldUnhook = false) {}
|
||||
.override("onError") {
|
||||
onError(it.arg<Any>(0).toString())
|
||||
}.build()
|
||||
|
@ -9,5 +9,7 @@ class MessageContent(obj: Any?) : AbstractWrapper(obj) {
|
||||
var content
|
||||
get() = instanceNonNull().getObjectField("mContent") as ByteArray
|
||||
set(value) = instanceNonNull().setObjectField("mContent", value)
|
||||
val quotedMessage
|
||||
get() = QuotedMessage(instanceNonNull().getObjectField("mQuotedMessage"))
|
||||
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