diff --git a/filekit-dialogs/src/commonMain/kotlin/io/github/vinceglb/filekit/dialogs/FileSaverName.kt b/filekit-dialogs/src/commonMain/kotlin/io/github/vinceglb/filekit/dialogs/FileSaverName.kt index 09f54bbd..ccc19484 100644 --- a/filekit-dialogs/src/commonMain/kotlin/io/github/vinceglb/filekit/dialogs/FileSaverName.kt +++ b/filekit-dialogs/src/commonMain/kotlin/io/github/vinceglb/filekit/dialogs/FileSaverName.kt @@ -20,3 +20,15 @@ internal fun buildFileSaverSuggestedName( else -> "$suggestedName.$normalizedExtension" } } + +internal fun buildFileSaverAllowedFileTypes( + defaultExtension: String?, + allowedExtensions: Set?, +): List? { + val normalizedDefault = normalizeFileSaverExtension(defaultExtension) + val normalizedAllowed = normalizeFileSaverExtensions(allowedExtensions).orEmpty() + return buildList { + normalizedDefault?.let { add(it) } + normalizedAllowed.forEach { if (it != normalizedDefault) add(it) } + }.takeIf { it.isNotEmpty() } +} diff --git a/filekit-dialogs/src/commonTest/kotlin/io/github/vinceglb/filekit/dialogs/FileSaverNameTest.kt b/filekit-dialogs/src/commonTest/kotlin/io/github/vinceglb/filekit/dialogs/FileSaverNameTest.kt index 08ef6def..c67d4505 100644 --- a/filekit-dialogs/src/commonTest/kotlin/io/github/vinceglb/filekit/dialogs/FileSaverNameTest.kt +++ b/filekit-dialogs/src/commonTest/kotlin/io/github/vinceglb/filekit/dialogs/FileSaverNameTest.kt @@ -55,4 +55,28 @@ class FileSaverNameTest { assertEquals("document.pdf", buildFileSaverSuggestedName("document", ".pdf")) assertEquals("document.pdf", buildFileSaverSuggestedName("document", " .pdf ")) } + + @Test + fun buildFileSaverAllowedFileTypes_whenNoExtensions_returnsNull() { + assertNull(buildFileSaverAllowedFileTypes(null, null)) + assertNull(buildFileSaverAllowedFileTypes("", setOf("", "."))) + } + + @Test + fun buildFileSaverAllowedFileTypes_whenOnlyDefaultExtension_returnsSingleNormalizedType() { + assertEquals(listOf("pdf"), buildFileSaverAllowedFileTypes(".pdf", null)) + } + + @Test + fun buildFileSaverAllowedFileTypes_whenNoDefault_returnsNormalizedAllowedExtensions() { + assertEquals(listOf("md", "txt"), buildFileSaverAllowedFileTypes(null, setOf("md", "txt"))) + } + + @Test + fun buildFileSaverAllowedFileTypes_putsDefaultExtensionFirstAndDeduplicates() { + assertEquals( + listOf("pdf", "md", "txt"), + buildFileSaverAllowedFileTypes("pdf", setOf("md", "pdf", "txt")), + ) + } } diff --git a/filekit-dialogs/src/jvmMain/kotlin/io/github/vinceglb/filekit/dialogs/platform/mac/MacOSFilePicker.kt b/filekit-dialogs/src/jvmMain/kotlin/io/github/vinceglb/filekit/dialogs/platform/mac/MacOSFilePicker.kt index eee483e4..2fd58cf0 100644 --- a/filekit-dialogs/src/jvmMain/kotlin/io/github/vinceglb/filekit/dialogs/platform/mac/MacOSFilePicker.kt +++ b/filekit-dialogs/src/jvmMain/kotlin/io/github/vinceglb/filekit/dialogs/platform/mac/MacOSFilePicker.kt @@ -3,7 +3,7 @@ package io.github.vinceglb.filekit.dialogs.platform.mac import io.github.vinceglb.filekit.PlatformFile import io.github.vinceglb.filekit.dialogs.FileKitDialogSettings import io.github.vinceglb.filekit.dialogs.FileKitMacOSSettings -import io.github.vinceglb.filekit.dialogs.buildFileSaverSuggestedName +import io.github.vinceglb.filekit.dialogs.buildFileSaverAllowedFileTypes import io.github.vinceglb.filekit.dialogs.platform.PlatformFilePicker import io.github.vinceglb.filekit.dialogs.platform.mac.foundation.Foundation import io.github.vinceglb.filekit.dialogs.platform.mac.foundation.ID @@ -73,18 +73,15 @@ internal class MacOSFilePicker : PlatformFilePicker { Foundation.invoke(savePanel, "setDirectoryURL:", Foundation.nsURL(it.path)) } + // Set the file name without extension, NSSavePanel appends it from allowedFileTypes Foundation.invoke( savePanel, "setNameFieldStringValue:", - Foundation.nsString( - buildFileSaverSuggestedName( - suggestedName = suggestedName, - extension = defaultExtension, - ), - ), + Foundation.nsString(suggestedName), ) - val fileTypes = allowedExtensions ?: defaultExtension?.let { setOf(it) } + // Default extension first so it is the one appended + val fileTypes = buildFileSaverAllowedFileTypes(defaultExtension, allowedExtensions) savePanel.setAllowedFileTypes(fileTypes) Foundation.invoke( diff --git a/filekit-dialogs/src/macosMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.macos.kt b/filekit-dialogs/src/macosMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.macos.kt index 851f2acf..7523fa8e 100644 --- a/filekit-dialogs/src/macosMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.macos.kt +++ b/filekit-dialogs/src/macosMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.macos.kt @@ -74,21 +74,16 @@ internal actual suspend fun FileKit.platformOpenFileSaver( ): PlatformFile? { // Create an NSSavePanel val nsSavePanel = NSSavePanel() - val normalizedDefaultExtension = normalizeFileSaverExtension(defaultExtension) - val normalizedAllowedExtensions = normalizeFileSaverExtensions(allowedExtensions) // Set the initial directory directory?.let { nsSavePanel.directoryURL = NSURL.fileURLWithPath(it.path) } - // Set the file name - nsSavePanel.nameFieldStringValue = buildFileSaverSuggestedName( - suggestedName = suggestedName, - extension = normalizedDefaultExtension, - ) + // Set the file name without extension, NSSavePanel appends it from allowedFileTypes + nsSavePanel.nameFieldStringValue = suggestedName - // Set the file extension filters - val fileTypes = normalizedAllowedExtensions ?: normalizedDefaultExtension?.let { setOf(it) } - fileTypes?.let { nsSavePanel.allowedFileTypes = it.toList() } + // Set the file extension filters, default extension first so it is the one appended + buildFileSaverAllowedFileTypes(defaultExtension, allowedExtensions) + ?.let { nsSavePanel.allowedFileTypes = it } // Accept the creation of directories nsSavePanel.canCreateDirectories = dialogSettings.canCreateDirectories