wavesonics / compose-multiplatform-file-picker Goto Github PK
View Code? Open in Web Editor NEWA multiplatform compose widget for picking files
License: MIT License
A multiplatform compose widget for picking files
License: MIT License
Just as the title says and a TODO here
would be great to get this platform implemented
Hello, faced such an issue while trying to implement your lib into my project
in common target I get such a Gradle error, but in android target everything works perfectly fine
Could not resolve com.darkrockstudios:mpfilepicker:2.1.0.
Required by:
project :composeApp > project :features:comments:ui
> No matching variant of com.darkrockstudios:mpfilepicker:2.1.0 was found. The consumer was configured to find a library for use during 'kotlin-api', preferably optimized for non-jvm, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native', attribute 'org.jetbrains.kotlin.native.target' with value 'ios_arm64' but:
- Variant 'jsApiElements-published' capability com.darkrockstudios:mpfilepicker:2.1.0 declares a library for use during 'kotlin-api':
- Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'js' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attributes:
- Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
- Variant 'jsRuntimeElements-published' capability com.darkrockstudios:mpfilepicker:2.1.0 declares a library:
- Incompatible because this component declares a component for use during 'kotlin-runtime', as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'js' and the consumer needed a component for use during 'kotlin-api', as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
- Other compatible attributes:
- Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
- Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
At least on Windows it's possible to filter for multiple file extensions. Would be nice if fileExtension
was a list instead of a string to reflect that 😁
At first it complains about JVM versions
Execution failed for task ':examples:jvm:compileKotlinJvm'.
> 'compileJava' task (current target is 17) and 'compileKotlinJvm' task (current target is 11) jvm target compatibility should be set to the same Java version.
Consider using JVM toolchain: https://kotl.in/gradle/jvm/toolchain
I have tried to change kotlinOptions.jvmTarget = "11"
to 17
, then I get another error, which I cant fix
Caused by: org.jetbrains.skiko.LibraryLoadException: Cannot find libskiko-macos-x64.dylib.sha256, proper native dependency missing.
I think version catalogs are much cleaner way to keep versions. For example here is a catalog from my app
[versions]
minSdk = "24"
targetSdk = "33"
compileSdk = "33"
versionCode = "9"
versionName = "1.3.1"
composeCompiler = "1.2.0"
[libraries]
kiwi-icons = "kiwi.orbit.compose:icons:0.24.0"
kiwi-ui = "kiwi.orbit.compose:ui:0.24.0"
kiwi-illustrations = "kiwi.orbit.compose:illustrations:0.24.0"
androidx-compose-navigation-hilt = "androidx.hilt:hilt-navigation-compose:1.0.0"
androidx-compose-foundation = "androidx.compose.foundation:foundation:1.3.1"
androidx-compose-viewmodel-lifecycle = "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1"
androidx-compose-ui = "androidx.compose.ui:ui:1.3.3"
androidx-compose-material = "androidx.compose.material:material:1.3.1"
androidx-compose-material-icons-extended = "androidx.compose.material:material-icons-extended:1.3.1"
androidx-compose-constraintlayout = "androidx.constraintlayout:constraintlayout-compose:1.0.1"
androidx-tooling = "androidx.compose.ui:ui-tooling:1.3.3"
androidx-tooling-preview = "androidx.compose.ui:ui-tooling-preview:1.3.3"
raamcosta-destinations = 'io.github.raamcosta.compose-destinations:core:1.4.4-beta'
raamcosta-destinations-animations = 'io.github.raamcosta.compose-destinations:animations-core:1.4.4-beta'
raamcosta-destinations-ksp = 'io.github.raamcosta.compose-destinations:ksp:1.4.4-beta'
[bundles]
kiwi = [
"kiwi-icons",
"kiwi-ui",
"kiwi-illustrations"
]
androidx = [
"androidx-lifecycle",
"androidx-compose-activity",
"androidx-datastore-preferences",
"androidx-datastore-core",
"androidx-datastore",
"androidx-core",
"androidx-appcompat",
"androidx-room-runtime",
"androidx-room-ktx",
]
version: v2.0.2
operating system: macOS Monterey v12.6.1
JDK: IBM OpenJ9, version: 17.0.8
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.darkrockstudios.libraries.mpfilepicker.FilePicker
fun main() = application {
var show1 by remember { mutableStateOf(false) }
var show2 by remember { mutableStateOf(false) }
var pathChosen1 by remember { mutableStateOf("") }
var pathChosen2 by remember { mutableStateOf("") }
Window(onCloseRequest = ::exitApplication) {
Column {
Button(onClick = {
show1 = true
}) {
Text("Choose File 1")
}
Text("File Chosen 1: $pathChosen1")
/////////////////////////////////////////////////////////////////
Button(onClick = {
show2 = true
}) {
Text("Choose File 2")
}
Text("File Chosen 2: $pathChosen2")
}
// if set one json file extension, cannot choose json files
FilePicker(show1, fileExtensions = listOf("json")) { file ->
pathChosen1 = file?.path ?: "none selected"
show1 = false
}
// if set multiple file extensions, can choose json files
FilePicker(show2, fileExtensions = listOf("json", "txt")) { file ->
pathChosen2 = file?.path ?: "none selected"
show2 = false
}
}
}
I'm making a windows application that works with excel files. I added an option to add files: both drag and drop, and use file picker (by clicking on DnD box). I found out that FilePicker does not work properly with .onExternalDrag modifier: the application totally freezes after you try to drag any element out of File chooser dialog. That happens only if at least once any element with .onExternalDrag modifier is used.
Upd: I mean it's happens even if you change screen. And even if on this screen are no elements with that modifier.
At this point the application just does not respond and there are no ways to do something to it. If I comment an .onExternalDrag and try to launch application, everything works just fine:
I have this modifier only in one element. It's code:
@OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class)
@Composable
fun DragAndDropFileBox(navigator: Navigator, modifier: Modifier = Modifier) {
var isDragging by remember { mutableStateOf(false) }
val dragNDropColor = if (isDragging) Colors.active else Colors.default
var localPath by remember { mutableStateOf("") }
Box(
modifier = modifier
.border(border = BorderStroke(5.dp, Color.Magenta), shape = RectangleShape)
.onExternalDrag(
onDragStart = { isDragging = true },
onDragExit = { },
onDrop = { value ->
isDragging = false
val dragData = value.dragData
if (dragData is DragData.FilesList) {
val draggedList = DragDataList(dragData)
localPath = draggedList.receiveFilePath()
isDragging = false
navigator.replaceAll(MainScreen(localPath))
}
})
.onClick {
navigator.replace(FilePickerScreen())
}
) {
Column(modifier = Modifier.align(Alignment.Center)) {
DragAndDropDescription(
modifier = Modifier.align(Alignment.CenterHorizontally),
color = dragNDropColor
)
}
}
}
Java awt file picker does not have this problem, but I don't really won't use it (mostly because of it's appearance and not really native look).
P.S.
I'm not a native speaker, so my apologies if I spoke out not totally clear.
There are multiple places where version needs to be updated
I think it would look cleaner to have examples in one fodler called "examples"
When I debug my project in Windows, if found that the type of plaformFile is always the File of java.io. So I wonder if it is necessary to make it generic? Is it possible to have another type of file?
Thankyou
Can we configure which file picker to use on Windows?
We now have the smaller variant, but there is also a bigger one including a sidebar. I would prefer to use that one.
Debug mode: the file picker is the native (Explorer.exe)
Release mode: the file picker is non-native (swing)
Tested on only one machine:
OS: windows 10
Koltin: 1.8.10
Compose: 1.4.1
I like to have a title on macOS & Windows for the bar that says something like "Choose a directory that contains your photos" instead of "Choose folder". Please provide a way to specify this. It's a property that could be ignored for platforms where this is not applicable.
When opening a file chooser sudden crash
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSWindow drag regions should only be invalidated on the Main Thread!'
https://github.com/koolfreak/vpos/blob/main/src/jvmMain/kotlin/ui/settings/SettingsView.kt
osx 12.6.2, java 17.0.4.1
Given that there is already a JavaScript target, I was curious about the possibility of incorporating the WASM and WASI targets, which have recently been promoted to alpha. While it's not a requirement for me, it's just an idea I wanted to explore.
It would be nice if the window's title could be customized (e.g. from "Open File" on Linux / KDE) to any custom text (like "Open Image").
I get the following error when trying to run my app:
Exception in thread "main" java.lang.UnsatisfiedLinkError: 'void org.jetbrains.skia.CanvasKt._nTranslate(long, float, float)'
at org.jetbrains.skia.CanvasKt._nTranslate(Native Method)
at org.jetbrains.skia.CanvasKt.access$_nTranslate(Canvas.kt:1)
at org.jetbrains.skia.Canvas.translate(Canvas.kt:1091)
at androidx.compose.ui.graphics.SkiaBackedCanvas.translate(SkiaBackedCanvas.skiko.kt:84)
at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:357)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:922)
at androidx.compose.ui.platform.SkiaBasedOwner.draw(SkiaBasedOwner.skiko.kt:352)
at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:463)
at androidx.compose.ui.awt.ComposeBridge$skikoView$1$onRender$1.invoke(ComposeBridge.desktop.kt:153)
at androidx.compose.ui.awt.ComposeBridge$skikoView$1$onRender$1.invoke(ComposeBridge.desktop.kt:152)
at androidx.compose.ui.awt.ComposeBridge.catchExceptions(ComposeBridge.desktop.kt:126)
at androidx.compose.ui.awt.ComposeBridge.access$catchExceptions(ComposeBridge.desktop.kt:59)
at androidx.compose.ui.awt.ComposeBridge$skikoView$1.onRender(ComposeBridge.desktop.kt:152)
at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer.redrawImmediately(Direct3DRedrawer.kt:73)
at org.jetbrains.skiko.SkiaLayer.paint(SkiaLayer.awt.kt:388)
at androidx.compose.ui.awt.WindowComposeBridge$component$1.paint(WindowComposeBridge.desktop.kt:59)
at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:961)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1137)
at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:961)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1137)
at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:430)
at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:416)
at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:82)
at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:80)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:59)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:55)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2300)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:471)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:234)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke$performUpdate(UpdateEffect.desktop.kt:55)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:64)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:47)
at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:81)
at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:1137)
at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:828)
at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:849)
at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1041)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:520)
at androidx.compose.ui.window.Application_desktopKt$awaitApplication$2$1$2.invokeSuspend(Application.desktop.kt:219)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
My dependencies:
implementation(compose.desktop.currentOs)
implementation("org.xerial:sqlite-jdbc:3.42.0.0")
implementation(compose.material3)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.6.0")
implementation("com.darkrockstudios:mpfilepicker:2.1.0")
Also, something strange happened with the compose library when I installed this library. In ModifierNodeElement
class, the function abstract fun update
is changed from abstract fun update(node: N): N
to abstract fun update(node: N)
.
Would it be possible, at least in desktop, that when the file picker opens it's as a modal dialog, so you cannot interact with the original app window?
While maybe not strictly a "picker" anymore, it would be nice to also have a dialog for saving files.
Hi using the latest version of the multiple file picker (3.1.0) using the following snippet of code:
MultipleFilePicker(
show = //showFilePicker,
fileExtensions = //file extensions
) { assets ->
if(!assets.isNullOrEmpty()) {
val assetsPath = mutableListOf<File>()
assets.forEach { asset ->
assetsPath.add(File(asset.path))
}
if(assetsPath.isNotEmpty()) {
// do code
}
}
}
will be thrown the following exception:
Caused by: java.io.FileNotFoundException: /document/msf:59701: open failed: ENOENT (No such file or directory)
.
There is a way to get directly the file from the Android's storage? Because using the asset.path
it looks like does not get the complete path to get the file
When I ook at the FileChooser class it gives me flashbacks from Java. Also having a fallback chooseFileSwing
looks extra
Here are my ideas
FileChooser
class, because it has no state and is not injected anywhere.chooseFileNative
fails and users see non-native dialog they may think that this library does not show native dialogs (yes, there is a println for this error, but still) and may switch to another library.I think after all this, code will be twice as cleaner. Let me know if you agree and will send PR
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are currently rate-limited. Click on a checkbox below to force their creation now.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
org.jetbrains.kotlinx:kotlinx-coroutines-swing
, org.jetbrains.kotlinx:kotlinx-coroutines-android
, org.jetbrains.kotlinx:kotlinx-coroutines-core
)com.android.library
, com.android.application
).github/workflows/publish.yml
actions/checkout v4
actions/setup-java v4
gradle/wrapper-validation-action v2.1.1
gradle/gradle-build-action v3.1.0
.github/workflows/run-checks.yml
actions/checkout v4
gradle/wrapper-validation-action v2
actions/setup-java v4
gradle/actions v3
actions/checkout v4
gradle/wrapper-validation-action v2
actions/setup-java v4
gradle/actions v3
gradle.properties
settings.gradle.kts
build.gradle.kts
gradle/libs.versions.toml
androidx.appcompat:appcompat 1.6.1
androidx.core:core-ktx 1.12.0
androidx.activity:activity-compose 1.8.2
org.jetbrains.kotlinx:kotlinx-coroutines-core 1.8.0
org.jetbrains.kotlinx:kotlinx-coroutines-android 1.8.0
org.jetbrains.kotlinx:kotlinx-coroutines-swing 1.8.0
org.jetbrains.kotlinx:kotlinx-html 0.11.0
junit:junit 4.13.2
com.android.application 8.3.0
com.android.library 8.3.0
org.jetbrains.compose 1.6.1
org.jetbrains.kotlin.multiplatform 1.9.22
mpfilepicker/build.gradle.kts
gradle/wrapper/gradle-wrapper.properties
gradle 8.6
Looks like our publish task is failing now with the JS target:
A problem was found with the configuration of task ':mpfilepicker:publishAndroidReleasePublicationToMavenRepository' (type 'PublishToMavenRepository').
- Gradle detected a problem with the following location: '/home/runner/work/compose-multiplatform-file-picker/compose-multiplatform-file-picker/mpfilepicker/build/libs/mpfilepicker-2.0.0-javadoc.jar.asc'.
Reason: Task ':mpfilepicker:publishAndroidReleasePublicationToMavenRepository' uses this output of task ':mpfilepicker:signJsPublication' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed.
Possible solutions:
1. Declare task ':mpfilepicker:signJsPublication' as an input of ':mpfilepicker:publishAndroidReleasePublicationToMavenRepository'.
2. Declare an explicit dependency on ':mpfilepicker:signJsPublication' from ':mpfilepicker:publishAndroidReleasePublicationToMavenRepository' using Task#dependsOn.
3. Declare an explicit dependency on ':mpfilepicker:signJsPublication' from ':mpfilepicker:publishAndroidReleasePublicationToMavenRepository' using Task#mustRunAfter.
Hi, just found this lib and it'll be of great use for my multiplatform app i'm developing. One problem I've found is that the library has its minSdk set to 24, and my app is minSdk 21. I inspected the code and there doesn't appear to be anything preventing it from being dropped down. Perhaps I overlooked something but otherwise I'm certain the minSdk can be lowered to 21. Compose min sdk is also 21.
According to default style guide of Kotlin, it should be written with spaces.
For example, tabs are a bit inconsistent, if I copy a line with tabs and paste it somewhere else, it looks like this
println("A call to chooseDirectorySwing failed ${swingException.message}")
and in spaces its like this
println("A call to chooseDirectorySwing failed ${swingException.message}")
and in Intellij it looks like this (with a bit of custom settings)
And in Vim or Emacs it will also be different.
So, lets follow default style guide and switch to spaces
Thanks for the repo!
I need 2 more targets currently, will you consider a PR?
I think it will be cool to have it https://kotlinlang.org/docs/whatsnew14.html#explicit-api-mode-for-library-authors
I have code that's working fine in other Compose clients but on Android I'm getting following when calling getFileByteArray
01-14 19:37:45.657 22788 22788 E AndroidRuntime: java.lang.IllegalArgumentException: Uri lacks 'file' scheme: content://com.android.providers.media.documents/document/image%3A1000050843
01-14 19:37:45.657 22788 22788 E AndroidRuntime: at androidx.core.net.UriKt.toFile(Uri.kt:43)
01-14 19:37:45.657 22788 22788 E AndroidRuntime: at com.darkrockstudios.libraries.mpfilepicker.AndroidFile.getFileByteArray(AndroidFilePicker.kt:15)
following is code I have
val coroutineScope = rememberCoroutineScope()
val fileExtensions = listOf("jpg", "png")
FilePicker(show = show, fileExtensions = fileExtensions) { file ->
coroutineScope.launch {
val data = file?.getFileByteArray()
data?.let {
....
}
}
}
Thanks for iOS supported add.
But we can't select from iPhone Photos.
It is confusing. There is line in gradle file jvm("desktop")
and the sourceSet is called desktopMain
. I think if it had its original name then it would be more intuitive
This will make it easier to update libs. More info here https://www.mend.io/renovate/ and the example is here: Nodrex/Testomania#348
It would be great if we support to capture image from Camera in All platforms
Copied from README
platforms:windows
Describe the bug
Prior to 1.2.0, if no file extension is set, any file can be selected.
After 1.2.0, if no file extension is set, no file can be selected.
After signing with a certificate, a view for selecting files pops up, but there is no response when clicking the target.
To run in the distributable version you need to add modules("jdk.unsupported")
.
This should be documented.
Hello!
I'm trying to use this library for iOS and Android KMP app, but it seems like the new version was not published to Maven.
Maven central says that the latest version is 2.1.0
https://central.sonatype.com/search?q=com.darkrockstudios
It would be nice to have the new version published :)
I have a very specific problem and may be related to #30? I'm unfortunately not very knowledgeable about how the JVM interacts with native system calls, so this is a little out of my league.
My application requires LWJGL to operate. I have a Compose application that launches a jMonkeyEngine application—this is dependent on LWJGL. When LWJGL2 is on the classpath, attempts to open the file picker open an old, legacy file chooser:
This is also printed to the console: A call to chooseDirectoryNative failed: 'org.lwjgl.system.CustomBuffer org.lwjgl.PointerBuffer.rewind()'
If I instead package LWJGL3, the true, native picker is opened:
However, the JVM will sometimes crash when selecting a file. (Seemingly randomly, it happens maybe half the time?) When it crashes the JVM does a memory dump, so I've attached that here.
I package LWJGL by adding either of these dependencies to my Gradle build script: implementation("org.jmonkeyengine:jme3-lwjgl:3.5.2-stable")
or implementation("org.jmonkeyengine:jme3-lwjgl3:3.5.2-stable")
.
Therefore, I expect the file picker to load the native file picker (as seen in the second screenshot) without crashing. But—depending on the LWJGL version on the classpath—it either loads a legacy file picker, or randomly crashes.
If there's any other information I can provide, let me know.
Showing the FilePicker
component seems to cause heap corruption and cause the entire Compose application to crash at random times with error code 0xC0000374
(ERROR_HEAP_CORRUPTION
) on a Windows machine. Given that it seems that Windows itself is killing the process, no JVM error log nor any mini dumps are produced, and the code that is being executed when the application is terminated seems to be random, unrelated to the file picker library itself. Nevertheless, preventing the file picker from showing up consistently solves the issue.
I have managed to replicate the issue somewhat consistently by trying to load Bitmap images through AWT immediately after the file picker is closed: a minimal reproducible test-case is attached below. It does seem that the size of the image does not matter, although the bigger the image is the more likely an error occurs immediately. I have been testing with this Bitmap and it seems to trigger the error immediately around 90% of the time.
private class C {
var p by mutableStateOf(false)
var i by mutableStateOf(false)
}
fun main() {
application {
val state = remember { C() }
Window(onCloseRequest = ::exitApplication) {
if (state.i) { Image(ImageIO.read(Path("./bridge.bmp").inputStream()).toComposeImageBitmap(), null) }
Button(onClick = {
state.p = true
state.i = false
}) { Text("Click Me") }
}
FilePicker(show = state.p) {
state.p = false
state.i = true
}
}
}
The described behavior can be triggered by clicking on the button and then either choosing a file or canceling the file picking action. Setting state.i
to true
by default shows that the image is usually loaded without problems if the file picker is not involved.
These tests have been performed with version 1.2.0 of this library along with Compose 1.2.0 with Kotlin 1.8.21 (requires manually specifying version 1.4.7 of the Compose compiler in the project settings) on Java 17.
this happens at runtime on macOS apple silicon, just by adding the dependency
Exception in thread "main" java.lang.UnsatisfiedLinkError: 'long org.jetbrains.skiko.MetalApiKt.openAutoreleasepool()'
at org.jetbrains.skiko.MetalApiKt.openAutoreleasepool(Native Method)
at org.jetbrains.skiko.MetalApiKt.access$openAutoreleasepool(MetalApi.kt:1)
at org.jetbrains.skiko.redrawer.MetalRedrawer.performDraw(MetalRedrawer.kt:251)
at org.jetbrains.skiko.redrawer.MetalRedrawer.redrawImmediately(MetalRedrawer.kt:117)
at org.jetbrains.skiko.SkiaLayer.paint(SkiaLayer.awt.kt:388)
at androidx.compose.ui.awt.WindowComposeBridge$component$1.paint(WindowComposeBridge.desktop.kt:59)
at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:952)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1128)
at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:952)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1128)
at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:430)
at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:416)
at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:82)
at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:80)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:59)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:55)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2300)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:471)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:234)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke$performUpdate(UpdateEffect.desktop.kt:55)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:64)
at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:47)
at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:81)
at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:1137)
at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:828)
at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:849)
at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1041)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:520)
at androidx.compose.ui.window.Application_desktopKt$awaitApplication$2$1$2.invokeSuspend(Application.desktop.kt:219)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
This could be added to .editroconf
100 because I have a Mac with small screen :D
I'm using folder picker and it works properly in desktop but in Android, i have some troubles.
When user clicks on a fab, i will show the folder picker dialog, and user choose the target folder, the path returned to my app is something like this:
content://com.android.externalstorage.documents/tree/primary%3ADownload/MyApp
After that i'm checking is that folder exists or not:
val file = File(path)
val isExists = file.exists()
In desktop it returns true
but in Android it always returns false
.
Add support for ARM macs on top of intel macs
In a way it feels extra to have those functions as composable. Since it is multiplatform, one might not want compose, maybe they have React and now they will need to be using compose too. Or maybe in future if we have a native library that is compiled to native, then it might be called not from Kotlin, but from many different languages....
Similar thing happened here #17, i had to add a separate module, bucause then I get error :mpfilepicker:mingwX64Main: Could not resolve org.jetbrains.compose.foundation:foundation:1.3.0.
There could be 2 kinds of library maybe, one without compose and one with compose? something like implementation("com.darkrockstudios:mpfilepicker:1.1.0")
and implementation("com.darkrockstudios:mpfilepicker-compose:1.1.0")
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.