Skip to content

Commit 5c35b5c

Browse files
authored
🔀 Merge pull request #517 from vinceglb/compose-macos-support
Support FileKit Dialogs macOS targets
2 parents 76c72a7 + e537115 commit 5c35b5c

File tree

22 files changed

+893
-28
lines changed

22 files changed

+893
-28
lines changed

build-logic/convention/src/main/kotlin/ComposeMultiplatformLibraryConventionPlugin.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class ComposeMultiplatformLibraryConventionPlugin : Plugin<Project> {
2727
extension = this,
2828
modulePackage = modulePackage,
2929
moduleName = moduleName,
30-
addMacosTargets = false,
30+
addMacosTargets = true,
3131
addWatchosTargets = false,
3232
)
3333
configureComposeMultiplatform(this)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package io.github.vinceglb.filekit.dialogs.compose
2+
3+
import androidx.compose.runtime.Composable
4+
5+
@Composable
6+
internal actual fun InitFileKit() {}

filekit-dialogs/src/iosMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.ios.kt

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ import platform.UniformTypeIdentifiers.UTTypeItem
6262
import platform.UniformTypeIdentifiers.UTTypeMovie
6363
import kotlin.coroutines.resume
6464
import kotlin.coroutines.resumeWithException
65-
import kotlin.coroutines.suspendCoroutine
6665

