Skip to content
This repository has been archived by the owner on Jun 25, 2024. It is now read-only.

✨ Native desktop picker on Windows and MacOS / Remove lwjgl library #123

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
17 changes: 14 additions & 3 deletions examples/jvm/src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,28 @@ fun main() = application {
}
}

FilePicker(showSingleFile, fileExtensions = listOf("jpg", "png")) { file ->
FilePicker(
showSingleFile,
fileExtensions = listOf("jpg", "png"),
title = "Choose a file",
) { file ->
pathSingleChosen = file?.file?.path ?: "none selected"
showSingleFile = false
}

MultipleFilePicker(showMultiFile, fileExtensions = listOf("jpg", "png")) { files ->
MultipleFilePicker(
showMultiFile,
fileExtensions = listOf("jpg", "png"),
title = "Choose files"
) { files ->
pathMultiChosen = files?.map { it.file.path + "\n" } ?: emptyList()
showMultiFile = false
}

DirectoryPicker(showDirPicker) { path ->
DirectoryPicker(
showDirPicker,
title = "Choose a directory"
) { path ->
dirChosen = path ?: "none selected"
showDirPicker = false
}
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
kotlin.code.style=official
kotlin.mpp.androidGradlePluginCompatibility.nowarn=true
android.useAndroidX=true
org.jetbrains.compose.experimental.jscanvas.enabled=true
org.jetbrains.compose.experimental.macos.enabled=true
Expand Down
6 changes: 4 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ agp = "8.3.0"
androidx-appcompat = "1.6.1"
androidx-core = "1.12.0"
compose-android = "1.8.2"
compose-plugin = "1.6.0"
compose-plugin = "1.6.1"
jna = "5.14.0"
junit = "4.13.2"
kotlin = "1.9.22"
kotlinx-coroutines = "1.8.0"
Expand All @@ -17,11 +18,12 @@ android-min-sdk = "21"
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
compose-activity = { module = "androidx.activity:activity-compose", version.ref = "compose-android" }
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
junit = { module = "junit:junit", version.ref = "junit" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }
kotlinx-html = { module = "org.jetbrains.kotlinx:kotlinx-html", version.ref = "kotlinx-html" }
junit = { module = "junit:junit", version.ref = "junit" }

[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
Expand Down
17 changes: 1 addition & 16 deletions mpfilepicker/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,7 @@ kotlin {
api(compose.preview)
api(compose.material)

val lwjglVersion = "3.3.1"
listOf("lwjgl", "lwjgl-tinyfd").forEach { lwjglDep ->
implementation("org.lwjgl:${lwjglDep}:${lwjglVersion}")
listOf(
"natives-windows",
"natives-windows-x86",
"natives-windows-arm64",
"natives-macos",
"natives-macos-arm64",
"natives-linux",
"natives-linux-arm64",
"natives-linux-arm32"
).forEach { native ->
runtimeOnly("org.lwjgl:${lwjglDep}:${lwjglVersion}:${native}")
}
}
implementation(libs.jna)
}
val jvmTest by getting
val jsMain by getting
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import java.io.File

public actual data class PlatformFile(
actual data class PlatformFile(
val file: File,
)

@Composable
public actual fun FilePicker(
actual fun FilePicker(
show: Boolean,
initialDirectory: String?,
fileExtensions: List<String>,
Expand All @@ -18,32 +18,25 @@ public actual fun FilePicker(
) {
LaunchedEffect(show) {
if (show) {
val fileFilter = if (fileExtensions.isNotEmpty()) {
fileExtensions.joinToString(",")
} else {
""
}

val initialDir = initialDirectory ?: System.getProperty("user.dir")
val filePath = chooseFile(
initialDirectory = initialDir,
fileExtension = fileFilter,
title = title
// Get path from native file picker
val filePicker = PlatformFilePickerUtil.current
val filePath = filePicker.pickFile(
initialDirectory = initialDirectory,
fileExtensions = fileExtensions,
title = title,
)
if (filePath != null) {
val file = File(filePath)
val platformFile = PlatformFile(file)
onFileSelected(platformFile)
} else {
onFileSelected(null)
}

// Convert path to PlatformFile
val result = filePath?.let { PlatformFile(File(it)) }

// Return result
onFileSelected(result)
}
}
}

@Composable
public actual fun MultipleFilePicker(
actual fun MultipleFilePicker(
show: Boolean,
initialDirectory: String?,
fileExtensions: List<String>,
Expand All @@ -52,40 +45,41 @@ public actual fun MultipleFilePicker(
) {
LaunchedEffect(show) {
if (show) {
val fileFilter = if (fileExtensions.isNotEmpty()) {
fileExtensions.joinToString(",")
} else {
""
}

val initialDir = initialDirectory ?: System.getProperty("user.dir")
val filePaths = chooseFiles(
initialDirectory = initialDir,
fileExtension = fileFilter,
title = title
// Get paths from native file picker
val filePicker = PlatformFilePickerUtil.current
val filePaths = filePicker.pickFiles(
initialDirectory = initialDirectory,
fileExtensions = fileExtensions,
title = title,
)
if (filePaths != null) {
onFileSelected(filePaths.map { PlatformFile(File(it)) })
} else {
onFileSelected(null)
}

// Convert paths to PlatformFile
val result = filePaths?.map { PlatformFile(File(it)) }

// Return result
onFileSelected(result)
}
}
}

@Composable
public actual fun DirectoryPicker(
actual fun DirectoryPicker(
show: Boolean,
initialDirectory: String?,
title: String?,
onFileSelected: (String?) -> Unit,
) {
LaunchedEffect(show) {
if (show) {
val initialDir = initialDirectory ?: System.getProperty("user.dir")
val fileChosen = chooseDirectory(initialDir, title)
onFileSelected(fileChosen)
// Get path from native file picker
val filePicker = PlatformFilePickerUtil.current
val filePath = filePicker.pickDirectory(
initialDirectory = initialDirectory,
title = title,
)

// Return result
onFileSelected(filePath)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.darkrockstudios.libraries.mpfilepicker

import com.darkrockstudios.libraries.mpfilepicker.mac.MacOSFilePicker
import com.darkrockstudios.libraries.mpfilepicker.util.Platform
import com.darkrockstudios.libraries.mpfilepicker.util.PlatformUtil
import com.darkrockstudios.libraries.mpfilepicker.windows.WindowsFilePicker

internal interface PlatformFilePicker {
fun pickFile(
initialDirectory: String? = null,
fileExtensions: List<String>? = null,
title: String? = null,
): String?

fun pickFiles(
initialDirectory: String? = null,
fileExtensions: List<String>? = null,
title: String? = null,
): List<String>?

fun pickDirectory(
initialDirectory: String? = null,
title: String? = null,
): String?
}

internal object PlatformFilePickerUtil {
val current: PlatformFilePicker by lazy { createPlatformFilePicker() }

private fun createPlatformFilePicker(): PlatformFilePicker {
return when (PlatformUtil.current) {
Platform.MacOS -> MacOSFilePicker()
Platform.Windows -> WindowsFilePicker()
Platform.Linux -> WindowsFilePicker() // TODO: WindowsFilePicker is compatible with other platforms but we need to implement native Linux file picker
}
}
}
Loading