refactor: compose icon deprecation
- refactor script interface
This commit is contained in:
@@ -6,7 +6,7 @@ import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -80,7 +80,7 @@ class Navigation(
|
||||
IconButton(
|
||||
onClick = { navHostController.popBackStack() }
|
||||
) {
|
||||
Icon(Icons.Filled.ArrowBack, contentDescription = null)
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}, actions = {
|
||||
|
||||
@@ -8,9 +8,9 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.OpenInNew
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.FilterList
|
||||
import androidx.compose.material.icons.filled.OpenInNew
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -218,7 +218,7 @@ class DownloadsSection : Section() {
|
||||
context.androidContext.startActivity(intent)
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.OpenInNew,
|
||||
imageVector = Icons.AutoMirrored.Filled.OpenInNew,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.OpenInNew
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.FolderOpen
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material.icons.filled.OpenInNew
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.rounded.Save
|
||||
import androidx.compose.material3.*
|
||||
@@ -224,7 +224,7 @@ class FeaturesSection : Section() {
|
||||
}
|
||||
} else {
|
||||
IconButton(onClick = it) {
|
||||
Icon(Icons.Filled.OpenInNew, contentDescription = null)
|
||||
Icon(Icons.AutoMirrored.Filled.OpenInNew, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.OpenInNew
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -155,7 +156,7 @@ class HomeSection : Section() {
|
||||
Button(onClick = {
|
||||
context.checkForRequirements(Requirements.LANGUAGE)
|
||||
}, modifier = Modifier.height(40.dp)) {
|
||||
Icon(Icons.Filled.OpenInNew, contentDescription = null)
|
||||
Icon(Icons.AutoMirrored.Filled.OpenInNew, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.OpenInNew
|
||||
import androidx.compose.material.icons.automirrored.filled.OpenInNew
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
@@ -73,7 +73,7 @@ class SettingsSection : Section() {
|
||||
Text(text = title, modifier = Modifier.padding(start = 26.dp))
|
||||
IconButton(onClick = { takeAction() }) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.OpenInNew,
|
||||
imageVector = Icons.AutoMirrored.Filled.OpenInNew,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
package me.rhunk.snapenhance.ui.manager.sections.scripting
|
||||
|
||||
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.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import kotlinx.coroutines.launch
|
||||
import me.rhunk.snapenhance.core.Logger
|
||||
import me.rhunk.snapenhance.scripting.impl.ui.InterfaceBuilder
|
||||
import me.rhunk.snapenhance.scripting.impl.ui.components.Node
|
||||
import me.rhunk.snapenhance.scripting.impl.ui.components.NodeType
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
@Composable
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun DrawNode(node: Node) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val cachedAttributes = remember { mutableStateMapOf(*node.attributes.toList().toTypedArray()) }
|
||||
|
||||
node.uiChangeDetection = { key, value ->
|
||||
coroutineScope.launch {
|
||||
cachedAttributes[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
node.uiChangeDetection = { _, _ -> }
|
||||
}
|
||||
}
|
||||
|
||||
val arrangement = cachedAttributes["arrangement"]
|
||||
val alignment = cachedAttributes["alignment"]
|
||||
val spacing = cachedAttributes["spacing"]?.toString()?.toInt()?.let { abs(it) }
|
||||
|
||||
val rowColumnModifier = Modifier
|
||||
.then(if (cachedAttributes["fillMaxWidth"] as? Boolean == true) Modifier.fillMaxWidth() else Modifier)
|
||||
.then(if (cachedAttributes["fillMaxHeight"] as? Boolean == true) Modifier.fillMaxHeight() else Modifier)
|
||||
.padding(
|
||||
(cachedAttributes["padding"]
|
||||
?.toString()
|
||||
?.toInt()
|
||||
?.let { abs(it) } ?: 2).dp)
|
||||
|
||||
fun runCallbackSafe(callback: () -> Unit) {
|
||||
runCatching {
|
||||
callback()
|
||||
}.onFailure {
|
||||
Logger.directError("Error running callback", it)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NodeLabel() {
|
||||
Text(
|
||||
text = cachedAttributes["label"] as String,
|
||||
fontSize = (cachedAttributes["fontSize"]?.toString()?.toInt() ?: 14).sp,
|
||||
color = (cachedAttributes["color"] as? Long)?.let { Color(it) } ?: Color.Unspecified
|
||||
)
|
||||
}
|
||||
|
||||
when (node.type) {
|
||||
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.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.BUTTON -> {
|
||||
OutlinedButton(onClick = {
|
||||
runCallbackSafe {
|
||||
(cachedAttributes["callback"] as? () -> Unit)?.let { it() }
|
||||
}
|
||||
}) {
|
||||
NodeLabel()
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ScriptInterface(interfaceBuilder: InterfaceBuilder) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp)
|
||||
) {
|
||||
interfaceBuilder.nodes.forEach { node ->
|
||||
DrawNode(node)
|
||||
}
|
||||
|
||||
LaunchedEffect(interfaceBuilder) {
|
||||
interfaceBuilder.onLaunchedCallback?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,19 +9,15 @@ import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import me.rhunk.snapenhance.scripting.impl.ui.components.Node
|
||||
import me.rhunk.snapenhance.scripting.impl.ui.components.NodeType
|
||||
import me.rhunk.snapenhance.scripting.type.ModuleInfo
|
||||
import me.rhunk.snapenhance.ui.manager.Section
|
||||
import me.rhunk.snapenhance.ui.util.pullrefresh.PullRefreshIndicator
|
||||
import me.rhunk.snapenhance.ui.util.pullrefresh.pullRefresh
|
||||
import me.rhunk.snapenhance.ui.util.pullrefresh.rememberPullRefreshState
|
||||
import kotlin.math.abs
|
||||
|
||||
class ScriptsSection : Section() {
|
||||
@Composable
|
||||
@@ -88,115 +84,6 @@ class ScriptsSection : Section() {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DrawNode(node: Node) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val cachedAttributes = remember { mutableStateMapOf(*node.attributes.toList().toTypedArray()) }
|
||||
|
||||
node.uiChangeDetection = { key, value ->
|
||||
coroutineScope.launch {
|
||||
cachedAttributes[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
val arrangement = cachedAttributes["arrangement"]
|
||||
val alignment = cachedAttributes["alignment"]
|
||||
val spacing = cachedAttributes["spacing"]?.toString()?.toInt()?.let { abs(it) }
|
||||
|
||||
val rowColumnModifier = Modifier
|
||||
.then(if (cachedAttributes["fillMaxWidth"] as? Boolean == true) Modifier.fillMaxWidth() else Modifier)
|
||||
.then(if (cachedAttributes["fillMaxHeight"] as? Boolean == true) Modifier.fillMaxHeight() else Modifier)
|
||||
.padding(
|
||||
(cachedAttributes["padding"]
|
||||
?.toString()
|
||||
?.toInt()
|
||||
?.let { abs(it) } ?: 2).dp)
|
||||
|
||||
fun runCallbackSafe(callback: () -> Unit) {
|
||||
runCatching {
|
||||
callback()
|
||||
}.onFailure {
|
||||
context.log.error("Error running callback", it)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NodeLabel() {
|
||||
Text(
|
||||
text = cachedAttributes["label"] as String,
|
||||
fontSize = (cachedAttributes["fontSize"]?.toString()?.toInt() ?: 14).sp,
|
||||
color = (cachedAttributes["color"] as? Long)?.let { Color(it) } ?: Color.Unspecified
|
||||
)
|
||||
}
|
||||
|
||||
when (node.type) {
|
||||
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.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.BUTTON -> {
|
||||
OutlinedButton(onClick = {
|
||||
runCallbackSafe {
|
||||
(cachedAttributes["callback"] as? () -> Unit)?.let { it() }
|
||||
}
|
||||
}) {
|
||||
NodeLabel()
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ScriptSettings(script: ModuleInfo) {
|
||||
@@ -211,19 +98,7 @@ class ScriptsSection : Section() {
|
||||
return
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp)
|
||||
) {
|
||||
settingsInterface.nodes.forEach { node ->
|
||||
DrawNode(node)
|
||||
}
|
||||
|
||||
LaunchedEffect(settingsInterface) {
|
||||
settingsInterface.onLaunchedCallback?.invoke()
|
||||
}
|
||||
}
|
||||
ScriptInterface(interfaceBuilder = settingsInterface)
|
||||
}
|
||||
|
||||
|
||||
@@ -259,13 +134,14 @@ class ScriptsSection : Section() {
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.pullRefresh(pullRefreshState),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
item {
|
||||
if (scriptModules.isEmpty()) {
|
||||
Text(
|
||||
text = "No scripts found",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
modifier = Modifier.padding(8.dp).align(Alignment.Center)
|
||||
modifier = Modifier.padding(8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowForwardIos
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowForwardIos
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.FilledIconButton
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -122,7 +122,7 @@ class SetupActivity : ComponentActivity() {
|
||||
imageVector = if (requiredScreens.size <= 1 && canGoNext) {
|
||||
Icons.Default.Check
|
||||
} else {
|
||||
Icons.Default.ArrowForwardIos
|
||||
Icons.AutoMirrored.Default.ArrowForwardIos
|
||||
},
|
||||
contentDescription = null
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ import me.rhunk.snapenhance.ui.menu.AbstractMenu
|
||||
class SettingsMenu : AbstractMenu() {
|
||||
//TODO: quick settings
|
||||
@SuppressLint("SetTextI18n")
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun inject(viewModel: View, addView: (View) -> Unit) {
|
||||
/*val actions = context.actionManager.getActions().map {
|
||||
Pair(it) {
|
||||
|
||||
Reference in New Issue
Block a user