From 3eef0de648010f65762b56641628ecbdaed3c978 Mon Sep 17 00:00:00 2001 From: Ahmed Atwa Date: Sun, 30 Oct 2022 15:14:10 +0200 Subject: [PATCH] implement camera image picker --- README.md | 3 ++ filepicker/build.gradle | 2 +- .../com/atwa/filepicker/core/FilePicker.kt | 9 +++++ .../atwa/filepicker/core/StorageFilePicker.kt | 7 ++++ .../com/atwa/filepicker/decoder/Decoder.kt | 1 + .../com/atwa/filepicker/decoder/UriDecoder.kt | 8 ++++- .../filepicker/request/ImageCameraRequest.kt | 36 +++++++++++++++++++ 7 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 filepicker/src/main/java/com/atwa/filepicker/request/ImageCameraRequest.kt diff --git a/README.md b/README.md index e654b60..4070644 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,9 @@ them with api requests to upload them to server, -Not a single permission is req | 1.0.0 | Initial release | | 1.0.1 | Increase buffer size to handle larger files (8GB Max) | | 1.0.3 | Fix bug : LifecycleOwner Activity is attempting to register while current state is RESUMED. | +| 1.0.4 | Enhancement : Avoid possible activity reference leaking + Feature : Implement camera image picker. | + ### Contribution diff --git a/filepicker/build.gradle b/filepicker/build.gradle index 98a1475..da9e0d4 100644 --- a/filepicker/build.gradle +++ b/filepicker/build.gradle @@ -44,7 +44,7 @@ afterEvaluate { groupId = 'com.github.atwa' artifactId = 'filepicker' - version = '1.0.3' + version = '1.0.4-alpha1' } } repositories { diff --git a/filepicker/src/main/java/com/atwa/filepicker/core/FilePicker.kt b/filepicker/src/main/java/com/atwa/filepicker/core/FilePicker.kt index 17ff7c7..f08d3e1 100644 --- a/filepicker/src/main/java/com/atwa/filepicker/core/FilePicker.kt +++ b/filepicker/src/main/java/com/atwa/filepicker/core/FilePicker.kt @@ -16,6 +16,15 @@ interface FilePicker { */ fun pickImage(onImagePicked: (Pair?) -> Unit) + /** + * launching intent for picking images from gallery. + * This method should be called from activity and the result will be provided in the callback. + * + * Parameters: + * @param onImagePicked Callback to receive the picker gallery image result. + */ + fun captureCameraImage(onImagePicked: (Pair?) -> Unit) + /** * launching intent for picking pdf files. * This method should be called from activity and the result will be provided in the callback. diff --git a/filepicker/src/main/java/com/atwa/filepicker/core/StorageFilePicker.kt b/filepicker/src/main/java/com/atwa/filepicker/core/StorageFilePicker.kt index b0cb15a..8f9a1f1 100644 --- a/filepicker/src/main/java/com/atwa/filepicker/core/StorageFilePicker.kt +++ b/filepicker/src/main/java/com/atwa/filepicker/core/StorageFilePicker.kt @@ -7,7 +7,9 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import com.atwa.filepicker.decoder.Decoder import com.atwa.filepicker.decoder.UriDecoder +import com.atwa.filepicker.request.* import com.atwa.filepicker.request.FilePickerRequest +import com.atwa.filepicker.request.ImageCameraRequest import com.atwa.filepicker.request.ImagePickerRequest import com.atwa.filepicker.request.PdfPickerRequest import com.atwa.filepicker.request.PickerRequest @@ -30,6 +32,11 @@ internal class StorageFilePicker(private val activity: WeakReference?) -> Unit) { + pickerRequest = ImageCameraRequest(decoder, onImagePicked) + initialize() + } + override fun pickPdf(onPdfPicked: (Pair?) -> Unit) { pickerRequest = PdfPickerRequest(decoder, onPdfPicked) initialize() diff --git a/filepicker/src/main/java/com/atwa/filepicker/decoder/Decoder.kt b/filepicker/src/main/java/com/atwa/filepicker/decoder/Decoder.kt index 5fb622d..e023e6a 100644 --- a/filepicker/src/main/java/com/atwa/filepicker/decoder/Decoder.kt +++ b/filepicker/src/main/java/com/atwa/filepicker/decoder/Decoder.kt @@ -9,4 +9,5 @@ internal interface Decoder { fun getStorageImage(imageUri: Uri?): Flow?> fun getStoragePDF(pdfUri: Uri?): Flow?> fun getStorageFile(pdfUri: Uri?): Flow?> + fun createCameraOutputUri() : Uri } \ No newline at end of file diff --git a/filepicker/src/main/java/com/atwa/filepicker/decoder/UriDecoder.kt b/filepicker/src/main/java/com/atwa/filepicker/decoder/UriDecoder.kt index 9c56b7e..83af482 100644 --- a/filepicker/src/main/java/com/atwa/filepicker/decoder/UriDecoder.kt +++ b/filepicker/src/main/java/com/atwa/filepicker/decoder/UriDecoder.kt @@ -7,13 +7,14 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory.decodeFileDescriptor import android.net.Uri import android.provider.OpenableColumns -import com.atwa.filepicker.stream.Streamer import com.atwa.filepicker.stream.FileStreamer +import com.atwa.filepicker.stream.Streamer import kotlinx.coroutines.flow.flow import java.io.File import java.io.FileInputStream import java.io.FileOutputStream import java.io.IOException +import java.util.concurrent.TimeUnit internal class UriDecoder( private val context: Context?, @@ -59,6 +60,11 @@ internal class UriDecoder( emit(result) } + override fun createCameraOutputUri(): Uri { + val timeStamp = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toString() + return Uri.parse("${context?.cacheDir}$timeStamp") + } + private fun getBitMap(): Pair? { return uri?.let { uri -> diff --git a/filepicker/src/main/java/com/atwa/filepicker/request/ImageCameraRequest.kt b/filepicker/src/main/java/com/atwa/filepicker/request/ImageCameraRequest.kt new file mode 100644 index 0000000..ee2d5eb --- /dev/null +++ b/filepicker/src/main/java/com/atwa/filepicker/request/ImageCameraRequest.kt @@ -0,0 +1,36 @@ +package com.atwa.filepicker.request + +import android.content.Intent +import android.graphics.Bitmap +import android.net.Uri +import android.os.Environment +import android.provider.MediaStore +import com.atwa.filepicker.decoder.Decoder +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.withContext +import java.io.File +import java.util.concurrent.TimeUnit + +internal class ImageCameraRequest( + private val decoder: Decoder, + private val onPhotoTaken: (Pair?) -> Unit +) : PickerRequest { + + private val outputUri : Uri by lazy { decoder.createCameraOutputUri() } + + override val intent: Intent + get() = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply { + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + putExtra(MediaStore.EXTRA_OUTPUT, outputUri) + } + + + override suspend fun invokeCallback(uri: Uri) { + var result: Pair? = null + decoder.getStorageImage(outputUri).collect { result = it } + withContext(Dispatchers.Main) { + onPhotoTaken(result) + } + } +} \ No newline at end of file