From c1d3e0736a3633760b237abed7b3c87b5a39933a Mon Sep 17 00:00:00 2001 From: rhunk <101876869+rhunk@users.noreply.github.com> Date: Sun, 3 Mar 2024 19:41:40 +0100 Subject: [PATCH] feat: composer utils --- .../snapenhance/core/data/SnapClassCache.kt | 4 ++ .../core/ui/ViewAppearanceHelper.kt | 12 +++++ .../wrapper/impl/composer/ComposerViewNode.kt | 50 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 core/src/main/kotlin/me/rhunk/snapenhance/core/wrapper/impl/composer/ComposerViewNode.kt diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/data/SnapClassCache.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/data/SnapClassCache.kt index 29c2890f..1b9f6ced 100644 --- a/core/src/main/kotlin/me/rhunk/snapenhance/core/data/SnapClassCache.kt +++ b/core/src/main/kotlin/me/rhunk/snapenhance/core/data/SnapClassCache.kt @@ -17,6 +17,10 @@ class SnapClassCache ( val feedEntry by lazy { findClass("com.snapchat.client.messaging.FeedEntry") } val conversation by lazy { findClass("com.snapchat.client.messaging.Conversation") } val feedManager by lazy { findClass("com.snapchat.client.messaging.FeedManager\$CppProxy") } + val nativeBridge by lazy { findClass("com.snapchat.client.composer.NativeBridge") } + val composerView by lazy { findClass("com.snap.composer.views.ComposerView") } + val composerAction by lazy { findClass("com.snap.composer.actions.ComposerAction") } + val composerFunctionActionAdapter by lazy { findClass("com.snap.composer.callable.ComposerFunctionActionAdapter") } private fun findClass(className: String): Class<*> { return try { diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/ViewAppearanceHelper.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/ViewAppearanceHelper.kt index 2eb942d5..c476508b 100644 --- a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/ViewAppearanceHelper.kt +++ b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/ViewAppearanceHelper.kt @@ -19,9 +19,11 @@ import android.view.View import android.view.ViewGroup import android.widget.Switch import android.widget.TextView +import me.rhunk.snapenhance.core.SnapEnhance import me.rhunk.snapenhance.core.util.ktx.getDimens import me.rhunk.snapenhance.core.util.ktx.getDimensFloat import me.rhunk.snapenhance.core.util.ktx.getIdentifier +import me.rhunk.snapenhance.core.wrapper.impl.composer.ComposerViewNode import kotlin.random.Random fun View.applyTheme(componentWidth: Int? = null, hasRadius: Boolean = false, isAmoled: Boolean = true) { @@ -91,6 +93,16 @@ fun View.iterateParent(predicate: (View) -> Boolean) { } } +fun View.getComposerViewNode(): ComposerViewNode? { + if (!this::class.java.isAssignableFrom(SnapEnhance.classCache.composerView)) return null + val composerViewNode = this::class.java.methods.firstOrNull { + it.name == "getComposerViewNode" + }?.invoke(this) ?: return null + + return ComposerViewNode(composerViewNode::class.java.methods.firstOrNull { + it.name == "getNativeHandle" + }?.invoke(composerViewNode) as? Long ?: return null) +} object ViewAppearanceHelper { private fun createRoundedBackground(color: Int, radius: Float, hasRadius: Boolean): Drawable { diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/wrapper/impl/composer/ComposerViewNode.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/wrapper/impl/composer/ComposerViewNode.kt new file mode 100644 index 00000000..9ab659d8 --- /dev/null +++ b/core/src/main/kotlin/me/rhunk/snapenhance/core/wrapper/impl/composer/ComposerViewNode.kt @@ -0,0 +1,50 @@ +package me.rhunk.snapenhance.core.wrapper.impl.composer + +import me.rhunk.snapenhance.core.SnapEnhance +import me.rhunk.snapenhance.core.wrapper.AbstractWrapper +import java.lang.reflect.Proxy + +fun createComposerFunction(block: (args: Array<*>) -> Any?): Any { + return SnapEnhance.classCache.composerFunctionActionAdapter.constructors.first().newInstance( + Proxy.newProxyInstance( + SnapEnhance.classCache.composerAction.classLoader, + arrayOf(SnapEnhance.classCache.composerAction), + ) { _, _, args -> + block(args?.get(0) as Array<*>) + } + ) +} + +class ComposerViewNode(obj: Long) : AbstractWrapper(obj) { + fun getAttribute(name: String): Any? { + return SnapEnhance.classCache.nativeBridge.methods.firstOrNull { + it.name == "getValueForAttribute" + }?.invoke(null, instanceNonNull(), name) + } + + fun setAttribute(name: String, value: Any) { + SnapEnhance.classCache.nativeBridge.methods.firstOrNull { + it.name == "setValueForAttribute" + }?.invoke(null, instanceNonNull(), name, value, false) + } + + fun getChildren(): List { + return ((SnapEnhance.classCache.nativeBridge.methods.firstOrNull { + it.name == "getRetainedViewNodeChildren" + }?.invoke(null, instanceNonNull(), 1))!! as? LongArray)?.map { + ComposerViewNode(it) + } ?: emptyList() + } + + fun getClassName(): String { + return SnapEnhance.classCache.nativeBridge.methods.firstOrNull { + it.name == "getViewClassName" + }?.invoke(null, instanceNonNull()).toString() + } + + override fun toString(): String { + return SnapEnhance.classCache.nativeBridge.methods.firstOrNull { + it.name == "getViewNodeDebugDescription" + }?.invoke(null, instanceNonNull()).toString() + } +} \ No newline at end of file