Auto-commit after successful build: update app gameplay/UI, improve build setup

Changed files:\napp/build.gradle.kts
app/src/main/java/com/kawomi/githugandroid/GitHugApp.kt
This commit is contained in:
Joe Tretter
2026-04-23 10:11:01 -05:00
parent c0ea54c784
commit 21334203c7
2 changed files with 73 additions and 36 deletions

View File

@@ -11,8 +11,8 @@ android {
applicationId = "com.kawomi.githugandroid"
minSdk = 26
targetSdk = 34
versionCode = 20
versionName = "0.1.19"
versionCode = 22
versionName = "0.1.21"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true

View File

@@ -7,16 +7,19 @@ import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.draggable
import androidx.compose.foundation.gestures.rememberDraggableState
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
@@ -35,6 +38,8 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TextButton
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
@@ -50,6 +55,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalConfiguration
@@ -66,6 +72,8 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.relocation.bringIntoViewRequester
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
@@ -119,10 +127,10 @@ private fun defaultPaneLayout(): PaneLayout = PaneLayout(
order = listOf(PaneId.LEVELS, PaneId.VISUAL, PaneId.EXERCISE, PaneId.TERMINAL),
collapsed = emptySet(),
weights = mapOf(
PaneId.LEVELS to 1.1f,
PaneId.VISUAL to 1.3f,
PaneId.EXERCISE to 1.0f,
PaneId.TERMINAL to 1.8f,
PaneId.LEVELS to 0.9f,
PaneId.VISUAL to 1.0f,
PaneId.EXERCISE to 0.9f,
PaneId.TERMINAL to 1.4f,
),
)
@@ -190,11 +198,14 @@ private class PaneLayoutStore(private val context: Context) {
fun GitHugApp() {
MaterialTheme(colorScheme = GitHugColorScheme) {
val context = LocalContext.current
val configuration = LocalConfiguration.current
val levels = remember { sampleLevels() }
val runtime = remember(context) { GitRepositoryRuntime(context.applicationContext) }
val paneLayoutStore = remember(context) { PaneLayoutStore(context.applicationContext) }
val persistedPaneLayout by paneLayoutStore.layoutFlow.collectAsState(initial = defaultPaneLayout())
val scope = rememberCoroutineScope()
val screenScrollState = rememberScrollState()
val workspaceHeight = (configuration.screenHeightDp.dp * 0.72f).coerceAtLeast(420.dp)
var paneLayout by remember { mutableStateOf(defaultPaneLayout()) }
var currentLevelIndex by remember { mutableStateOf(0) }
@@ -355,13 +366,18 @@ fun GitHugApp() {
) {
Column(
modifier = Modifier
.fillMaxSize()
.fillMaxWidth()
.background(AppBackground)
.padding(12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
.verticalScroll(screenScrollState)
.imePadding()
.padding(horizontal = 10.dp, vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
FixedHeader()
PaneWorkspace(
modifier = Modifier
.fillMaxWidth()
.height(workspaceHeight),
paneLayout = paneLayout,
onMovePane = { paneId, delta ->
updatePaneLayout { layout -> movePane(layout, paneId, delta) }
@@ -417,6 +433,7 @@ fun GitHugApp() {
)
},
)
Spacer(modifier = Modifier.height(220.dp))
}
}
}
@@ -427,30 +444,28 @@ fun GitHugApp() {
private fun FixedHeader() {
Card(
colors = CardDefaults.cardColors(containerColor = PanelPrimary),
shape = RoundedCornerShape(18.dp),
shape = RoundedCornerShape(14.dp),
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 14.dp),
.padding(horizontal = 12.dp, vertical = 10.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
) {
Image(
painter = painterResource(id = R.drawable.githug_android_logo),
contentDescription = "GitHug Android logo",
modifier = Modifier.size(40.dp),
modifier = Modifier.size(28.dp),
)
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
Text("GitHug Android", style = MaterialTheme.typography.headlineSmall, color = TextPrimary)
Text("Customizable panes for Git learning on phone and tablet.", color = TextSecondary)
}
Text("GitHug Android", style = MaterialTheme.typography.titleLarge, color = TextPrimary)
}
}
}
@Composable
private fun PaneWorkspace(
modifier: Modifier = Modifier,
paneLayout: PaneLayout,
onMovePane: (PaneId, Int) -> Unit,
onTogglePane: (PaneId) -> Unit,
@@ -460,7 +475,7 @@ private fun PaneWorkspace(
exerciseContent: @Composable () -> Unit,
terminalContent: @Composable () -> Unit,
) {
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
BoxWithConstraints(modifier = modifier) {
val heightBasis = maxHeight.value.takeIf { it > 0f } ?: 1f
Column(
@@ -592,7 +607,7 @@ private fun PaneHeader(
modifier = Modifier
.fillMaxWidth()
.background(if (collapsed) PanelTertiary else PanelPrimary)
.padding(horizontal = 12.dp, vertical = 10.dp),
.padding(horizontal = 10.dp, vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
@@ -614,13 +629,13 @@ private fun HeaderActionButton(
TextButton(
onClick = onClick,
enabled = enabled,
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 0.dp),
contentPadding = PaddingValues(horizontal = 6.dp, vertical = 0.dp),
colors = ButtonDefaults.textButtonColors(
contentColor = Accent,
disabledContentColor = TextMuted,
),
) {
Text(label, fontSize = 12.sp)
Text(label, fontSize = 11.sp)
}
}
@@ -636,7 +651,7 @@ private fun PaneDivider(
Box(
modifier = Modifier
.fillMaxWidth()
.height(12.dp)
.height(6.dp)
.draggable(
state = dragState,
orientation = Orientation.Vertical,
@@ -647,7 +662,7 @@ private fun PaneDivider(
Box(
modifier = Modifier
.fillMaxWidth()
.height(2.dp)
.height(1.dp)
.background(if (enabled) Accent.copy(alpha = 0.45f) else PanelTertiary),
)
}
@@ -671,7 +686,7 @@ private fun LevelsPane(
colors = CardDefaults.cardColors(
containerColor = if (index == currentLevelIndex) PanelTertiary else PanelPrimary,
),
shape = RoundedCornerShape(12.dp),
shape = RoundedCornerShape(10.dp),
) {
TextButton(
onClick = { onSelect(index) },
@@ -800,13 +815,13 @@ private fun InfoPaneCard(
Card(
modifier = modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = PanelPrimary),
shape = RoundedCornerShape(14.dp),
shape = RoundedCornerShape(10.dp),
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(12.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
Text(title, color = TextPrimary, fontWeight = FontWeight.Bold)
Text(
@@ -818,6 +833,7 @@ private fun InfoPaneCard(
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun TerminalPane(
output: List<String>,
@@ -833,6 +849,7 @@ private fun TerminalPane(
onHistoryDown: () -> Unit,
) {
val focusRequester = remember { FocusRequester() }
val bringIntoViewRequester = remember { BringIntoViewRequester() }
val focusManager = LocalFocusManager.current
val keyboardController = LocalSoftwareKeyboardController.current
val horizontalScroll = rememberScrollState()
@@ -846,6 +863,10 @@ private fun TerminalPane(
keyboardController?.show()
}
LaunchedEffect(output.size) {
outputVerticalScroll.animateScrollTo(outputVerticalScroll.maxValue)
}
fun submitCommand() {
focusManager.clearFocus(force = true)
keyboardController?.hide()
@@ -856,7 +877,7 @@ private fun TerminalPane(
modifier = Modifier
.fillMaxSize()
.background(TerminalBackground, RoundedCornerShape(12.dp))
.padding(12.dp)
.padding(8.dp)
.horizontalScroll(horizontalScroll),
) {
Column(
@@ -871,7 +892,7 @@ private fun TerminalPane(
.weight(1f)
.fillMaxWidth()
.background(PanelPrimary, RoundedCornerShape(10.dp))
.padding(12.dp)
.padding(8.dp)
.verticalScroll(outputVerticalScroll),
) {
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
@@ -894,9 +915,10 @@ private fun TerminalPane(
)
Row(
modifier = Modifier
.bringIntoViewRequester(bringIntoViewRequester)
.fillMaxWidth()
.background(PanelPrimary, RoundedCornerShape(8.dp))
.padding(horizontal = 12.dp, vertical = 10.dp),
.padding(horizontal = 8.dp, vertical = 4.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
@@ -907,15 +929,30 @@ private fun TerminalPane(
fontWeight = FontWeight.Bold,
)
key(inputFieldVersion) {
BasicTextField(
TextField(
value = commandInput,
onValueChange = onValueChange,
modifier = Modifier
.weight(1f)
.focusRequester(focusRequester),
.focusRequester(focusRequester)
.onFocusChanged { state ->
if (state.isFocused) {
keyboardController?.show()
}
},
singleLine = true,
textStyle = TextStyle(color = TextPrimary, fontFamily = FontFamily.Monospace),
cursorBrush = SolidColor(Accent),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
disabledContainerColor = Color.Transparent,
cursorColor = Accent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
focusedTextColor = TextPrimary,
unfocusedTextColor = TextPrimary,
),
keyboardOptions = KeyboardOptions(
autoCorrect = false,
keyboardType = KeyboardType.Ascii,
@@ -960,8 +997,8 @@ private fun TerminalKeyButton(
) {
Button(
onClick = onClick,
modifier = modifier.height(34.dp),
contentPadding = PaddingValues(horizontal = 10.dp, vertical = 4.dp),
modifier = modifier.height(28.dp),
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 2.dp),
colors = ButtonDefaults.buttonColors(
containerColor = PanelSecondary,
contentColor = TextPrimary,
@@ -971,7 +1008,7 @@ private fun TerminalKeyButton(
text = label,
fontFamily = fontFamily,
fontWeight = FontWeight.Bold,
fontSize = 13.sp,
fontSize = 11.sp,
)
}
}