commit 381b346c7a0a3d7b560e9bfa8452d5e0779258a7
parent 283f0266d9f4588d5242c719172e21cbef6eede8
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sun,  4 Feb 2024 16:01:30 +0100

feat(scripting): text input component
- add visibility attribute

Diffstat:
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/InterfaceManager.kt | 7+++++++
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/ScriptInterface.kt | 171++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/components/Node.kt | 10++++++++++
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/components/NodeType.kt | 3++-
Acommon/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/components/impl/TextInputNode.kt | 37+++++++++++++++++++++++++++++++++++++
5 files changed, 155 insertions(+), 73 deletions(-)

diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/InterfaceManager.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/InterfaceManager.kt @@ -12,6 +12,7 @@ import me.rhunk.snapenhance.common.scripting.ui.components.NodeType import me.rhunk.snapenhance.common.scripting.ui.components.impl.ActionNode import me.rhunk.snapenhance.common.scripting.ui.components.impl.ActionType import me.rhunk.snapenhance.common.scripting.ui.components.impl.RowColumnNode +import me.rhunk.snapenhance.common.scripting.ui.components.impl.TextInputNode import me.rhunk.snapenhance.common.ui.createComposeAlertDialog import org.mozilla.javascript.Function import org.mozilla.javascript.annotations.JSFunction @@ -74,6 +75,12 @@ class InterfaceBuilder { attributes["items"] = items attributes["callback"] = callback } + + fun textInput(placeholder: String, value: String, callback: (String) -> Unit) = TextInputNode().apply { + placeholder(placeholder) + value(value) + callback(callback) + }.also { nodes.add(it) } } diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/ScriptInterface.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/ScriptInterface.kt @@ -1,10 +1,12 @@ package me.rhunk.snapenhance.common.scripting.ui +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.* import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Slider import androidx.compose.material3.Switch import androidx.compose.material3.Text +import androidx.compose.material3.TextField import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -68,92 +70,117 @@ private fun DrawNode(node: Node) { ) } - when (node.type) { - NodeType.ACTION -> { - when ((node as ActionNode).actionType) { - ActionType.LAUNCHED -> { - LaunchedEffect(node.key) { - runCallbackSafe { - node.callback() + if (cachedAttributes["visibility"] != "gone") { + AnimatedVisibility( + visible = cachedAttributes["visibility"] != "invisible", + ) { + when (node.type) { + NodeType.ACTION -> { + when ((node as ActionNode).actionType) { + ActionType.LAUNCHED -> { + LaunchedEffect(node.key) { + runCallbackSafe { + node.callback() + } + } + } + ActionType.DISPOSE -> { + DisposableEffect(Unit) { + onDispose { + runCallbackSafe { + node.callback() + } + } + } } } } - ActionType.DISPOSE -> { - DisposableEffect(Unit) { - onDispose { - runCallbackSafe { - node.callback() - } + NodeType.COLUMN -> { + Column( + verticalArrangement = arrangement as? Arrangement.Vertical ?: spacing?.let { Arrangement.spacedBy(it.dp) } ?: Arrangement.Top, + horizontalAlignment = alignment as? Alignment.Horizontal ?: Alignment.Start, + modifier = rowColumnModifier + ) { + node.children.forEach { child -> + DrawNode(child) } } } - } - } - NodeType.COLUMN -> { - Column( - verticalArrangement = arrangement as? Arrangement.Vertical ?: spacing?.let { Arrangement.spacedBy(it.dp) } ?: Arrangement.Top, - horizontalAlignment = alignment as? Alignment.Horizontal ?: Alignment.Start, - modifier = rowColumnModifier - ) { - node.children.forEach { child -> - DrawNode(child) + NodeType.ROW -> { + Row( + horizontalArrangement = arrangement as? Arrangement.Horizontal ?: spacing?.let { Arrangement.spacedBy(it.dp) } ?: Arrangement.SpaceBetween, + verticalAlignment = alignment as? Alignment.Vertical ?: Alignment.CenterVertically, + modifier = rowColumnModifier + ) { + node.children.forEach { child -> + DrawNode(child) + } + } } - } - } - NodeType.ROW -> { - Row( - horizontalArrangement = arrangement as? Arrangement.Horizontal ?: spacing?.let { Arrangement.spacedBy(it.dp) } ?: Arrangement.SpaceBetween, - verticalAlignment = alignment as? Alignment.Vertical ?: Alignment.CenterVertically, - modifier = rowColumnModifier - ) { - node.children.forEach { child -> - DrawNode(child) + NodeType.TEXT -> NodeLabel() + NodeType.SWITCH -> { + var switchState by remember { + mutableStateOf(cachedAttributes["state"] as Boolean) + } + Switch( + checked = switchState, + onCheckedChange = { state -> + runCallbackSafe { + switchState = state + node.setAttribute("state", state) + (cachedAttributes["callback"] as? (Boolean) -> Unit)?.let { it(state) } + } + } + ) } - } - } - NodeType.TEXT -> NodeLabel() - NodeType.SWITCH -> { - var switchState by remember { - mutableStateOf(cachedAttributes["state"] as Boolean) - } - Switch( - checked = switchState, - onCheckedChange = { state -> - runCallbackSafe { - switchState = state - node.setAttribute("state", state) - (cachedAttributes["callback"] as? (Boolean) -> Unit)?.let { it(state) } + NodeType.SLIDER -> { + var sliderValue by remember { + mutableFloatStateOf((cachedAttributes["value"] as Int).toFloat()) } + Slider( + value = sliderValue, + onValueChange = { value -> + runCallbackSafe { + sliderValue = value + node.setAttribute("value", value.toInt()) + (cachedAttributes["callback"] as? (Int) -> Unit)?.let { it(value.toInt()) } + } + }, + valueRange = (cachedAttributes["min"] as Int).toFloat()..(cachedAttributes["max"] as Int).toFloat(), + steps = cachedAttributes["step"] as Int, + ) } - ) - } - NodeType.SLIDER -> { - var sliderValue by remember { - mutableFloatStateOf((cachedAttributes["value"] as Int).toFloat()) - } - Slider( - value = sliderValue, - onValueChange = { value -> - runCallbackSafe { - sliderValue = value - node.setAttribute("value", value.toInt()) - (cachedAttributes["callback"] as? (Int) -> Unit)?.let { it(value.toInt()) } + NodeType.BUTTON -> { + OutlinedButton(onClick = { + runCallbackSafe { + (cachedAttributes["callback"] as? () -> Unit)?.let { it() } + } + }) { + NodeLabel() } - }, - valueRange = (cachedAttributes["min"] as Int).toFloat()..(cachedAttributes["max"] as Int).toFloat(), - steps = cachedAttributes["step"] as Int, - ) - } - NodeType.BUTTON -> { - OutlinedButton(onClick = { - runCallbackSafe { - (cachedAttributes["callback"] as? () -> Unit)?.let { it() } } - }) { - NodeLabel() + NodeType.TEXT_INPUT -> { + var textInputValue by remember { + mutableStateOf(cachedAttributes["value"].toString()) + } + TextField( + value = textInputValue, + readOnly = cachedAttributes["readonly"] as? Boolean ?: false, + singleLine = cachedAttributes["singleLine"] as? Boolean ?: true, + maxLines = cachedAttributes["maxLines"] as? Int ?: 1, + onValueChange = { value -> + runCallbackSafe { + textInputValue = value + node.setAttribute("value", value) + (cachedAttributes["callback"] as? (String) -> Unit)?.let { it(value) } + } + }, + placeholder = { Text(cachedAttributes["placeholder"].toString()) } + ) + } + else -> {} } } - else -> {} } } diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/components/Node.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/components/Node.kt @@ -1,5 +1,6 @@ package me.rhunk.snapenhance.common.scripting.ui.components +@Suppress("MemberVisibilityCanBePrivate") open class Node( val type: NodeType, ) { @@ -16,6 +17,10 @@ open class Node( } } + init { + visibility("visible") + } + fun setAttribute(key: String, value: Any?) { attributes[key] = value } @@ -49,4 +54,9 @@ open class Node( attributes["color"] = color return this } + + fun visibility(state: String) { + assert(state == "visible" || state == "invisible" || state == "gone") { "Invalid visibility state. Must be one of: visible, invisible, gone" } + attributes["visibility"] = state + } } diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/components/NodeType.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/components/NodeType.kt @@ -8,5 +8,6 @@ enum class NodeType { BUTTON, SLIDER, LIST, - ACTION + ACTION, + TEXT_INPUT, } \ No newline at end of file diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/components/impl/TextInputNode.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/scripting/ui/components/impl/TextInputNode.kt @@ -0,0 +1,36 @@ +package me.rhunk.snapenhance.common.scripting.ui.components.impl + +import me.rhunk.snapenhance.common.scripting.ui.components.Node +import me.rhunk.snapenhance.common.scripting.ui.components.NodeType + +class TextInputNode : Node(NodeType.TEXT_INPUT) { + fun placeholder(text: String): TextInputNode { + attributes["placeholder"] = text + return this + } + + fun value(text: String): TextInputNode { + attributes["value"] = text + return this + } + + fun callback(callback: (String) -> Unit): TextInputNode { + attributes["callback"] = callback + return this + } + + fun readonly(state: Boolean): TextInputNode { + attributes["readonly"] = state + return this + } + + fun singleLine(state: Boolean): TextInputNode { + attributes["singleLine"] = state + return this + } + + fun maxLines(maxLines: Int): TextInputNode { + attributes["maxLines"] = maxLines + return this + } +}+ \ No newline at end of file