Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use native directory pickers on Mac and Windows #26

Merged
merged 2 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gradle-client/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ kotlin {

implementation(libs.material3WindowSizeClassMultiplatform)
implementation(libs.materialKolor)
implementation(libs.filekit.compose)

implementation(libs.slf4j.api)
implementation(libs.logback.classic)
Expand Down
7 changes: 6 additions & 1 deletion gradle-client/proguard-desktop.pro
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
-dontwarn org.openjsse.**

# Kotlin embedded compiler dependencies
-dontwarn com.sun.jna.**
-dontwarn kotlin.annotations.jvm.**
-dontwarn org.jetbrains.kotlin.com.google.common.**
-dontwarn org.jetbrains.kotlin.com.google.gson.**
Expand Down Expand Up @@ -86,3 +85,9 @@

# Kotlin embedded compiler
-keep class org.jetbrains.kotlin.** { *; }

# JNA classes
-keep class com.sun.jna.** { *; }
-keepclassmembers class * extends com.sun.jna.** { public *; }
-keep class * implements com.sun.jna.** { *; }
-dontnote com.sun.**
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ enum class DesktopOS(val id: String) {
Linux("linux"),
Mac("macos"),
Windows("windows");

val isLinux: Boolean get() = this == Linux
}

val currentDesktopOS: DesktopOS by lazy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import io.github.vinceglb.filekit.compose.rememberDirectoryPickerLauncher
import kotlinx.coroutines.launch
import org.gradle.client.core.database.Build
import org.gradle.client.core.gradle.GradleConnectionParameters
Expand All @@ -21,6 +22,7 @@ import org.gradle.client.core.gradle.GradleConnectionParameters.Companion.isVali
import org.gradle.client.core.gradle.GradleConnectionParameters.Companion.isValidGradleVersion
import org.gradle.client.core.gradle.GradleConnectionParameters.Companion.isValidJavaHome
import org.gradle.client.core.gradle.GradleDistribution
import org.gradle.client.core.util.currentDesktopOS
import org.gradle.client.ui.composables.*
import org.gradle.client.ui.theme.plusPaneSpacing
import org.gradle.client.ui.theme.spacing
Expand Down Expand Up @@ -287,37 +289,82 @@ private fun DirectoryField(
},
trailingIcon = {
val helpText = "Select a $description"
var isDirChooserOpen by remember { mutableStateOf(false) }
if (isDirChooserOpen) {
DirChooserDialog(
helpText = helpText,
showHiddenFiles = showHiddenFiles,
onDirChosen = { dir ->
isDirChooserOpen = false
if (dir == null) {
showSnackbar("No $description selected")
} else {
state.value = dir.absolutePath
}
}
)
}
Row {
IconButton(
enabled = state.value.isNotBlank(),
onClick = { state.value = "" },
content = { Icon(Icons.Default.Clear, "Clear") }
)
PlainTextTooltip(helpText) {
IconButton(onClick = { isDirChooserOpen = true }) {
Icon(Icons.Default.Folder, helpText)
}
}
if (currentDesktopOS.isLinux) {
LinuxDirectoryFieldPicker(description, helpText, state, showHiddenFiles, showSnackbar)
} else {
NonLinuxDirectoryFieldPicker(description, helpText, state, showSnackbar)
}
},
)
}

@Composable
private fun LinuxDirectoryFieldPicker(
description: String,
helpText: String,
state: MutableState<String>,
showHiddenFiles: Boolean = false,
showSnackbar: (message: String) -> Unit,
) {
var isDirChooserOpen by remember { mutableStateOf(false) }
if (isDirChooserOpen) {
DirChooserDialog(
helpText = helpText,
showHiddenFiles = showHiddenFiles,
onDirChosen = { dir ->
isDirChooserOpen = false
if (dir == null) {
showSnackbar("No $description selected")
} else {
state.value = dir.absolutePath
}
}
)
}
DirectoryFilePickerIcon(helpText, state) {
isDirChooserOpen = true
}
}

@Composable
private fun NonLinuxDirectoryFieldPicker(
description: String,
helpText: String,
state: MutableState<String>,
showSnackbar: (message: String) -> Unit,
) {
val dirPickerLauncher = rememberDirectoryPickerLauncher(helpText) { dir ->
if (dir == null) {
showSnackbar("No $description selected")
} else {
state.value = dir.file.absolutePath
}
}
DirectoryFilePickerIcon(helpText, state) {
dirPickerLauncher.launch()
}
}

@Composable
private fun DirectoryFilePickerIcon(
helpText: String,
state: MutableState<String>,
onClick: () -> Unit
) {
Row {
IconButton(
enabled = state.value.isNotBlank(),
onClick = { state.value = "" },
content = { Icon(Icons.Default.Clear, "Clear") }
)
PlainTextTooltip(helpText) {
IconButton(onClick = onClick) {
Icon(Icons.Default.Folder, helpText)
}
}
}
}

