fix: several bugs and inconsistencies
This commit is contained in:
@@ -206,8 +206,45 @@ fun ScriptCatalog(root: ScriptingRootSection) {
|
||||
) {
|
||||
item {
|
||||
if (isLoading) {
|
||||
Box(modifier = Modifier.fillMaxWidth().padding(8.dp), contentAlignment = Alignment.Center) {
|
||||
CircularProgressIndicator()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(10.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
color = Color.White.copy(alpha = 0.06f),
|
||||
tonalElevation = 0.dp,
|
||||
shadowElevation = 0.dp,
|
||||
border = BorderStroke(
|
||||
1.dp,
|
||||
Brush.linearGradient(
|
||||
listOf(
|
||||
PurrfectPalette.glowPrimary.copy(alpha = 0.45f),
|
||||
PurrfectPalette.glowSecondary.copy(alpha = 0.30f)
|
||||
)
|
||||
)
|
||||
)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 14.dp, vertical = 10.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(18.dp),
|
||||
strokeWidth = 2.dp,
|
||||
color = Color.White
|
||||
)
|
||||
Text(
|
||||
text = translation["loading"] ?: "Loading...",
|
||||
color = Color.White,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 13.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (allScripts.isEmpty() && repositories.isNotEmpty()) {
|
||||
Box(
|
||||
|
||||
@@ -547,6 +547,8 @@
|
||||
"no_settings_for_module": "This module does not have any settings",
|
||||
"open_module_failed": "Failed to open module file",
|
||||
"open_scripts_folder_button": "Open scripts folder",
|
||||
"loaded_script": "Loaded script {name}",
|
||||
"unloaded_script": "Unloaded script {name}",
|
||||
"script_already_installed": "Script already installed",
|
||||
"select_folder_button": "Choose Folder",
|
||||
"select_scripts_folder_toast": "Please select a scripts folder first",
|
||||
@@ -558,6 +560,7 @@
|
||||
"no_repos_added": "No repositories added",
|
||||
"repo_list_info": "Find repositories here:",
|
||||
"link_text": "Repository list",
|
||||
"loading": "Loading catalog...",
|
||||
"script_already_installed": "Script already installed",
|
||||
"script_downloaded": "Script downloaded",
|
||||
"could_not_create_file": "Could not create file",
|
||||
@@ -3530,6 +3533,11 @@
|
||||
"toast_open_snap_failed": "Failed to open snap",
|
||||
"toast_mark_message_read_failed": "Failed to mark message as read. Check logs for more details",
|
||||
"toast_open_conversation_first": "You must open a conversation first",
|
||||
"conversation_toolbox": {
|
||||
"title": "Conversation Toolbox",
|
||||
"loaded_script": "Loaded Script",
|
||||
"failed_to_load": "Failed to load: {message}"
|
||||
},
|
||||
"toast_open_link_failed": "Failed to open link",
|
||||
"ai_response_style": {
|
||||
"casual": "Casual",
|
||||
|
||||
@@ -2,7 +2,17 @@ package me.eternal.purrfectsnap.common.scripting.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.eternal.purrfectsnap.common.scripting.bindings.AbstractBinding
|
||||
import me.eternal.purrfectsnap.common.scripting.bindings.BindingSide
|
||||
import me.eternal.purrfectsnap.common.scripting.ktx.contextScope
|
||||
@@ -125,13 +135,46 @@ class InterfaceManager : AbstractBinding("interface-manager", BindingSide.COMMON
|
||||
|
||||
@JSFunction fun createAlertDialog(activity: Activity, builder: (AlertDialog.Builder) -> Unit, callback: (interfaceBuilder: InterfaceBuilder, alertDialog: AlertDialog) -> Unit): AlertDialog {
|
||||
return createComposeAlertDialog(activity, builder = builder) { alertDialog ->
|
||||
ScriptInterface(interfaceBuilder = remember {
|
||||
val interfaceBuilder = remember {
|
||||
InterfaceBuilder().also {
|
||||
contextScope {
|
||||
callback(it, alertDialog)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
val shape = RoundedCornerShape(22.dp)
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.border(
|
||||
width = 1.dp,
|
||||
brush = Brush.linearGradient(
|
||||
listOf(
|
||||
Color(0xFF8C7BFF).copy(alpha = 0.52f),
|
||||
Color(0xFF5FD8FF).copy(alpha = 0.30f)
|
||||
)
|
||||
),
|
||||
shape = shape
|
||||
),
|
||||
color = Color.Transparent,
|
||||
shape = shape
|
||||
) {
|
||||
androidx.compose.foundation.layout.Column(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
brush = Brush.linearGradient(
|
||||
listOf(
|
||||
Color(0xFF2A2452).copy(alpha = 0.97f),
|
||||
Color(0xFF1A143A).copy(alpha = 0.94f),
|
||||
)
|
||||
),
|
||||
shape = shape
|
||||
)
|
||||
.padding(10.dp)
|
||||
) {
|
||||
ScriptInterface(interfaceBuilder = interfaceBuilder)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
package me.eternal.purrfectsnap.common.scripting.ui
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.SliderDefaults
|
||||
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
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import kotlinx.coroutines.launch
|
||||
import me.eternal.purrfectsnap.common.logger.AbstractLogger
|
||||
import me.eternal.purrfectsnap.common.scripting.ui.components.Node
|
||||
@@ -66,7 +75,7 @@ private fun DrawNode(node: Node) {
|
||||
Text(
|
||||
text = cachedAttributes["label"] as String,
|
||||
fontSize = (cachedAttributes["fontSize"]?.toString()?.toInt() ?: 14).sp,
|
||||
color = (cachedAttributes["color"] as? Long)?.let { Color(it) } ?: Color.Unspecified
|
||||
color = (cachedAttributes["color"] as? Long)?.let { Color(it) } ?: Color.White
|
||||
)
|
||||
}
|
||||
|
||||
@@ -130,7 +139,15 @@ private fun DrawNode(node: Node) {
|
||||
node.setAttribute("state", state)
|
||||
(cachedAttributes["callback"] as? (Boolean) -> Unit)?.let { it(state) }
|
||||
}
|
||||
}
|
||||
},
|
||||
colors = androidx.compose.material3.SwitchDefaults.colors(
|
||||
checkedThumbColor = Color.White,
|
||||
checkedTrackColor = Color(0xFF8C7BFF).copy(alpha = 0.66f),
|
||||
uncheckedThumbColor = Color.White.copy(alpha = 0.9f),
|
||||
uncheckedTrackColor = Color.White.copy(alpha = 0.20f),
|
||||
checkedBorderColor = Color.Transparent,
|
||||
uncheckedBorderColor = Color.Transparent
|
||||
)
|
||||
)
|
||||
}
|
||||
NodeType.SLIDER -> {
|
||||
@@ -148,26 +165,55 @@ private fun DrawNode(node: Node) {
|
||||
},
|
||||
valueRange = (cachedAttributes["min"] as Int).toFloat()..(cachedAttributes["max"] as Int).toFloat(),
|
||||
steps = cachedAttributes["step"] as Int,
|
||||
colors = SliderDefaults.colors(
|
||||
thumbColor = Color(0xFF8C7BFF),
|
||||
activeTrackColor = Color(0xFF8C7BFF).copy(alpha = 0.72f),
|
||||
inactiveTrackColor = Color.White.copy(alpha = 0.20f),
|
||||
)
|
||||
)
|
||||
}
|
||||
NodeType.BUTTON -> {
|
||||
OutlinedButton(onClick = {
|
||||
runCallbackSafe {
|
||||
(cachedAttributes["callback"] as? () -> Unit)?.let { it() }
|
||||
}
|
||||
}) {
|
||||
NodeLabel()
|
||||
val buttonShape = RoundedCornerShape(999.dp)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(buttonShape)
|
||||
.background(Color.White.copy(alpha = 0.08f), buttonShape)
|
||||
.border(1.dp, Color.White.copy(alpha = 0.20f), buttonShape)
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = {
|
||||
runCallbackSafe {
|
||||
(cachedAttributes["callback"] as? () -> Unit)?.let { it() }
|
||||
}
|
||||
}
|
||||
)
|
||||
.padding(horizontal = 16.dp, vertical = 9.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = cachedAttributes["label"] as String,
|
||||
color = Color.White,
|
||||
fontSize = (cachedAttributes["fontSize"]?.toString()?.toInt() ?: 14).sp,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
}
|
||||
}
|
||||
NodeType.TEXT_INPUT -> {
|
||||
var textInputValue by remember {
|
||||
mutableStateOf(cachedAttributes["value"].toString())
|
||||
}
|
||||
TextField(
|
||||
val inputShape = RoundedCornerShape(14.dp)
|
||||
BasicTextField(
|
||||
value = textInputValue,
|
||||
readOnly = cachedAttributes["readonly"] as? Boolean ?: false,
|
||||
singleLine = cachedAttributes["singleLine"] as? Boolean ?: true,
|
||||
maxLines = cachedAttributes["maxLines"] as? Int ?: 1,
|
||||
textStyle = TextStyle(
|
||||
color = Color.White,
|
||||
fontSize = 14.sp
|
||||
),
|
||||
cursorBrush = SolidColor(Color(0xFF8C7BFF)),
|
||||
onValueChange = { value ->
|
||||
runCallbackSafe {
|
||||
textInputValue = value
|
||||
@@ -175,7 +221,24 @@ private fun DrawNode(node: Node) {
|
||||
(cachedAttributes["callback"] as? (String) -> Unit)?.let { it(value) }
|
||||
}
|
||||
},
|
||||
placeholder = { Text(cachedAttributes["placeholder"].toString()) }
|
||||
decorationBox = { innerTextField ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(Color.White.copy(alpha = 0.08f), inputShape)
|
||||
.border(1.dp, Color.White.copy(alpha = 0.18f), inputShape)
|
||||
.padding(horizontal = 12.dp, vertical = 10.dp)
|
||||
) {
|
||||
if (textInputValue.isEmpty()) {
|
||||
Text(
|
||||
text = cachedAttributes["placeholder"].toString(),
|
||||
color = Color.White.copy(alpha = 0.6f),
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
innerTextField()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
@@ -25,7 +26,6 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
@@ -99,7 +99,9 @@ class ConversationToolbox : Feature("Conversation Toolbox") {
|
||||
val interfaceManager = getBinding(InterfaceManager::class)?.takeIf {
|
||||
it.hasInterface(EnumScriptInterface.CONVERSATION_TOOLBOX)
|
||||
} ?: return@eachModule
|
||||
addComposable("\uD83D\uDCDC ${moduleInfo.displayName}") { alertDialog, conversationId ->
|
||||
addComposable(
|
||||
"\uD83D\uDCDC ${context.translation["conversation_toolbox.loaded_script"]}: ${moduleInfo.displayName}"
|
||||
) { alertDialog, conversationId ->
|
||||
ScriptInterface(remember {
|
||||
interfaceManager.buildInterface(EnumScriptInterface.CONVERSATION_TOOLBOX, mapOf(
|
||||
"alertDialog" to alertDialog,
|
||||
@@ -143,7 +145,7 @@ class ConversationToolbox : Feature("Conversation Toolbox") {
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Text(
|
||||
"Conversation Toolbox",
|
||||
context.translation["conversation_toolbox.title"],
|
||||
fontSize = 18.sp,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -160,14 +162,16 @@ class ConversationToolbox : Feature("Conversation Toolbox") {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.shadow(10.dp, itemShape, clip = true)
|
||||
.clip(itemShape)
|
||||
.background(Color.White.copy(alpha = 0.06f), itemShape)
|
||||
.border(1.dp, Color.White.copy(alpha = 0.10f), itemShape)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable { expandedComposableCache[title] = !expanded }
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
) { expandedComposableCache[title] = !expanded }
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 12.dp, vertical = 12.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
@@ -196,7 +200,10 @@ class ConversationToolbox : Feature("Conversation Toolbox") {
|
||||
composable(alertDialog, openedConversationId)
|
||||
}.onFailure { throwable ->
|
||||
Text(
|
||||
"Failed to load: ${throwable.message}",
|
||||
context.translation.format(
|
||||
"conversation_toolbox.failed_to_load",
|
||||
"message" to (throwable.message ?: "unknown error")
|
||||
),
|
||||
color = PurrfectOverlayPalette.textSecondary,
|
||||
fontSize = 12.sp
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user