Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import platform.UIKit.UIApplication
import platform.UIKit.UIDevice
import platform.UIKit.UIDocumentInteractionController
import platform.UIKit.UIDocumentPickerViewController
import platform.UIKit.UIImage
import platform.UIKit.UIImageJPEGRepresentation
import platform.UIKit.UIImagePickerController
import platform.UIKit.UIImagePickerControllerCameraDevice
Expand Down Expand Up @@ -225,55 +226,57 @@ public actual suspend fun FileKit.openCameraPicker(
cameraFacing: FileKitCameraFacing,
destinationFile: PlatformFile,
openCameraSettings: FileKitOpenCameraSettings,
): PlatformFile? = withContext(Dispatchers.Main) {
suspendCancellableCoroutine { continuation ->
cameraControllerDelegate = CameraControllerDelegate(
onImagePicked = { image ->
if (image != null) {
// Convert UIImage to NSData (JPEG format with compression quality 1.0)
val imageData = UIImageJPEGRepresentation(image, 1.0)

// Create an NSURL for the file path
val fileUrl = NSURL.fileURLWithPath(destinationFile.path)

// Write the NSData to the file
if (imageData?.writeToURL(fileUrl, true) == true) {
// Return the NSURL of the saved image file
continuation.resume(destinationFile)
} else {
// If saving fails, return null
continuation.resume(null)
}
} else {
continuation.resume(null)
}
},
)
): PlatformFile? {
val image = withContext(Dispatchers.Main) {
suspendCancellableCoroutine<UIImage?> { continuation ->
cameraControllerDelegate = CameraControllerDelegate(
onImagePicked = { image ->
continuation.resume(image)
},
)

val pickerController = UIImagePickerController()
pickerController.sourceType =
UIImagePickerControllerSourceType.UIImagePickerControllerSourceTypeCamera
pickerController.delegate = cameraControllerDelegate
val pickerController = UIImagePickerController()
pickerController.sourceType =
UIImagePickerControllerSourceType.UIImagePickerControllerSourceTypeCamera
pickerController.delegate = cameraControllerDelegate

when (cameraFacing) {
FileKitCameraFacing.Front -> {
pickerController.cameraDevice =
UIImagePickerControllerCameraDevice.UIImagePickerControllerCameraDeviceFront
}
when (cameraFacing) {
FileKitCameraFacing.Front -> {
pickerController.cameraDevice =
UIImagePickerControllerCameraDevice.UIImagePickerControllerCameraDeviceFront
}

FileKitCameraFacing.Back -> {
pickerController.cameraDevice =
UIImagePickerControllerCameraDevice.UIImagePickerControllerCameraDeviceRear
}

FileKitCameraFacing.Back -> {
pickerController.cameraDevice =
UIImagePickerControllerCameraDevice.UIImagePickerControllerCameraDeviceRear
FileKitCameraFacing.System -> {}
}

FileKitCameraFacing.System -> {}
openCameraSettings.presenterViewController()?.presentViewController(
pickerController,
animated = true,
completion = null,
)
}
} ?: return null

openCameraSettings.presenterViewController()?.presentViewController(
pickerController,
animated = true,
completion = null,
)
// Encode and write off the main thread: JPEG encoding a full-resolution photo
// at quality 1.0 is expensive and used to freeze the UI right after the capture
return withContext(Dispatchers.IO) {
// Convert UIImage to NSData (JPEG format with compression quality 1.0)
val imageData = UIImageJPEGRepresentation(image, 1.0)

// Create an NSURL for the file path
val fileUrl = NSURL.fileURLWithPath(destinationFile.path)

// Write the NSData to the file, returning the saved file on success
if (imageData?.writeToURL(fileUrl, true) == true) {
destinationFile
} else {
null
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ internal class CameraControllerDelegate(
didFinishPickingMediaWithInfo: Map<Any?, *>,
) {
val image = didFinishPickingMediaWithInfo[UIImagePickerControllerOriginalImage] as? UIImage
onImagePicked.invoke(image)
picker.dismissViewControllerAnimated(true, null)
// Deliver the result only once the picker is fully dismissed, so client reactions
// (navigation, closing dialogs, ...) can't race the UIKit dismissal transition
picker.dismissViewControllerAnimated(true) {
onImagePicked.invoke(image)
}
}

override fun imagePickerControllerDidCancel(picker: UIImagePickerController) {
picker.dismissViewControllerAnimated(true, null)
onImagePicked.invoke(null)
picker.dismissViewControllerAnimated(true) {
onImagePicked.invoke(null)
}
}
}