From c65f7d0547661b9af6fbbde9fb5c3e025acf5174 Mon Sep 17 00:00:00 2001 From: Joe Tretter Date: Thu, 23 Apr 2026 13:09:29 -0500 Subject: [PATCH] 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 --- app/build.gradle.kts | 4 +- .../com/kawomi/githugandroid/GitHugApp.kt | 62 ++++++++++++++++--- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 22fd2d0..9814121 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -11,8 +11,8 @@ android { applicationId = "com.kawomi.githugandroid" minSdk = 26 targetSdk = 34 - versionCode = 28 - versionName = "0.1.27" + versionCode = 29 + versionName = "0.1.28" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true diff --git a/app/src/main/java/com/kawomi/githugandroid/GitHugApp.kt b/app/src/main/java/com/kawomi/githugandroid/GitHugApp.kt index 174cf64..ddd5bc1 100644 --- a/app/src/main/java/com/kawomi/githugandroid/GitHugApp.kt +++ b/app/src/main/java/com/kawomi/githugandroid/GitHugApp.kt @@ -123,6 +123,11 @@ private data class PaneLayout( val weights: Map, ) +private enum class ExerciseDetailPanel { + HINT, + SUGGESTIONS, +} + private fun defaultPaneLayout(): PaneLayout = PaneLayout( order = listOf(PaneId.EXERCISE, PaneId.TERMINAL, PaneId.VISUAL, PaneId.LEVELS), collapsed = emptySet(), @@ -205,7 +210,6 @@ fun GitHugApp() { val persistedPaneLayout by paneLayoutStore.layoutFlow.collectAsState(initial = defaultPaneLayout()) val scope = rememberCoroutineScope() val screenScrollState = rememberScrollState() - val workspaceHeight = (configuration.screenHeightDp.dp * 1.05f).coerceAtLeast(560.dp) val screenHeightDp = configuration.screenHeightDp var paneLayout by remember { mutableStateOf(defaultPaneLayout()) } @@ -216,7 +220,8 @@ fun GitHugApp() { var suppressedImeEcho by remember { mutableStateOf(null) } var output by remember { mutableStateOf(listOf(runtime.startupBanner())) } var hintIndex by remember { mutableStateOf(0) } - var suggestionsExpanded by remember { mutableStateOf(false) } + var activeExerciseDetail by remember { mutableStateOf(null) } + var visibleHint by remember { mutableStateOf(null) } var completedLevels by remember { mutableStateOf(setOf()) } var commandHistory by remember { mutableStateOf(listOf()) } var historyIndex by remember { mutableStateOf(-1) } @@ -258,13 +263,26 @@ fun GitHugApp() { ) } + val recommendedWeights = recommendedPaneWeights( + level = currentLevel, + levelCount = levels.size, + outputLineCount = output.size, + screenHeightDp = screenHeightDp, + ) + val workspaceHeight = recommendedWorkspaceHeight( + paneLayout = paneLayout, + recommendedWeights = recommendedWeights, + screenHeightDp = screenHeightDp, + ) + fun resetCurrentLevel(message: String = "Level reset.") { repo = runtime.prepareLevel(currentLevel) clearCommandInput() suppressedImeEcho = null output = listOf(message) hintIndex = 0 - suggestionsExpanded = false + activeExerciseDetail = null + visibleHint = null historyIndex = -1 historyDraft = "" applyRecommendedPaneWeights(persist = false) @@ -277,7 +295,8 @@ fun GitHugApp() { clearCommandInput() suppressedImeEcho = null hintIndex = 0 - suggestionsExpanded = false + activeExerciseDetail = null + visibleHint = null historyIndex = -1 historyDraft = "" paneLayout = paneLayout.copy( @@ -434,11 +453,15 @@ fun GitHugApp() { exerciseContent = { ExercisePane( level = currentLevel, - suggestionsExpanded = suggestionsExpanded, - onToggleSuggestions = { suggestionsExpanded = !suggestionsExpanded }, + visibleHint = if (activeExerciseDetail == ExerciseDetailPanel.HINT) visibleHint else null, + suggestionsExpanded = activeExerciseDetail == ExerciseDetailPanel.SUGGESTIONS, + onToggleSuggestions = { + activeExerciseDetail = if (activeExerciseDetail == ExerciseDetailPanel.SUGGESTIONS) null else ExerciseDetailPanel.SUGGESTIONS + }, onHint = { val hint = currentLevel.hints.getOrNull(hintIndex) ?: "No more hints for this level." - output = output + "hint> $hint" + visibleHint = hint + activeExerciseDetail = ExerciseDetailPanel.HINT hintIndex = (hintIndex + 1).coerceAtMost(currentLevel.hints.size) }, onReset = { resetCurrentLevel() }, @@ -890,6 +913,7 @@ private fun VisualPane(repo: RepoState) { @Composable private fun ExercisePane( level: Level, + visibleHint: String?, suggestionsExpanded: Boolean, onToggleSuggestions: () -> Unit, onHint: () -> Unit, @@ -930,6 +954,10 @@ private fun ExercisePane( Text(suggestion, color = TextSecondary, fontFamily = FontFamily.Monospace) } } + if (visibleHint != null) { + Text("Hint", color = TextPrimary, fontWeight = FontWeight.Bold) + Text(visibleHint, color = TextSecondary) + } } } @@ -983,7 +1011,9 @@ private fun TerminalPane( val horizontalScroll = rememberScrollState() val outputVerticalScroll = rememberScrollState() val terminalMinWidth = 80.dp * 7.2f - val maxOutputHeight = configuration.screenHeightDp.dp * 0.7f + val terminalPaneMaxHeight = configuration.screenHeightDp.dp * 0.7f + val reservedControlsHeight = 86.dp + val maxOutputHeight = (terminalPaneMaxHeight - reservedControlsHeight).coerceAtLeast(120.dp) val outputLineHeight = 20.dp val desiredOutputHeight = (output.size.coerceAtLeast(6) * outputLineHeight.value).dp.coerceAtMost(maxOutputHeight) @@ -1187,6 +1217,22 @@ private fun recommendedPaneWeights( ) } +private fun recommendedWorkspaceHeight( + paneLayout: PaneLayout, + recommendedWeights: Map, + screenHeightDp: Int, +): androidx.compose.ui.unit.Dp { + val screenHeight = screenHeightDp.coerceAtLeast(560) + val dividerHeight = 18 * (paneLayout.order.size - 1) + val collapsedPaneHeight = 44 * paneLayout.collapsed.size + val expandedHeight = paneLayout.order + .filterNot { it in paneLayout.collapsed } + .sumOf { pane -> + (recommendedWeights[pane] ?: 1f * screenHeight).toInt() + } + return (expandedHeight + dividerHeight + collapsedPaneHeight).coerceAtLeast(screenHeight / 2).dp +} + private fun commonPrefix(values: List): String { if (values.isEmpty()) return "" var prefix = values.first()