@Composable
@Suppress("LongParameterList")
fun BuildTextField(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import io.github.vinceglb.filekit.compose.rememberDirectoryPickerLauncher
import io.github.vinceglb.filekit.core.FileKitPlatformSettings
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.gradle.client.core.Constants.APPLICATION_DISPLAY_NAME
import org.gradle.client.core.database.Build
import org.gradle.client.core.util.currentDesktopOS
import org.gradle.client.ui.composables.*
import org.gradle.client.ui.theme.plusPaneSpacing
import java.io.File

@Composable
fun BuildListContent(component: BuildListComponent) {
Expand Down Expand Up @@ -78,33 +83,65 @@ private fun BuildListDeleteButon(component: BuildListComponent, build: Build) {

@Composable
private fun AddBuildButton(component: BuildListComponent, snackbarState: SnackbarHostState) {
if (currentDesktopOS.isLinux) {
LinuxAddBuildButton(component, snackbarState)
} else {
NonLinuxAddBuildButton(component, snackbarState)
}
}

@Composable
private fun NonLinuxAddBuildButton(component: BuildListComponent, snackbarState: SnackbarHostState) {
val scope = rememberCoroutineScope()
val dirPickerLauncher = rememberDirectoryPickerLauncher(ADD_BUILD_HELP_TEXT) { rootDir ->
onBuildDirSelected(scope, component, snackbarState, rootDir?.file)
}
AddBuildDirFAB { dirPickerLauncher.launch() }
}

@Composable
private fun LinuxAddBuildButton(component: BuildListComponent, snackbarState: SnackbarHostState) {
val scope = rememberCoroutineScope()
var isDirChooserOpen by remember { mutableStateOf(false) }
if (isDirChooserOpen) {
DirChooserDialog(
helpText = ADD_BUILD_HELP_TEXT,
onDirChosen = { rootDir ->
isDirChooserOpen = false
if (rootDir == null) {
scope.launch { snackbarState.showSnackbar("No build selected") }
} else {
val valid = rootDir.listFiles { file ->
file.name.startsWith("settings.gradle")
}?.isNotEmpty() ?: false
if (!valid) {
scope.launch { snackbarState.showSnackbar("Directory is not a Gradle build!") }
} else {
component.onNewBuildRootDirChosen(rootDir)
}
}
onBuildDirSelected(scope, component, snackbarState, rootDir)
}
)
}
AddBuildDirFAB { isDirChooserOpen = true }
}

private fun onBuildDirSelected(
scope: CoroutineScope,
component: BuildListComponent,
snackbarState: SnackbarHostState,
rootDir: File?
) {
if (rootDir == null) {
scope.launch { snackbarState.showSnackbar("No build selected") }
} else {
val valid = rootDir.listFiles { file ->
file.name.startsWith("settings.gradle")
}?.isNotEmpty() ?: false
if (!valid) {
scope.launch { snackbarState.showSnackbar("Directory is not a Gradle build!") }
} else {
component.onNewBuildRootDirChosen(rootDir)
}
}
}

@Composable
private fun AddBuildDirFAB(onClick: () -> Unit) {
PlainTextTooltip(ADD_BUILD_HELP_TEXT) {
ExtendedFloatingActionButton(
icon = { Icon(Icons.Default.Add, "") },
text = { Text(text = "Add build", Modifier.testTag("add_build")) },
onClick = { isDirChooserOpen = true },
onClick = onClick,
)
}
}
Expand Down
21 changes: 11 additions & 10 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[versions]
kotlin = "1.9.23"
kotlinx-coroutines = "1.7.3"
kotlinx-serialization = "1.6.2"
compose-plugin = "1.6.1"
decompose = "3.0.0-alpha07"
kotlinx-coroutines = "1.8.1"
kotlinx-serialization = "1.6.3"
compose-plugin = "1.6.11"
decompose = "3.0.0"
gradle-tooling = "8.10-20240723003427+0000"
declarative-dsl = "8.10-20240723003427+0000"
sqldelight = "2.0.1"
ktor = "2.3.9"
sqldelight = "2.0.2"
ktor = "2.3.12"

[libraries]
kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
Expand All @@ -28,10 +28,11 @@ gradle-tooling-api = { module = "org.gradle:gradle-tooling-api", version.ref = "
gradle-declarative-dsl-core = { module = "org.gradle:gradle-declarative-dsl-core", version.ref = "declarative-dsl" }
gradle-declarative-dsl-evaluator = { module = "org.gradle:gradle-declarative-dsl-evaluator", version.ref = "declarative-dsl" }
gradle-declarative-dsl-tooling-models = { module = "org.gradle:gradle-declarative-dsl-tooling-models", version.ref = "declarative-dsl" }
material3WindowSizeClassMultiplatform = { module = "dev.chrisbanes.material3:material3-window-size-class-multiplatform", version = "0.3.1" }
materialKolor = { module = "com.materialkolor:material-kolor", version = "1.4.4" }
slf4j-api = { module = "org.slf4j:slf4j-api", version = "2.0.12" }
logback-classic = { module = "ch.qos.logback:logback-classic", version = "1.5.3" }
material3WindowSizeClassMultiplatform = { module = "dev.chrisbanes.material3:material3-window-size-class-multiplatform", version = "0.5.0" }
materialKolor = { module = "com.materialkolor:material-kolor", version = "1.7.0" }
filekit-compose = { module = "io.github.vinceglb:filekit-compose", version = "0.7.0" }
slf4j-api = { module = "org.slf4j:slf4j-api", version = "2.0.14" }
logback-classic = { module = "ch.qos.logback:logback-classic", version = "1.5.6" }
junit-junit = { module = "junit:junit", version = "4.13.2" }

[plugins]
Expand Down