commit d0e6c5571703820c31a430f883e019b97aceedcd parent 89a155227794b987bb91abd003c33db9d9a50161 Author: rhunk <101876869+rhunk@users.noreply.github.com> Date: Fri, 1 Sep 2023 16:01:21 +0200 feat: disable hold to replay in FF - add setEnumField ktx - refactor AbstractWrapper delegate (nullable getValue) Diffstat:
11 files changed, 53 insertions(+), 12 deletions(-)
diff --git a/core/src/main/assets/lang/en_US.json b/core/src/main/assets/lang/en_US.json @@ -233,6 +233,10 @@ "name": "Unlimited Snap View Time", "description": "Removes the time limit for viewing Snaps" }, + "disable_replay_in_ff": { + "name": "Disable Replay in FF", + "description": "Disables the ability to replay with a long press from the friend feed" + }, "prevent_message_sending": { "name": "Prevent Message Sending", "description": "Prevents sending certain types of messages" diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/EventDispatcher.kt b/core/src/main/kotlin/me/rhunk/snapenhance/EventDispatcher.kt @@ -35,13 +35,15 @@ class EventDispatcher( } context.classCache.snapManager.hook("onSnapInteraction", HookStage.BEFORE) { param -> + val interactionType = param.arg<Any>(0).toString() val conversationId = SnapUUID(param.arg(1)) val messageId = param.arg<Long>(2) context.event.post( OnSnapInteractionEvent( - conversationId = conversationId, - messageId = messageId - ) + interactionType = interactionType, + conversationId = conversationId, + messageId = messageId + ) )?.also { if (it.canceled) { param.setResult(null) diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/MessagingTweaks.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/config/impl/MessagingTweaks.kt @@ -9,6 +9,7 @@ class MessagingTweaks : ConfigContainer() { val hideBitmojiPresence = boolean("hide_bitmoji_presence") val hideTypingNotifications = boolean("hide_typing_notifications") val unlimitedSnapViewTime = boolean("unlimited_snap_view_time") + val disableReplayInFF = boolean("disable_replay_in_ff") val autoSaveMessagesInConversations = multiple("auto_save_messages_in_conversations", "CHAT", "SNAP", diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/eventbus/events/impl/OnSnapInteractionEvent.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/eventbus/events/impl/OnSnapInteractionEvent.kt @@ -4,6 +4,7 @@ import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID class OnSnapInteractionEvent( + val interactionType: String, val conversationId: SnapUUID, val messageId: Long ) : AbstractHookEvent() \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/data/wrapper/AbstractWrapper.kt b/core/src/main/kotlin/me/rhunk/snapenhance/data/wrapper/AbstractWrapper.kt @@ -9,8 +9,8 @@ abstract class AbstractWrapper( ) { @Suppress("UNCHECKED_CAST") inner class EnumAccessor<T>(private val fieldName: String, private val defaultValue: T) { - operator fun getValue(obj: Any, property: KProperty<*>): T = getEnumValue(fieldName, defaultValue as Enum<*>) as T - operator fun setValue(obj: Any, property: KProperty<*>, value: Any) = setEnumValue(fieldName, value as Enum<*>) + operator fun getValue(obj: Any, property: KProperty<*>): T? = getEnumValue(fieldName, defaultValue as Enum<*>) as? T + operator fun setValue(obj: Any, property: KProperty<*>, value: Any?) = setEnumValue(fieldName, value as Enum<*>) } companion object { @@ -32,9 +32,10 @@ abstract class AbstractWrapper( protected fun <T> enum(fieldName: String, defaultValue: T) = EnumAccessor(fieldName, defaultValue) - fun <T : Enum<*>> getEnumValue(fieldName: String, defaultValue: T): T { + fun <T : Enum<*>> getEnumValue(fieldName: String, defaultValue: T?): T? { + if (defaultValue == null) return null val mContentType = XposedHelpers.getObjectField(instance, fieldName) as Enum<*> - return java.lang.Enum.valueOf(defaultValue::class.java, mContentType.name) as T + return java.lang.Enum.valueOf(defaultValue::class.java, mContentType.name) } @Suppress("UNCHECKED_CAST") diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/privacy/PreventMessageSending.kt b/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/privacy/PreventMessageSending.kt @@ -24,7 +24,7 @@ class PreventMessageSending : Feature("Prevent message sending", loadParams = Fe context.event.subscribe(SendMessageWithContentEvent::class) { event -> val contentType = event.messageContent.contentType - val associatedType = NotificationType.fromContentType(contentType) ?: return@subscribe + val associatedType = NotificationType.fromContentType(contentType ?: return@subscribe) ?: return@subscribe if (preventMessageSending.contains(associatedType.key)) { context.log.verbose("Preventing message sending for $associatedType") diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/DisableReplayInFF.kt b/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/DisableReplayInFF.kt @@ -0,0 +1,22 @@ +package me.rhunk.snapenhance.features.impl.tweaks + +import me.rhunk.snapenhance.features.Feature +import me.rhunk.snapenhance.features.FeatureLoadParams +import me.rhunk.snapenhance.hook.HookStage +import me.rhunk.snapenhance.hook.hookConstructor +import me.rhunk.snapenhance.util.ktx.getObjectField +import me.rhunk.snapenhance.util.ktx.setEnumField + +class DisableReplayInFF : Feature("DisableReplayInFF", loadParams = FeatureLoadParams.ACTIVITY_CREATE_ASYNC) { + override fun asyncOnActivityCreate() { + val state by context.config.messaging.disableReplayInFF + + findClass("com.snapchat.client.messaging.InteractionInfo") + .hookConstructor(HookStage.AFTER, { state }) { param -> + val instance = param.thisObject<Any>() + if (instance.getObjectField("mLongPressActionState").toString() == "REQUEST_SNAP_REPLAY") { + instance.setEnumField("mLongPressActionState", "SHOW_CONVERSATION_ACTION_MENU") + } + } + } +}+ \ No newline at end of file diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/Notifications.kt b/core/src/main/kotlin/me/rhunk/snapenhance/features/impl/tweaks/Notifications.kt @@ -221,7 +221,7 @@ class Notifications : Feature("Notifications", loadParams = FeatureLoadParams.IN } } - val contentType = snapMessage.messageContent.contentType + val contentType = snapMessage.messageContent.contentType ?: return@onEach val contentData = snapMessage.messageContent.content val formatUsername: (String) -> String = { "$senderUsername: $it" } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/manager/impl/FeatureManager.kt b/core/src/main/kotlin/me/rhunk/snapenhance/manager/impl/FeatureManager.kt @@ -25,6 +25,7 @@ import me.rhunk.snapenhance.features.impl.spying.PreventReadReceipts import me.rhunk.snapenhance.features.impl.spying.StealthMode import me.rhunk.snapenhance.features.impl.tweaks.AutoSave import me.rhunk.snapenhance.features.impl.tweaks.CameraTweaks +import me.rhunk.snapenhance.features.impl.tweaks.DisableReplayInFF import me.rhunk.snapenhance.features.impl.tweaks.DisableVideoLengthRestriction import me.rhunk.snapenhance.features.impl.tweaks.GalleryMediaSendOverride import me.rhunk.snapenhance.features.impl.tweaks.GooglePlayServicesDialogs @@ -95,6 +96,7 @@ class FeatureManager(private val context: ModContext) : Manager { register(NoFriendScoreDelay::class) register(ProfilePictureDownloader::class) register(AddFriendSourceSpoof::class) + register(DisableReplayInFF::class) initializeFeatures() } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/util/export/MessageExporter.kt b/core/src/main/kotlin/me/rhunk/snapenhance/util/export/MessageExporter.kt @@ -87,7 +87,7 @@ class MessageExporter( val sender = conversationParticipants[message.senderId.toString()] val senderUsername = sender?.usernameForSorting ?: message.senderId.toString() val senderDisplayName = sender?.displayName ?: message.senderId.toString() - val messageContent = serializeMessageContent(message) ?: message.messageContent.contentType.name + val messageContent = serializeMessageContent(message) ?: message.messageContent.contentType?.name val date = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH).format(Date(message.messageMetadata.createdAt)) writer.write("[$date] - $senderDisplayName (${senderUsername}): $messageContent\n") } @@ -118,7 +118,7 @@ class MessageExporter( runCatching { val downloadedMedia = MediaDownloaderHelper.downloadMediaFromReference(protoMediaReference) { - EncryptionHelper.decryptInputStream(it, message.messageContent.contentType, ProtoReader(message.messageContent.content), isArroyo = false) + EncryptionHelper.decryptInputStream(it, message.messageContent.contentType!!, ProtoReader(message.messageContent.content), isArroyo = false) } printLog("downloaded media ${message.orderKey}") @@ -276,7 +276,7 @@ class MessageExporter( addProperty("serializedContent", serializeMessageContent(message)) addProperty("rawContent", Base64.getUrlEncoder().encodeToString(message.messageContent.content)) - val messageContentType = message.messageContent.contentType + val messageContentType = message.messageContent.contentType ?: ContentType.CHAT EncryptionHelper.getEncryptionKeys(messageContentType, ProtoReader(message.messageContent.content), isArroyo = false)?.let { encryptionKeyPair -> add("encryption", JsonObject().apply encryption@{ diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/util/ktx/XposedHelperExt.kt b/core/src/main/kotlin/me/rhunk/snapenhance/util/ktx/XposedHelperExt.kt @@ -6,6 +6,13 @@ fun Any.getObjectField(fieldName: String): Any? { return XposedHelpers.getObjectField(this, fieldName) } +fun Any.setEnumField(fieldName: String, value: String) { + this::class.java.getDeclaredField(fieldName) + .type.enumConstants?.firstOrNull { it.toString() == value }?.let { enum -> + setObjectField(fieldName, enum) + } +} + fun Any.setObjectField(fieldName: String, value: Any?) { XposedHelpers.setObjectField(this, fieldName, value) }