From 891866c99919d5a9d7fece9a6e74187071a93216 Mon Sep 17 00:00:00 2001 From: Alon Albert Date: Sat, 4 May 2024 19:26:50 -0700 Subject: [PATCH] Add a Progress Indicator I tried to add a popup dialog with a progress bar but I couldn't get the dialog to show. I added it to the status bar instead. --- build.gradle.kts | 1 + .../romainguy/kotlin/explorer/Disassembly.kt | 37 ++++++++++++------- .../kotlin/explorer/KotlinExplorer.kt | 31 +++++++++++----- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 40f24195..86d97c6d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,6 +32,7 @@ kotlin { implementation("org.jetbrains.jewel:jewel-int-ui-decorated-window-241:${extra["jewel.version"] as String}") implementation("org.jetbrains.skiko:skiko-awt-runtime-macos-arm64:${extra["skiko.version"] as String}") implementation("org.jetbrains.compose.components:components-splitpane-desktop:${extra["compose.version"] as String}") + implementation("org.jetbrains.compose.material3:material3-desktop:${extra["compose.version"] as String}") implementation("com.fifesoft:rsyntaxtextarea:${extra["rsyntaxtextarea.version"] as String}") implementation("com.fifesoft:rstaui:${extra["rstaui.version"] as String}") implementation("net.java.dev.jna:jna:${extra["jna.version"] as String}") diff --git a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt index 10a91b7b..a9b7c0f3 100644 --- a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt +++ b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt @@ -17,24 +17,32 @@ package dev.romainguy.kotlin.explorer import dev.romainguy.kotlin.explorer.dex.DexDumpParser -import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.currentCoroutineContext +import kotlinx.coroutines.launch import java.nio.file.Files import java.nio.file.Path import java.util.stream.Collectors import kotlin.io.path.extension +private const val TotalSteps = 5 +private const val Done = 1f + suspend fun disassemble( toolPaths: ToolPaths, source: String, onDex: (String) -> Unit, onOat: (String) -> Unit, - onStatusUpdate: (String) -> Unit, + onStatusUpdate: (String, Float) -> Unit, optimize: Boolean ) = coroutineScope { val ui = currentCoroutineContext() launch(Dispatchers.IO) { - launch(ui) { onStatusUpdate("Compiling Kotlin…") } + var step = 0f + + launch(ui) { onStatusUpdate("Compiling Kotlin…", step++ / TotalSteps) } val directory = toolPaths.tempDirectory cleanupClasses(directory) @@ -50,7 +58,7 @@ suspend fun disassemble( if (kotlinc.exitCode != 0) { launch(ui) { onDex(kotlinc.output.replace(path.parent.toString() + "/", "")) - onStatusUpdate("Ready") + onStatusUpdate("Ready", Done) } return@launch } @@ -60,7 +68,8 @@ suspend fun disassemble( "Optimizing with R8…" } else { "Compiling with D8…" - }) + }, step++ / TotalSteps + ) } writeR8Rules(directory) @@ -73,12 +82,12 @@ suspend fun disassemble( if (r8.exitCode != 0) { launch(ui) { onDex(r8.output) - onStatusUpdate("Ready") + onStatusUpdate("Ready", Done) } return@launch } - launch(ui) { onStatusUpdate("Disassembling DEX…") } + launch(ui) { onStatusUpdate("Disassembling DEX…", step++ / TotalSteps) } val dexdump = process( toolPaths.dexdump.toString(), @@ -90,14 +99,14 @@ suspend fun disassemble( if (dexdump.exitCode != 0) { launch(ui) { onDex(dexdump.output) - onStatusUpdate("Ready") + onStatusUpdate("Ready", Done) } return@launch } launch(ui) { onDex(DexDumpParser(dexdump.output).parseDexDump()) - onStatusUpdate("AOT compilation…") + onStatusUpdate("AOT compilation…", step++ / TotalSteps) } val push = process( @@ -111,7 +120,7 @@ suspend fun disassemble( if (push.exitCode != 0) { launch(ui) { onOat(push.output) - onStatusUpdate("Ready") + onStatusUpdate("Ready", Done) } return@launch } @@ -128,12 +137,12 @@ suspend fun disassemble( if (dex2oat.exitCode != 0) { launch(ui) { onOat(dex2oat.output) - onStatusUpdate("Ready") + onStatusUpdate("Ready", Done) } return@launch } - launch(ui) { onStatusUpdate("Disassembling OAT…") } + launch(ui) { onStatusUpdate("Disassembling OAT…", step++ / TotalSteps) } val oatdump = process( toolPaths.adb.toString(), @@ -146,11 +155,11 @@ suspend fun disassemble( launch(ui) { onOat(filterOat(oatdump.output)) } if (oatdump.exitCode != 0) { - launch(ui) { onStatusUpdate("Ready") } + launch(ui) { onStatusUpdate("Ready", Done) } return@launch } - launch(ui) { onStatusUpdate("Ready") } + launch(ui) { onStatusUpdate("Ready", Done) } } } diff --git a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt index b115f938..2c341073 100644 --- a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt +++ b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt @@ -20,8 +20,10 @@ package dev.romainguy.kotlin.explorer import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.material3.LinearProgressIndicator import androidx.compose.runtime.* import androidx.compose.ui.Alignment +import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.awt.SwingPanel import androidx.compose.ui.graphics.Color @@ -55,7 +57,10 @@ import org.jetbrains.jewel.intui.window.decoratedWindow import org.jetbrains.jewel.intui.window.styling.dark import org.jetbrains.jewel.intui.window.styling.light import org.jetbrains.jewel.ui.ComponentStyling -import org.jetbrains.jewel.ui.component.* +import org.jetbrains.jewel.ui.component.DefaultButton +import org.jetbrains.jewel.ui.component.Icon +import org.jetbrains.jewel.ui.component.Text +import org.jetbrains.jewel.ui.component.TextField import org.jetbrains.jewel.window.DecoratedWindow import org.jetbrains.jewel.window.TitleBar import org.jetbrains.jewel.window.newFullscreenControls @@ -75,6 +80,7 @@ private fun FrameWindowScope.KotlinExplorer( // TODO: Move all those remembers to an internal private state object var activeTextArea by remember { mutableStateOf(null) } var status by remember { mutableStateOf("Ready") } + var progress by remember { mutableStateOf(1f) } val searchListener = remember { object : SearchListener { override fun searchEvent(e: SearchEvent?) { @@ -124,7 +130,11 @@ private fun FrameWindowScope.KotlinExplorer( val dexPanel: @Composable () -> Unit = { TextPanel("DEX", dexTextArea, explorerState) } val oatPanel: @Composable () -> Unit = { TextPanel("OAT", oatTextArea, explorerState) } var panels by remember { mutableStateOf(explorerState.getPanels(sourcePanel, dexPanel, oatPanel)) } - + val onProgressUpdate: (String, Float) -> Unit = { newStatus: String, newProgress: Float -> + status = newStatus + progress = newProgress + } + MainMenu( explorerState, sourceTextArea, @@ -136,7 +146,7 @@ private fun FrameWindowScope.KotlinExplorer( } }, { oat -> updateTextArea(oatTextArea, oat) }, - { statusUpdate -> status = statusUpdate }, + onProgressUpdate, { findDialog.isVisible = true }, { SearchEngine.find(activeTextArea, findDialog.searchContext) }, { showSettings = true }, @@ -153,14 +163,17 @@ private fun FrameWindowScope.KotlinExplorer( modifier = Modifier.background(JewelTheme.globalColors.paneBackground) ) { MultiSplitter(modifier = Modifier.weight(1.0f), panels) - Row { + Row(verticalAlignment = CenterVertically) { + val width = 160.dp Text( modifier = Modifier - .weight(1.0f, true) - .align(Alignment.CenterVertically) + .widthIn(min = width, max = width) .padding(8.dp), text = status ) + if (progress < 1) { + LinearProgressIndicator({ progress }) + } } } } @@ -252,7 +265,7 @@ private fun FrameWindowScope.MainMenu( sourceTextArea: RSyntaxTextArea, onDexUpdate: (String?) -> Unit, onOatUpdate: (String) -> Unit, - onStatusUpdate: (String) -> Unit, + onStatusUpdate: (String, Float) -> Unit, onFindClicked: () -> Unit, onFindNextClicked: () -> Unit, onOpenSettings: () -> Unit, @@ -352,7 +365,7 @@ private fun Settings( Row { Text( "Android home directory: ", - modifier = Modifier.align(Alignment.CenterVertically) + modifier = Modifier.align(CenterVertically) ) TextField( androidHome, @@ -371,7 +384,7 @@ private fun Settings( Row { Text( "Kotlin home directory: ", - modifier = Modifier.align(Alignment.CenterVertically) + modifier = Modifier.align(CenterVertically) ) TextField( kotlinHome,