-
Notifications
You must be signed in to change notification settings - Fork 39
Add ability to monitor file picker import progress #300
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
Conversation
9e45fde
to
aa86b77
Compare
Hi @kihaki! That's a really good idea! I'm going to try that 🔥 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: State Update Errors and Duplicate File Handling
The _uiState.update
calls incorrectly use the copy()
method without named parameters (e.g., files = ...
), which may cause a compilation error or update the wrong field. Additionally, FileKitPickerState.Progress
and FileKitPickerState.Completed
likely provide cumulative lists (result.processed
, result.result
), leading to duplicate files being added to the _uiState.files
list.
samples/sample-core/shared/src/commonMain/kotlin/io/github/vinceglb/sample/core/MainViewModel.kt#L101-L109
Lines 101 to 109 in bc39937
is FileKitPickerState.Started -> println("Started picking ${result.total} files") | |
is FileKitPickerState.Progress -> { | |
println("New files processed: ${result.processed.size} / ${result.total}") | |
_uiState.update { it.copy(it.files + result.processed) } | |
} | |
is FileKitPickerState.Completed -> { | |
println("File picker completed with ${result.result.size} files") | |
_uiState.update { it.copy(it.files + result.result) } |
Bug: File Picker Fails with Empty MIME Types
The getMimeTypes
function no longer falls back to ["*/*"]
when all provided file extensions fail to map to valid MIME types. This results in an empty MIME type array being passed to the Android file picker, which can prevent it from showing any file types or allowing selection.
filekit-dialogs/src/androidMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.android.kt#L226-L234
FileKit/filekit-dialogs/src/androidMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.android.kt
Lines 226 to 234 in bc39937
private fun getMimeTypes(fileExtensions: Set<String>?): Array<String> { | |
val mimeTypeMap = MimeTypeMap.getSingleton() | |
return fileExtensions | |
?.takeIf { it.isNotEmpty() } | |
?.mapNotNull { mimeTypeMap.getMimeTypeFromExtension(it) } | |
?.toTypedArray() | |
?: arrayOf("*/*") | |
} |
Bug: File List Duplication in Picker State Flow
The toPickerStateFlow
function's FileKitPickerState.Progress
events emit a cumulative list of files processed so far (using subList(0, index + 1)
), and FileKitPickerState.Completed
events emit the full list. The sample code's consumer logic appends result.processed
from Progress
and result.result
from Completed
to its state, causing duplicate files. This requires either Progress
to emit only newly processed files, or the consumer to replace the file list or handle only truly new additions.
filekit-dialogs/src/commonMain/kotlin/io/github/vinceglb/filekit/dialogs/Utils.kt#L9-L24
FileKit/filekit-dialogs/src/commonMain/kotlin/io/github/vinceglb/filekit/dialogs/Utils.kt
Lines 9 to 24 in bc39937
internal fun List<PlatformFile>?.toPickerStateFlow(): Flow<FileKitPickerState<List<PlatformFile>>> { | |
val files = this | |
return channelFlow { | |
when { | |
files.isNullOrEmpty() -> send(FileKitPickerState.Cancelled) | |
else -> { | |
send(FileKitPickerState.Started(files.size)) | |
files.forEachIndexed { index, file -> | |
send(FileKitPickerState.Progress(files.subList(0, index + 1), files.size)) | |
} | |
send(FileKitPickerState.Completed(files)) | |
} | |
} | |
} | |
} |
samples/sample-core/shared/src/commonMain/kotlin/io/github/vinceglb/sample/core/MainViewModel.kt#L101-L110
Lines 101 to 110 in bc39937
is FileKitPickerState.Started -> println("Started picking ${result.total} files") | |
is FileKitPickerState.Progress -> { | |
println("New files processed: ${result.processed.size} / ${result.total}") | |
_uiState.update { it.copy(it.files + result.processed) } | |
} | |
is FileKitPickerState.Completed -> { | |
println("File picker completed with ${result.result.size} files") | |
_uiState.update { it.copy(it.files + result.result) } | |
} |
Bug: State Emission Issue in Parsing Function
In SingleWithState.parseResult()
, the mapNotNull
operator, combined with firstOrNull()
, incorrectly filters out Progress
and Completed
states when their underlying lists (processed
or result
) are empty. This prevents these states from being emitted, leading to incomplete state transitions and potential flow non-completion.
filekit-dialogs/src/commonMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKitMode.kt#L68-L84
FileKit/filekit-dialogs/src/commonMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKitMode.kt
Lines 68 to 84 in bc39937
is FileKitPickerState.Progress -> { | |
it.processed.firstOrNull()?.let { file -> | |
FileKitPickerState.Progress( | |
processed = file, | |
total = it.total | |
) | |
} | |
} | |
is FileKitPickerState.Completed -> { | |
it.result.firstOrNull()?.let { file -> | |
FileKitPickerState.Completed(result = file) | |
} | |
} | |
} | |
} |
BugBot free trial expires on July 22, 2025
You have used $0.00 of your $2.00 spend limit so far. Manage your spend limit in the Cursor dashboard.
Was this report helpful? Give feedback by reacting with 👍 or 👎
Hi @kihaki! I tried to improve the developer experience as much as I could by:
Also, I finished the implementation on all the platforms, and I fixed a bug on the iOS part. Here is an example of how to use it: val multipleFilesPickerWithState = rememberFilePickerLauncher(
type = FileKitType.Image,
mode = FileKitMode.MultipleWithState(),
) { result ->
when (result) {
FileKitPickerState.Cancelled -> println("File picker cancelled")
is FileKitPickerState.Started -> println("Started picking ${result.total} files")
is FileKitPickerState.Progress -> println("New files processed: ${result.processed.size} / ${result.total}")
is FileKitPickerState.Completed -> println("File picker completed with ${result.result.size} files")
}
}
Button(onClick = { multipleFilesPickerWithState.launch() }) {
Text("Picke images with state")
} and val files = FileKit.openFilePicker(
type = FileKitType.Image,
mode = FileKitMode.MultipleWithState(),
)
files.collect { result ->
when (result) {
FileKitPickerState.Cancelled -> println("File picker cancelled")
is FileKitPickerState.Started -> println("Started picking ${result.total} files")
is FileKitPickerState.Progress -> println("New files processed: ${result.processed.size} / ${result.total}")
is FileKitPickerState.Completed -> println("File picker completed with ${result.result.size} files")
}
} I'm really interested in having your feedback on my changes! |
Hey @vinceglb I just came back to see how its going, I wasn't notified about your comment it seems, so sorry for not checking in earlier! |
Hey @kihaki! No problem! Thanks again for your contribution! 🙏 |
No description provided.