6766
private object FileKitDialog {
6867
// Create a reference to the picker delegate to prevent it from being garbage collected
@@ -111,7 +110,7 @@ internal actual suspend fun FileKit.platformOpenFilePicker(
111110
*
112111
* @param directory The initial directory. Supported on desktop platforms.
113112
* @param dialogSettings Platform-specific settings for the dialog.
114-
* @return The picked directory as a [PlatformFile], or null if cancelled.
113+
* @return The picked directory as a [PlatformFile], or null if canceled.
115114
*/
116115
public actual suspend fun FileKit.openDirectoryPicker(
117116
directory: PlatformFile?,
@@ -129,7 +128,7 @@ public actual suspend fun FileKit.openDirectoryPicker(
129128
* @param extension The file extension (optional).
130129
* @param directory The initial directory. Supported on desktop platforms.
131130
* @param dialogSettings Platform-specific settings for the dialog.
132-
* @return The path where the file should be saved as a [PlatformFile], or null if cancelled.
131+
* @return The path where the file should be saved as a [PlatformFile], or null if canceled.
133132
*/
134133
@OptIn(ExperimentalForeignApi::class)
135134
public actual suspend fun FileKit.openFileSaver(
@@ -138,7 +137,7 @@ public actual suspend fun FileKit.openFileSaver(
138137
directory: PlatformFile?,
139138
dialogSettings: FileKitDialogSettings,
140139
): PlatformFile? = withContext(Dispatchers.Main) {
141-
suspendCoroutine { continuation ->
140+
suspendCancellableCoroutine { continuation ->
142141
// Create a picker delegate
143142
documentPickerDelegate = DocumentPickerDelegate(
144143
onFilesPicked = { urls ->
@@ -159,7 +158,7 @@ public actual suspend fun FileKit.openFileSaver(
159158
},
160159
)
161160

162-
// suggestedName cannot include "/" because the OS interprets it as a directory separator.
161+
// the suggestedName cannot include "/" because the OS interprets it as a directory separator.
163162
// However, "Files" renders ":" as "/", so we can just use ":" and the user will see "/".
164163
val sanitizedSuggestedName = suggestedName.replace("/", ":")
165164
val fileName = buildFileSaverSuggestedName(
@@ -211,15 +210,15 @@ public actual suspend fun FileKit.openFileSaver(
211210
* @param cameraFacing The camera facing (System, Back or Front).
212211
* @param destinationFile The file where the captured media will be saved.
213212
* @param openCameraSettings Platform-specific settings for the camera.
214-
* @return The saved file as a [PlatformFile], or null if cancelled.
213+
* @return The saved file as a [PlatformFile], or null if canceled.
215214
*/
216215
public actual suspend fun FileKit.openCameraPicker(
217216
type: FileKitCameraType,
218217
cameraFacing: FileKitCameraFacing,
219218
destinationFile: PlatformFile,
220219
openCameraSettings: FileKitOpenCameraSettings,
221220
): PlatformFile? = withContext(Dispatchers.Main) {
222-
suspendCoroutine { continuation ->
221+
suspendCancellableCoroutine { continuation ->
223222
cameraControllerDelegate = CameraControllerDelegate(
224223
onImagePicked = { image ->
225224
if (image != null) {
@@ -310,7 +309,7 @@ public actual suspend fun FileKit.shareFile(
310309
val shareVC = UIActivityViewController(activityItems, null)
311310

312311
if (isIpad()) {
313-
// ipad need sourceView for show
312+
// iPad need sourceView for show
314313
shareVC.popoverPresentationController?.apply {
315314
sourceView = viewController.view
316315
sourceRect = viewController.view.center.useContents { CGRectMake(x, y, 0.0, 0.0) }
@@ -374,7 +373,7 @@ private suspend fun callPicker(
374373
contentTypes: List<UTType>,
375374
directory: PlatformFile?,
376375
): List<NSURL>? = withContext(Dispatchers.Main) {
377-
suspendCoroutine { continuation ->
376+
suspendCancellableCoroutine { continuation ->
378377
// Create a picker delegate
379378
documentPickerDelegate = DocumentPickerDelegate(
380379
onFilesPicked = { urls -> continuation.resume(urls) },
@@ -387,7 +386,7 @@ private suspend fun callPicker(
387386
// Set the initial directory
388387
directory?.let { pickerController.directoryURL = NSURL.fileURLWithPath(it.path) }
389388

390-
// Setup the picker mode
389+
// Set up the picker mode
391390
pickerController.allowsMultipleSelection = mode == Mode.Multiple
392391

393392
// Assign the delegate to the picker controller
@@ -405,7 +404,7 @@ private suspend fun callPicker(
405404
private suspend fun getPhPickerResults(
406405
mode: PickerMode,
407406
type: FileKitType,
408-
): List<PHPickerResult> = suspendCoroutine { continuation ->
407+
): List<PHPickerResult> = suspendCancellableCoroutine { continuation ->
409408
// Create a picker delegate
410409
phPickerDelegate = PhPickerDelegate(onFilesPicked = continuation::resume)
411410
phPickerDismissDelegate = PhPickerDismissDelegate(onFilesPicked = continuation::resume)
@@ -483,7 +482,7 @@ private fun callPhPicker(
483482
val orderedFiles = arrayOfNulls<PlatformFile>(pickerResults.size)
484483
val lock = Mutex()
485484

486-
// Launch a child coroutine for every copy, preserving index
485+
// Launch a child coroutine for every copy, preserving the index
487486
pickerResults
488487
.mapIndexed { index, result ->
489488
launch(Dispatchers.IO) {
@@ -502,7 +501,7 @@ private fun callPhPicker(
502501
}
503502

504503
else -> {
505-
// Must copy the URL here because it becomes invalid outside of the loadFileRepresentationForTypeIdentifier callback scope
504+
// Must copy the URL here because it becomes invalid outside the loadFileRepresentationForTypeIdentifier callback scope
506505
val tempUrl = url?.let {
507506
copyToTempFile(fileManager, it, tempRoot.lastPathComponent!!)
508507
}
@@ -513,7 +512,7 @@ private fun callPhPicker(
513512
} ?: return@launch // skip nulls
514513

515514
lock.withLock {
516-
// Insert at original index to preserve selection order
515+
// Insert at the original index to preserve selection order
517516
orderedFiles[index] = PlatformFile(src)
518517
send(FileKitPickerState.Progress(orderedFiles.filterNotNull(), pickerResults.size))
519518
}

filekit-dialogs/src/macosMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.macos.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ internal actual suspend fun FileKit.platformOpenFilePicker(
4343
*
4444
* @param directory The initial directory. Supported on desktop platforms.
4545
* @param dialogSettings Platform-specific settings for the dialog.
46-
* @return The picked directory as a [PlatformFile], or null if cancelled.
46+
* @return The picked directory as a [PlatformFile], or null if canceled.
4747
*/
4848
public actual suspend fun FileKit.openDirectoryPicker(
4949
directory: PlatformFile?,
@@ -63,7 +63,7 @@ public actual suspend fun FileKit.openDirectoryPicker(
6363
* @param extension The file extension (optional).
6464
* @param directory The initial directory. Supported on desktop platforms.
6565
* @param dialogSettings Platform-specific settings for the dialog.
66-
* @return The path where the file should be saved as a [PlatformFile], or null if cancelled.
66+
* @return The path where the file should be saved as a [PlatformFile], or null if canceled.
6767
*/
6868
public actual suspend fun FileKit.openFileSaver(
6969
suggestedName: String,
@@ -95,7 +95,7 @@ public actual suspend fun FileKit.openFileSaver(
9595
// Run the NSSavePanel
9696
val result = nsSavePanel.runModal()
9797

98-
// If the user cancelled the operation, return null
98+
// If the user canceled the operation, return null
9999
if (result != NSModalResponseOK) {
100100
return null
101101
}
@@ -151,7 +151,7 @@ private fun callPicker(
151151
// Run the NSOpenPanel
152152
val result = nsOpenPanel.runModal()
153153

154-
// If the user cancelled the operation, return null
154+
// If the user canceled the operation, return null
155155
if (result != NSModalResponseOK) {
156156
return null
157157
}
@@ -176,7 +176,7 @@ private fun NSOpenPanel.configure(
176176
// Set the allowed file types
177177
extensions?.let { allowedFileTypes = extensions.toList() }
178178

179-
// Setup the picker mode and files extensions
179+
// Set up the picker mode and files extensions
180180
when (mode) {
181181
Mode.Single -> {
182182
canChooseFiles = true

gradle.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ org.gradle.caching=true
1111
android.nonTransitiveRClass=true
1212
android.useAndroidX=true
1313

14+
# Compose
15+
org.jetbrains.compose.experimental.macos.enabled=true
16+
1417
# == Publication == #
1518

1619
# OSS

sample/desktopApp/src/main/kotlin/io/github/vinceglb/filekit/sample/main.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import io.github.vinceglb.filekit.FileKit
1111
import io.github.vinceglb.filekit.sample.shared.App
1212

1313
fun main() {
14-
// MacOS System Appearance
14+
// macOS System Appearance
1515
System.setProperty("apple.awt.application.appearance", "system")
1616

1717
application {

0 commit comments

Comments
 (0)