Skip to content

Commit

Permalink
Merge pull request #6 from Atwa/feature/gallery_image_picker
Browse files Browse the repository at this point in the history
Implement camera image picker
  • Loading branch information
Atwa authored Oct 30, 2022
2 parents a62f3fd + c307288 commit c2a4927
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 25 deletions.
2 changes: 1 addition & 1 deletion filepicker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ afterEvaluate {

groupId = 'com.github.atwa'
artifactId = 'filepicker'
version = '1.0.4-alpha1'
version = '1.0.4-alpha2'
}
}
repositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,27 @@ import java.lang.ref.WeakReference
internal class StorageFilePicker(private val activity: WeakReference<AppCompatActivity>) : FilePicker {

private lateinit var pickerRequest: PickerRequest
private lateinit var cameraRequest: ImageCameraRequest
private val decoder: Decoder by lazy { UriDecoder(activity.get()?.applicationContext) }

private val filePickerLauncher =
activity.get()?.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
result?.data?.data?.let { processFile(it) }
}

private val cameraCaptureLauncher =
activity.get()?.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
(result.data?.extras?.get("data") as? Bitmap)?.let { processBitmap(it) }
}

override fun pickImage(onImagePicked: (Pair<Bitmap?, File?>?) -> Unit) {
pickerRequest = ImagePickerRequest(decoder, onImagePicked)
initialize()
}

override fun captureCameraImage(onImagePicked: (Pair<Bitmap?, File?>?) -> Unit) {
pickerRequest = ImageCameraRequest(decoder, onImagePicked)
initialize()
cameraRequest = ImageCameraRequest(decoder, onImagePicked)
cameraCaptureLauncher?.launch(cameraRequest.intent)
}

override fun pickPdf(onPdfPicked: (Pair<String?, File?>?) -> Unit) {
Expand All @@ -57,4 +63,10 @@ internal class StorageFilePicker(private val activity: WeakReference<AppCompatAc
}
}

private fun processBitmap(bitmap: Bitmap) {
activity.get()?.lifecycleScope?.launchWhenResumed {
cameraRequest.invokeCameraCallback(bitmap)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ internal interface Decoder {
fun getStorageImage(imageUri: Uri?): Flow<Pair<Bitmap?, File?>?>
fun getStoragePDF(pdfUri: Uri?): Flow<Pair<String?, File>?>
fun getStorageFile(pdfUri: Uri?): Flow<Pair<String?, File>?>
fun createCameraOutputUri() : Uri
fun saveStorageImage(bitmap: Bitmap): Flow<Pair<Bitmap?, File>?>
}
33 changes: 26 additions & 7 deletions filepicker/src/main/java/com/atwa/filepicker/decoder/UriDecoder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import android.net.Uri
import android.provider.OpenableColumns
import com.atwa.filepicker.stream.FileStreamer
import com.atwa.filepicker.stream.Streamer
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.*
import java.nio.ByteBuffer
import java.util.concurrent.TimeUnit


internal class UriDecoder(
private val context: Context?,
private val streamer: Streamer = FileStreamer()
Expand Down Expand Up @@ -60,11 +60,30 @@ internal class UriDecoder(
emit(result)
}

override fun createCameraOutputUri(): Uri {
val timeStamp = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toString()
return Uri.parse("${context?.cacheDir}$timeStamp")
override fun saveStorageImage(bitmap: Bitmap): Flow<Pair<Bitmap?, File>?> = flow {
val result = try {
getFile(bitmap)
} catch (ex: IOException) {
println(ex.message)
null
}
emit(result)
}

private fun getFile(bitmap: Bitmap): Pair<Bitmap, File> {
val fileName = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toString()
val imageFile = File(context?.cacheDir, fileName)

val byteArray = (bitmap.allocationByteCount * bitmap.height).run {
ByteBuffer.allocate(this)
}.apply { bitmap.copyPixelsToBuffer(this) }.array()

val byteStream = ByteArrayInputStream(byteArray)
val outputStream = FileOutputStream(imageFile)

streamer.copyFile(byteStream, outputStream)
return Pair(bitmap, imageFile)
}

private fun getBitMap(): Pair<Bitmap?, File?>? {
return uri?.let { uri ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,24 @@ 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<Bitmap?, File?>?) -> Unit
) : PickerRequest {
) {

private val outputUri : Uri by lazy { decoder.createCameraOutputUri() }
val intent: Intent
get() = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

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) {
suspend fun invokeCameraCallback(bitmap: Bitmap) {
var result: Pair<Bitmap?, File?>? = null
decoder.getStorageImage(outputUri).collect { result = it }
decoder.saveStorageImage(bitmap).collect { result = it }
withContext(Dispatchers.Main) {
onPhotoTaken(result)
}
Expand Down

0 comments on commit c2a4927

Please sign in to comment.