mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 18:39:55 +02:00
feat: add preferences and send empty state
This commit is contained in:
@@ -2,9 +2,12 @@ package com.vnidrop.app.core
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import java.awt.EventQueue
|
||||
import java.awt.FileDialog
|
||||
import java.awt.Frame
|
||||
import java.awt.KeyboardFocusManager
|
||||
import java.io.File
|
||||
import javax.swing.JFileChooser
|
||||
|
||||
@Composable
|
||||
actual fun rememberShareFilePicker(
|
||||
@@ -13,17 +16,29 @@ actual fun rememberShareFilePicker(
|
||||
): ShareFilePicker = remember(onFilePicked, onError) {
|
||||
object : ShareFilePicker {
|
||||
override fun pickFile() {
|
||||
try {
|
||||
val dialog = FileDialog(null as Frame?, "Select file to share", FileDialog.LOAD)
|
||||
dialog.isVisible = true
|
||||
val directory = dialog.directory
|
||||
val file = dialog.file
|
||||
if (directory != null && file != null) {
|
||||
val selected = File(directory, file)
|
||||
onFilePicked(PickedShareFile(selected.absolutePath, selected.name))
|
||||
}
|
||||
} catch (error: Throwable) {
|
||||
onError(error.message ?: error.toString())
|
||||
openPicker(onError) {
|
||||
pickShareFile()?.let(onFilePicked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun rememberReceiveFolderPicker(
|
||||
onFolderPicked: (ReceiveFolder) -> Unit,
|
||||
onError: (String) -> Unit,
|
||||
): ReceiveFolderPicker = remember(onFolderPicked, onError) {
|
||||
object : ReceiveFolderPicker {
|
||||
override fun pickFolder() {
|
||||
openPicker(onError) {
|
||||
val selected = pickDirectory() ?: return@openPicker
|
||||
onFolderPicked(
|
||||
ReceiveFolder(
|
||||
kind = ReceiveFolderKind.FileSystemPath,
|
||||
value = selected.absolutePath,
|
||||
displayName = selected.name.ifBlank { selected.absolutePath },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,3 +52,85 @@ actual suspend fun sharePickedFile(
|
||||
) {
|
||||
repository.sharePath(file.value, transferName, senderName)
|
||||
}
|
||||
|
||||
private fun openPicker(
|
||||
onError: (String) -> Unit,
|
||||
block: () -> Unit,
|
||||
) {
|
||||
EventQueue.invokeLater {
|
||||
try {
|
||||
block()
|
||||
} catch (error: Throwable) {
|
||||
onError(error.message ?: error.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun nativeFileDialog(title: String): FileDialog =
|
||||
FileDialog(activeFrame(), title, FileDialog.LOAD)
|
||||
|
||||
private fun activeFrame(): Frame? {
|
||||
val activeWindow = KeyboardFocusManager.getCurrentKeyboardFocusManager().activeWindow
|
||||
return activeWindow as? Frame
|
||||
?: Frame.getFrames().firstOrNull { it.isActive || it.isFocused }
|
||||
?: Frame.getFrames().firstOrNull { it.isVisible }
|
||||
}
|
||||
|
||||
private fun pickShareFile(): PickedShareFile? {
|
||||
val dialog = nativeFileDialog("Select file to share")
|
||||
return try {
|
||||
dialog.isVisible = true
|
||||
val directory = dialog.directory
|
||||
val file = dialog.file
|
||||
if (directory != null && file != null) {
|
||||
val selected = File(directory, file)
|
||||
PickedShareFile(selected.absolutePath, selected.name)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} finally {
|
||||
dialog.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private fun pickDirectory(): File? =
|
||||
if (isMacOs()) {
|
||||
val dialog = withMacDirectoryDialog {
|
||||
nativeFileDialog("Select receive folder").apply { isVisible = true }
|
||||
}
|
||||
try {
|
||||
val directory = dialog.directory ?: return null
|
||||
dialog.file
|
||||
?.let { File(directory, it) }
|
||||
?: File(directory)
|
||||
} finally {
|
||||
dialog.dispose()
|
||||
}
|
||||
} else {
|
||||
val chooser = JFileChooser().apply {
|
||||
dialogTitle = "Select receive folder"
|
||||
fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
|
||||
isAcceptAllFileFilterUsed = false
|
||||
}
|
||||
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) chooser.selectedFile else null
|
||||
}
|
||||
|
||||
private fun <T> withMacDirectoryDialog(block: () -> T): T {
|
||||
if (!isMacOs()) return block()
|
||||
|
||||
val key = "apple.awt.fileDialogForDirectories"
|
||||
val previous = System.getProperty(key)
|
||||
System.setProperty(key, "true")
|
||||
return try {
|
||||
block()
|
||||
} finally {
|
||||
if (previous == null) {
|
||||
System.clearProperty(key)
|
||||
} else {
|
||||
System.setProperty(key, previous)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isMacOs(): Boolean =
|
||||
System.getProperty("os.name").startsWith("Mac", ignoreCase = true)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.vnidrop.app.core
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import uniffi.vnidrop.ReceiveOutputSink
|
||||
import java.io.File
|
||||
|
||||
@Composable
|
||||
actual fun rememberFileSystemService(): FileSystemService =
|
||||
remember { JvmFileSystemService() }
|
||||
|
||||
private class JvmFileSystemService : FileSystemService {
|
||||
override fun defaultReceiveFolder(): ReceiveFolder =
|
||||
ReceiveFolder(
|
||||
kind = ReceiveFolderKind.FileSystemPath,
|
||||
value = File(System.getProperty("user.home"), "Downloads").absolutePath,
|
||||
displayName = "Downloads",
|
||||
)
|
||||
|
||||
override suspend fun validateReceiveFolder(folder: ReceiveFolder): FolderAccessStatus {
|
||||
if (folder.kind != ReceiveFolderKind.FileSystemPath) return FolderAccessStatus.Unavailable
|
||||
return runCatching {
|
||||
val directory = File(folder.value)
|
||||
if (!directory.exists()) directory.mkdirs()
|
||||
if (directory.isDirectory && directory.canWrite()) FolderAccessStatus.Writable else FolderAccessStatus.Unavailable
|
||||
}.getOrDefault(FolderAccessStatus.Unavailable)
|
||||
}
|
||||
|
||||
override fun createReceiveOutputSink(folder: ReceiveFolder): ReceiveOutputSink? = null
|
||||
}
|
||||
Reference in New Issue
Block a user