commit 8d2353bbbec41fe5ce286821a0fee55791eb933e
parent 7d06d1cc7221b1d84b296898b9f24a1706922d3e
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date: Wed, 21 Aug 2024 12:06:05 +0200
feat(scripting): setTimeout and setInterval support
Diffstat:
2 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/JSModule.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/JSModule.kt
@@ -2,6 +2,7 @@ package me.rhunk.snapenhance.common.scripting
import android.os.Handler
import android.widget.Toast
+import kotlinx.coroutines.*
import me.rhunk.snapenhance.common.scripting.bindings.AbstractBinding
import me.rhunk.snapenhance.common.scripting.bindings.BindingsContext
import me.rhunk.snapenhance.common.scripting.impl.JavaInterfaces
@@ -14,10 +15,8 @@ import me.rhunk.snapenhance.common.scripting.ktx.scriptableObject
import me.rhunk.snapenhance.common.scripting.type.ModuleInfo
import me.rhunk.snapenhance.common.scripting.type.Permissions
import me.rhunk.snapenhance.common.scripting.ui.InterfaceManager
+import org.mozilla.javascript.*
import org.mozilla.javascript.Function
-import org.mozilla.javascript.ScriptableObject
-import org.mozilla.javascript.Undefined
-import org.mozilla.javascript.Wrapper
import java.io.Reader
import java.lang.reflect.Modifier
import kotlin.reflect.KClass
@@ -27,13 +26,15 @@ class JSModule(
val moduleInfo: ModuleInfo,
private val reader: Reader,
) {
+ val coroutineScope = CoroutineScope(Dispatchers.IO)
private val moduleBindings = mutableMapOf<String, AbstractBinding>()
private lateinit var moduleObject: ScriptableObject
private val moduleBindingContext by lazy {
BindingsContext(
moduleInfo = moduleInfo,
- runtime = scriptRuntime
+ runtime = scriptRuntime,
+ module = this,
)
}
@@ -158,6 +159,42 @@ class JSModule(
Undefined.instance
}
+ moduleObject.putFunction("setTimeout") {
+ val function = it?.get(0) as? Function ?: return@putFunction Undefined.instance
+ val time = it[1] as? Number ?: 0
+
+ return@putFunction coroutineScope.launch {
+ delay(time.toLong())
+ contextScope {
+ function.call(this, this@putFunction, this@putFunction, emptyArray())
+ }
+ }
+ }
+
+ moduleObject.putFunction("setInterval") {
+ val function = it?.get(0) as? Function ?: return@putFunction Undefined.instance
+ val time = it[1] as? Number ?: 0
+
+ return@putFunction coroutineScope.launch {
+ while (true) {
+ delay(time.toLong())
+ contextScope {
+ function.call(this, this@putFunction, this@putFunction, emptyArray())
+ }
+ }
+ }
+ }
+
+ arrayOf("clearInterval", "clearTimeout").forEach {
+ moduleObject.putFunction(it) { args ->
+ val job = args?.get(0) as? Job ?: return@putFunction Undefined.instance
+ runCatching {
+ job.cancel()
+ }
+ Undefined.instance
+ }
+ }
+
for (toastFunc in listOf("longToast", "shortToast")) {
moduleObject.putFunction(toastFunc) { args ->
Handler(scriptRuntime.androidContext.mainLooper).post {
@@ -205,6 +242,9 @@ class JSModule(
fun unload() {
callFunction("module.onUnload")
+ runCatching {
+ coroutineScope.cancel("Module unloaded")
+ }
moduleBindings.entries.removeIf { (name, binding) ->
runCatching {
binding.onDispose()
diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/bindings/BindingsContext.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/bindings/BindingsContext.kt
@@ -1,9 +1,11 @@
package me.rhunk.snapenhance.common.scripting.bindings
+import me.rhunk.snapenhance.common.scripting.JSModule
import me.rhunk.snapenhance.common.scripting.ScriptRuntime
import me.rhunk.snapenhance.common.scripting.type.ModuleInfo
class BindingsContext(
val moduleInfo: ModuleInfo,
- val runtime: ScriptRuntime
+ val runtime: ScriptRuntime,
+ val module: JSModule
)
\ No newline at end of file