diff --git a/app/src/main/java/chat/revolt/components/generic/SheetButton.kt b/app/src/main/java/chat/revolt/components/generic/SheetButton.kt index 8b2c47da..b177a4b5 100644 --- a/app/src/main/java/chat/revolt/components/generic/SheetButton.kt +++ b/app/src/main/java/chat/revolt/components/generic/SheetButton.kt @@ -20,7 +20,8 @@ fun SheetButton( modifier: Modifier = Modifier, supportingContent: @Composable (() -> Unit)? = null, trailingContent: @Composable (() -> Unit)? = null, - dangerous: Boolean = false + dangerous: Boolean = false, + special: Boolean = false ) { Box( modifier = modifier @@ -33,6 +34,8 @@ fun SheetButton( CompositionLocalProvider( value = if (dangerous) { LocalContentColor provides MaterialTheme.colorScheme.error + } else if (special) { + LocalContentColor provides MaterialTheme.colorScheme.primary } else { LocalContentColor provides MaterialTheme.colorScheme.onSurface } @@ -44,6 +47,8 @@ fun SheetButton( CompositionLocalProvider( value = if (dangerous) { LocalContentColor provides MaterialTheme.colorScheme.error + } else if (special) { + LocalContentColor provides MaterialTheme.colorScheme.primary } else { LocalContentColor provides MaterialTheme.colorScheme.onSurface } @@ -56,6 +61,8 @@ fun SheetButton( CompositionLocalProvider( value = if (dangerous) { LocalContentColor provides MaterialTheme.colorScheme.error + } else if (special) { + LocalContentColor provides MaterialTheme.colorScheme.primary } else { LocalContentColor provides MaterialTheme.colorScheme.onSurface } @@ -69,6 +76,8 @@ fun SheetButton( CompositionLocalProvider( value = if (dangerous) { LocalContentColor provides MaterialTheme.colorScheme.error + } else if (special) { + LocalContentColor provides MaterialTheme.colorScheme.primary } else { LocalContentColor provides MaterialTheme.colorScheme.onSurface } diff --git a/app/src/main/java/chat/revolt/sheets/JBMDebuggerSheet.kt b/app/src/main/java/chat/revolt/sheets/JBMDebuggerSheet.kt new file mode 100644 index 00000000..ddf64a5f --- /dev/null +++ b/app/src/main/java/chat/revolt/sheets/JBMDebuggerSheet.kt @@ -0,0 +1,103 @@ +package chat.revolt.sheets + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.unit.dp +import chat.revolt.components.generic.SheetHeaderPadding +import chat.revolt.markdown.jbm.JBM +import chat.revolt.markdown.jbm.JBMApi +import org.intellij.markdown.ast.ASTNode +import org.intellij.markdown.ast.getTextInNode + +@OptIn(JBM::class) +@Composable +fun JBMDebuggerSheet(content: String, modifier: Modifier = Modifier) { + val rendered = remember(content) { JBMApi.parse(content) } + Column { + SheetHeaderPadding { + Text( + text = "Inspect AST", + style = MaterialTheme.typography.headlineSmall + ) + } + Column(modifier.verticalScroll(rememberScrollState())) { + JBMDebugTree(rendered, content) + } + } +} + +@Composable +fun JBMDebugTree(node: ASTNode, source: String, modifier: Modifier = Modifier) { + var showChildren by remember { mutableStateOf(false) } + val scheme = MaterialTheme.colorScheme + + Column( + modifier + .padding(start = 16.dp) + .clickable { showChildren = !showChildren }) { + JBMDebugNode(node, source, showChildren) + if (showChildren && node.children.isNotEmpty()) { + Column(Modifier.drawBehind { + drawLine( + color = scheme.primary, + start = Offset(0f, 0f), + end = Offset(0f, size.height), + strokeWidth = 2.dp.toPx() + ) + }) { + node.children.forEach { JBMDebugTree(it, source) } + } + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun JBMDebugNode(node: ASTNode, source: String, showingChildren: Boolean) { + Column { + FlowRow { + if (node.children.isNotEmpty()) { + Text(if (showingChildren) "▼ " else "▶ ") + } + Text(node.type.toString()) + Text(" - ") + if (node.children.isNotEmpty()) { + Text("${node.children.size} " + if (node.children.size == 1) "child" else "children") + } else { + Text("No children") + } + } + + val text = try { + node.getTextInNode(source) + } catch (e: Exception) { + "" + } + Text( + text.take(50).toString() + if (text.length > 50) "…" else "", + color = if (text == "") MaterialTheme.colorScheme.error else LocalContentColor.current, + modifier = Modifier.padding(4.dp) + ) + HorizontalDivider( + Modifier.fillMaxWidth() + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/sheets/MessageContextSheet.kt b/app/src/main/java/chat/revolt/sheets/MessageContextSheet.kt index 1eed0801..7cf11a3f 100644 --- a/app/src/main/java/chat/revolt/sheets/MessageContextSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/MessageContextSheet.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.unit.dp +import chat.revolt.BuildConfig import chat.revolt.R import chat.revolt.api.REVOLT_APP import chat.revolt.api.RevoltAPI @@ -44,6 +45,7 @@ import chat.revolt.api.internals.Roles import chat.revolt.api.internals.has import chat.revolt.api.routes.channel.deleteMessage import chat.revolt.api.routes.channel.react +import chat.revolt.api.settings.Experiments import chat.revolt.callbacks.UiCallbacks import chat.revolt.components.chat.Message import chat.revolt.components.generic.SheetButton @@ -76,6 +78,9 @@ fun MessageContextSheet( var showShareSheet by remember { mutableStateOf(false) } var showReactSheet by remember { mutableStateOf(false) } var showDeleteMessageConfirmation by remember { mutableStateOf(false) } + var showInspectASTSheet by remember { mutableStateOf(false) } + val showInspectASTSheetButton = + BuildConfig.DEBUG || (message.content != null && Experiments.useKotlinBasedMarkdownRenderer.isEnabled) if (showShareSheet) { val shareSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) @@ -305,6 +310,19 @@ fun MessageContextSheet( ) } + if (showInspectASTSheet) { + val inspectASTSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + + ModalBottomSheet( + sheetState = inspectASTSheetState, + onDismissRequest = { + showInspectASTSheet = false + } + ) { + JBMDebuggerSheet(message.content ?: "") + } + } + Column( modifier = Modifier .verticalScroll(rememberScrollState()) @@ -407,6 +425,26 @@ fun MessageContextSheet( } ) + if (showInspectASTSheetButton) { + SheetButton( + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.ic_file_tree_24dp), + contentDescription = null + ) + }, + headlineContent = { + Text( + text = "Inspect AST" + ) + }, + onClick = { + showInspectASTSheet = true + }, + special = true + ) + } + SheetButton( leadingContent = { Icon( diff --git a/app/src/main/res/drawable/ic_file_tree_24dp.xml b/app/src/main/res/drawable/ic_file_tree_24dp.xml new file mode 100644 index 00000000..819ef909 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_tree_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file