Add low-output tooling mode
This commit is contained in:
@@ -1,173 +0,0 @@
|
||||
package solutions.tretter.githugandroid
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
|
||||
data class GitMessageEditorState(
|
||||
val invocation: GitEditorInvocation,
|
||||
val content: String,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun GitMessageEditorDialog(
|
||||
state: GitMessageEditorState,
|
||||
onContentChange: (String) -> Unit,
|
||||
onClose: () -> Unit,
|
||||
onSave: () -> Unit,
|
||||
) {
|
||||
val horizontalScroll = rememberScrollState()
|
||||
val verticalScroll = rememberScrollState()
|
||||
val dialogScroll = rememberScrollState()
|
||||
val contentFocusRequester = remember { FocusRequester() }
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
LaunchedEffect(state.invocation.command) {
|
||||
runCatching { contentFocusRequester.requestFocus() }
|
||||
keyboardController?.show()
|
||||
}
|
||||
|
||||
Dialog(
|
||||
onDismissRequest = onClose,
|
||||
properties = DialogProperties(usePlatformDefaultWidth = false),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.imePadding()
|
||||
.verticalScroll(dialogScroll)
|
||||
.padding(12.dp),
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = 360.dp, max = 720.dp),
|
||||
color = PanelPrimary,
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||
) {
|
||||
Text(
|
||||
text = state.invocation.title,
|
||||
modifier = Modifier.testTag("git-message-editor-title"),
|
||||
color = TextPrimary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 20.sp,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
EditorButton(
|
||||
label = "Save",
|
||||
enabled = state.content.isNotBlank(),
|
||||
modifier = Modifier.testTag("git-message-editor-save"),
|
||||
onClick = onSave,
|
||||
)
|
||||
EditorButton(
|
||||
label = "Dismiss",
|
||||
modifier = Modifier.testTag("git-message-editor-dismiss"),
|
||||
onClick = onClose,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = state.invocation.displayPath,
|
||||
modifier = Modifier.testTag("git-message-editor-path"),
|
||||
color = TextSecondary,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 13.sp,
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.heightIn(min = 260.dp)
|
||||
.background(TerminalBackground, RoundedCornerShape(6.dp))
|
||||
.padding(10.dp)
|
||||
.horizontalScroll(horizontalScroll)
|
||||
.verticalScroll(verticalScroll),
|
||||
) {
|
||||
BasicTextField(
|
||||
value = state.content,
|
||||
onValueChange = onContentChange,
|
||||
modifier = Modifier
|
||||
.sizeIn(minWidth = 1200.dp, minHeight = 1200.dp)
|
||||
.focusRequester(contentFocusRequester)
|
||||
.testTag("git-message-editor-content"),
|
||||
textStyle = TextStyle(
|
||||
color = TextPrimary,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 14.sp,
|
||||
),
|
||||
cursorBrush = SolidColor(Accent),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
autoCorrect = false,
|
||||
keyboardType = KeyboardType.Ascii,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EditorButton(
|
||||
label: String,
|
||||
enabled: Boolean = true,
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
modifier = modifier,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Accent,
|
||||
contentColor = AppBackground,
|
||||
disabledContainerColor = PanelTertiary,
|
||||
disabledContentColor = TextMuted,
|
||||
),
|
||||
) {
|
||||
Text(label)
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,11 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
@@ -26,17 +24,16 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
@@ -50,6 +47,11 @@ data class TextEditorState(
|
||||
val saveAsPath: String,
|
||||
)
|
||||
|
||||
data class GitMessageEditorState(
|
||||
val invocation: GitEditorInvocation,
|
||||
val content: String,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun TextEditorDialog(
|
||||
state: TextEditorState,
|
||||
@@ -57,16 +59,75 @@ fun TextEditorDialog(
|
||||
onSaveAsPathChange: (String) -> Unit,
|
||||
onClose: () -> Unit,
|
||||
onSave: () -> Unit,
|
||||
) {
|
||||
ParameterizedTextEditorDialog(
|
||||
title = "Edit File",
|
||||
titleTag = null,
|
||||
metadata = "${state.editor} ${state.path.ifBlank { "<new file>" }}",
|
||||
metadataTag = null,
|
||||
metadataStyle = EditorMetadataStyle.Prominent,
|
||||
content = state.content,
|
||||
saveAsPath = state.saveAsPath,
|
||||
saveEnabled = state.saveAsPath.isNotBlank(),
|
||||
testTagPrefix = "text-editor",
|
||||
resetKey = "${state.originalCommand}\n${state.path}",
|
||||
onContentChange = onContentChange,
|
||||
onSaveAsPathChange = onSaveAsPathChange,
|
||||
onClose = onClose,
|
||||
onSave = onSave,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GitMessageEditorDialog(
|
||||
state: GitMessageEditorState,
|
||||
onContentChange: (String) -> Unit,
|
||||
onClose: () -> Unit,
|
||||
onSave: () -> Unit,
|
||||
) {
|
||||
ParameterizedTextEditorDialog(
|
||||
title = state.invocation.title,
|
||||
titleTag = "git-message-editor-title",
|
||||
metadata = state.invocation.displayPath,
|
||||
metadataTag = "git-message-editor-path",
|
||||
metadataStyle = EditorMetadataStyle.SecondaryMonospace,
|
||||
content = state.content,
|
||||
saveAsPath = null,
|
||||
saveEnabled = state.content.isNotBlank(),
|
||||
testTagPrefix = "git-message-editor",
|
||||
resetKey = "${state.invocation.command}\n${state.invocation.displayPath}",
|
||||
onContentChange = onContentChange,
|
||||
onSaveAsPathChange = {},
|
||||
onClose = onClose,
|
||||
onSave = onSave,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ParameterizedTextEditorDialog(
|
||||
title: String,
|
||||
titleTag: String?,
|
||||
metadata: String,
|
||||
metadataTag: String?,
|
||||
metadataStyle: EditorMetadataStyle,
|
||||
content: String,
|
||||
saveAsPath: String?,
|
||||
saveEnabled: Boolean,
|
||||
testTagPrefix: String,
|
||||
resetKey: String,
|
||||
onContentChange: (String) -> Unit,
|
||||
onSaveAsPathChange: (String) -> Unit,
|
||||
onClose: () -> Unit,
|
||||
onSave: () -> Unit,
|
||||
) {
|
||||
val editorHorizontalScroll = rememberScrollState()
|
||||
val editorVerticalScroll = rememberScrollState()
|
||||
val dialogScroll = rememberScrollState()
|
||||
val contentFocusRequester = remember { FocusRequester() }
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
LaunchedEffect(state.originalCommand, state.path) {
|
||||
runCatching { contentFocusRequester.requestFocus() }
|
||||
keyboardController?.show()
|
||||
LaunchedEffect(resetKey) {
|
||||
dialogScroll.scrollTo(0)
|
||||
editorVerticalScroll.scrollTo(0)
|
||||
editorHorizontalScroll.scrollTo(0)
|
||||
}
|
||||
|
||||
Dialog(
|
||||
@@ -92,7 +153,8 @@ fun TextEditorDialog(
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "Edit File",
|
||||
text = title,
|
||||
modifier = titleTag?.let { Modifier.testTag(it) } ?: Modifier,
|
||||
color = TextPrimary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 20.sp,
|
||||
@@ -101,26 +163,40 @@ fun TextEditorDialog(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
EditorButton(label = "Save", enabled = state.saveAsPath.isNotBlank(), onClick = onSave)
|
||||
EditorButton(label = "Dismiss", onClick = onClose)
|
||||
EditorButton(
|
||||
label = "Save",
|
||||
enabled = saveEnabled,
|
||||
modifier = Modifier.testTag("$testTagPrefix-save"),
|
||||
onClick = onSave,
|
||||
)
|
||||
EditorButton(
|
||||
label = "Dismiss",
|
||||
modifier = Modifier.testTag("$testTagPrefix-dismiss"),
|
||||
onClick = onClose,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "${state.editor} ${state.path.ifBlank { "<new file>" }}",
|
||||
color = TextPrimary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = state.saveAsPath,
|
||||
onValueChange = onSaveAsPathChange,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
autoCorrect = false,
|
||||
keyboardType = KeyboardType.Ascii,
|
||||
imeAction = ImeAction.Done,
|
||||
),
|
||||
label = { Text("File name") },
|
||||
text = metadata,
|
||||
modifier = metadataTag?.let { Modifier.testTag(it) } ?: Modifier,
|
||||
color = metadataStyle.color,
|
||||
fontFamily = metadataStyle.fontFamily,
|
||||
fontWeight = metadataStyle.fontWeight,
|
||||
fontSize = metadataStyle.fontSize,
|
||||
)
|
||||
saveAsPath?.let { path ->
|
||||
OutlinedTextField(
|
||||
value = path,
|
||||
onValueChange = onSaveAsPathChange,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
autoCorrect = false,
|
||||
keyboardType = KeyboardType.Ascii,
|
||||
imeAction = ImeAction.Done,
|
||||
),
|
||||
label = { Text("File name") },
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -132,11 +208,11 @@ fun TextEditorDialog(
|
||||
.verticalScroll(editorVerticalScroll),
|
||||
) {
|
||||
BasicTextField(
|
||||
value = state.content,
|
||||
value = content,
|
||||
onValueChange = onContentChange,
|
||||
modifier = Modifier
|
||||
.sizeIn(minWidth = 1200.dp, minHeight = 1200.dp)
|
||||
.focusRequester(contentFocusRequester),
|
||||
.testTag("$testTagPrefix-content"),
|
||||
textStyle = TextStyle(
|
||||
color = TextPrimary,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
@@ -155,15 +231,34 @@ fun TextEditorDialog(
|
||||
}
|
||||
}
|
||||
|
||||
private enum class EditorMetadataStyle(
|
||||
val color: Color,
|
||||
val fontFamily: FontFamily? = null,
|
||||
val fontWeight: FontWeight? = null,
|
||||
val fontSize: TextUnit = 14.sp,
|
||||
) {
|
||||
Prominent(
|
||||
color = TextPrimary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
),
|
||||
SecondaryMonospace(
|
||||
color = TextSecondary,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 13.sp,
|
||||
),
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EditorButton(
|
||||
label: String,
|
||||
enabled: Boolean = true,
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
modifier = modifier,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Accent,
|
||||
contentColor = AppBackground,
|
||||
|
||||
Reference in New Issue
Block a user