diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a0c6ece..e8358bf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -19,8 +19,8 @@ android { applicationId = "solutions.tretter.githugandroid" minSdk = 26 targetSdk = 35 - versionCode = 159 - versionName = "0.1.158" + versionCode = 160 + versionName = "0.1.159" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true diff --git a/app/src/main/java/solutions/tretter/githugandroid/GitHugApp.kt b/app/src/main/java/solutions/tretter/githugandroid/GitHugApp.kt index 0e3cecc..34f1d41 100644 --- a/app/src/main/java/solutions/tretter/githugandroid/GitHugApp.kt +++ b/app/src/main/java/solutions/tretter/githugandroid/GitHugApp.kt @@ -186,7 +186,10 @@ fun GitHugApp() { } } - fun applyRecommendedPaneWeights(persist: Boolean = true) { + fun applyRecommendedPaneWeights( + persist: Boolean = true, + outputLineCount: Int = terminalOutputLineCount(output), + ) { updatePaneLayout( transform = { layout -> layout.copy( @@ -194,7 +197,7 @@ fun GitHugApp() { heights = recommendedPaneHeights( level = currentLevel, levelCount = levels.size, - outputLineCount = output.size, + outputLineCount = outputLineCount, screenHeightDp = screenHeightDp, suggestionsVisible = activeExerciseDetail == ExerciseDetailPanel.SUGGESTIONS, visibleHint = visibleHint, @@ -223,7 +226,7 @@ fun GitHugApp() { editorState = null gitMessageEditorState = null manPageState = null - applyRecommendedPaneWeights(persist = false) + applyRecommendedPaneWeights(persist = false, outputLineCount = terminalOutputLineCount(listOf(message))) } fun loadLevel( @@ -307,7 +310,9 @@ fun GitHugApp() { val replacement = if (matches.size == 1) matches.first() else commonPrefix(matches) if (replacement == token && matches.size > 1) { - output = output + "completion> ${matches.joinToString(" ")}" + val newOutput = output + "completion> ${matches.joinToString(" ")}" + output = newOutput + applyRecommendedPaneWeights(persist = false, outputLineCount = terminalOutputLineCount(newOutput)) return } @@ -353,15 +358,17 @@ fun GitHugApp() { AppLog.d("GitHugApp", "All levels completed") scope.launch { persistProgress(updatedCompletedLevels, levels.lastOrNull()?.id) } repo = newRepo - output = newOutput + listOf("🏁 All Githug levels completed.") + val completedOutput = newOutput + listOf("🏁 All Githug levels completed.") + output = completedOutput clearCommandInput() suppressedImeEcho = null + applyRecommendedPaneWeights(persist = false, outputLineCount = terminalOutputLineCount(completedOutput)) } } else { AppLog.d("GitHugApp", "Staying on level=${levelForResult.id}") repo = newRepo output = newOutput - applyRecommendedPaneWeights(persist = false) + applyRecommendedPaneWeights(persist = false, outputLineCount = terminalOutputLineCount(newOutput)) } } @@ -372,7 +379,7 @@ fun GitHugApp() { } else { runtime.readEditorFile(currentLevel, repo, path) } - output = buildList { + val newOutput = buildList { addAll(output) add("$ ${invocation.command}") addAll(lines) @@ -380,6 +387,7 @@ fun GitHugApp() { add("Opened ${invocation.editor} editor${if (path.isBlank()) "" else " for $path"}") } } + output = newOutput if (lines.isEmpty()) { editorState = TextEditorState( editor = invocation.editor, @@ -389,18 +397,19 @@ fun GitHugApp() { saveAsPath = path, ) } - applyRecommendedPaneWeights(persist = false) + applyRecommendedPaneWeights(persist = false, outputLineCount = terminalOutputLineCount(newOutput)) } fun openManPage(invocation: GitHelpInvocation) { val content = runtime.gitManPage(currentLevel, repo, invocation.topic) - output = buildList { + val newOutput = buildList { addAll(output) add("$ ${invocation.command}") add("Opened git help viewer for ${invocation.topic}") } + output = newOutput manPageState = ManPageState(topic = invocation.topic, content = content) - applyRecommendedPaneWeights(persist = false) + applyRecommendedPaneWeights(persist = false, outputLineCount = terminalOutputLineCount(newOutput)) } fun openGitMessageEditor(invocation: GitEditorInvocation) { @@ -410,16 +419,17 @@ fun GitHugApp() { GitEditorCommandKind.PATCH_HUNK -> "Opened Git patch editor" else -> "Opened Git message editor" } - output = buildList { + val newOutput = buildList { addAll(output) add("$ ${invocation.command}") add(openedMessage) } + output = newOutput gitMessageEditorState = GitMessageEditorState( invocation = invocation.copy(initialContent = initialContent), content = initialContent, ) - applyRecommendedPaneWeights(persist = false) + applyRecommendedPaneWeights(persist = false, outputLineCount = terminalOutputLineCount(newOutput)) } fun saveEditor() { @@ -490,7 +500,9 @@ fun GitHugApp() { } fun showCommandHelp() { - output = output + runtime.commandReferenceLines() + val newOutput = output + runtime.commandReferenceLines() + output = newOutput + applyRecommendedPaneWeights(persist = false, outputLineCount = terminalOutputLineCount(newOutput)) } fun registerHeaderTap() { diff --git a/app/src/main/java/solutions/tretter/githugandroid/ManPageDialog.kt b/app/src/main/java/solutions/tretter/githugandroid/ManPageDialog.kt index 98bd74a..01e90d1 100644 --- a/app/src/main/java/solutions/tretter/githugandroid/ManPageDialog.kt +++ b/app/src/main/java/solutions/tretter/githugandroid/ManPageDialog.kt @@ -39,6 +39,7 @@ import androidx.compose.ui.unit.IntSize 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 ManPageState( val topic: String, @@ -131,7 +132,10 @@ fun ManPageDialog( horizontalScrollState.animateScrollTo(horizontalTarget) } - Dialog(onDismissRequest = onClose) { + Dialog( + onDismissRequest = onClose, + properties = DialogProperties(usePlatformDefaultWidth = false), + ) { Surface( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/solutions/tretter/githugandroid/PaneLayoutLogic.kt b/app/src/main/java/solutions/tretter/githugandroid/PaneLayoutLogic.kt index ee61420..6d3af28 100644 --- a/app/src/main/java/solutions/tretter/githugandroid/PaneLayoutLogic.kt +++ b/app/src/main/java/solutions/tretter/githugandroid/PaneLayoutLogic.kt @@ -29,7 +29,7 @@ fun recommendedPaneHeights( val suggestionsLines = if (suggestionsVisible) level.commandSuggestions.size + 1 else 0 val hintLines = visibleHint?.let { (it.length / 42).coerceAtLeast(1) + 1 } ?: 0 val exerciseHeight = (120 + descriptionLines * 24 + suggestionsLines * 22 + hintLines * 22).coerceAtLeast(180) - val terminalHeight = (170 + outputLineCount.coerceAtLeast(1) * 20).coerceAtMost((screenHeight * 0.7f).toInt()) + val terminalHeight = (170 + outputLineCount.coerceAtLeast(1) * 24).coerceAtMost((screenHeight * 0.8f).toInt() + 140) val visualHeight = (screenHeight * 0.24f).toInt().coerceAtLeast(170) return mapOf( @@ -69,4 +69,4 @@ fun commonPrefix(values: List): String { } } return prefix -} \ No newline at end of file +} diff --git a/app/src/main/java/solutions/tretter/githugandroid/Terminal.kt b/app/src/main/java/solutions/tretter/githugandroid/Terminal.kt index dd62b4a..6c84183 100644 --- a/app/src/main/java/solutions/tretter/githugandroid/Terminal.kt +++ b/app/src/main/java/solutions/tretter/githugandroid/Terminal.kt @@ -55,6 +55,10 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +fun terminalOutputDisplayLines(output: List): List = output.flatMap { line -> line.lines() } + +fun terminalOutputLineCount(output: List): Int = terminalOutputDisplayLines(output).size.coerceAtLeast(1) + @OptIn(ExperimentalFoundationApi::class) @Composable fun TerminalPane( @@ -78,12 +82,11 @@ fun TerminalPane( val outputHorizontalScroll = rememberScrollState() val outputVerticalScroll = rememberScrollState() val terminalMinWidth = 80.dp * 7.2f - val terminalPaneMaxHeight = configuration.screenHeightDp.dp * 0.7f - val reservedControlsHeight = 86.dp - val maxOutputHeight = (terminalPaneMaxHeight - reservedControlsHeight).coerceAtLeast(120.dp) - val outputLineHeight = 20.dp - val hasOutput = output.isNotEmpty() - val desiredOutputHeight = (output.size.coerceAtLeast(1) * outputLineHeight.value) + val displayOutput = remember(output) { terminalOutputDisplayLines(output) } + val maxOutputHeight = (configuration.screenHeightDp.dp * 0.8f).coerceAtLeast(120.dp) + val outputLineHeight = 24.dp + val hasOutput = displayOutput.isNotEmpty() + val desiredOutputHeight = (16 + displayOutput.size.coerceAtLeast(1) * outputLineHeight.value) .dp .coerceAtLeast(48.dp) .coerceAtMost(maxOutputHeight) @@ -93,7 +96,7 @@ fun TerminalPane( focusRequester.requestFocus() } - LaunchedEffect(output.size) { + LaunchedEffect(displayOutput.size) { outputVerticalScroll.animateScrollTo(outputVerticalScroll.maxValue) } @@ -140,7 +143,7 @@ fun TerminalPane( modifier = Modifier.widthIn(min = terminalMinWidth), verticalArrangement = Arrangement.spacedBy(4.dp), ) { - output.forEach { line -> + displayOutput.forEach { line -> Text( text = line, color = if (line.startsWith("✔") || line.startsWith("🏁")) Success else TextSecondary,