Skip to content

Commit c2a4927

Browse files
authored
Merge pull request #6 from Atwa/feature/gallery_image_picker
Implement camera image picker
2 parents a62f3fd + c307288 commit c2a4927

File tree

5 files changed

+47
-25
lines changed

5 files changed

+47
-25
lines changed

filepicker/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ afterEvaluate {
4444

4545
groupId = 'com.github.atwa'
4646
artifactId = 'filepicker'
47-
version = '1.0.4-alpha1'
47+
version = '1.0.4-alpha2'
4848
}
4949
}
5050
repositories {

filepicker/src/main/java/com/atwa/filepicker/core/StorageFilePicker.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,27 @@ import java.lang.ref.WeakReference
2020
internal class StorageFilePicker(private val activity: WeakReference<AppCompatActivity>) : FilePicker {
2121

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

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

31+
private val cameraCaptureLauncher =
32+
activity.get()?.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
33+
(result.data?.extras?.get("data") as? Bitmap)?.let { processBitmap(it) }
34+
}
35+
3036
override fun pickImage(onImagePicked: (Pair<Bitmap?, File?>?) -> Unit) {
3137
pickerRequest = ImagePickerRequest(decoder, onImagePicked)
3238
initialize()
3339
}
3440

3541
override fun captureCameraImage(onImagePicked: (Pair<Bitmap?, File?>?) -> Unit) {
36-
pickerRequest = ImageCameraRequest(decoder, onImagePicked)
37-
initialize()
42+
cameraRequest = ImageCameraRequest(decoder, onImagePicked)
43+
cameraCaptureLauncher?.launch(cameraRequest.intent)
3844
}
3945

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

66+
private fun processBitmap(bitmap: Bitmap) {
67+
activity.get()?.lifecycleScope?.launchWhenResumed {
68+
cameraRequest.invokeCameraCallback(bitmap)
69+
}
70+
}
71+
6072
}

filepicker/src/main/java/com/atwa/filepicker/decoder/Decoder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ internal interface Decoder {
99
fun getStorageImage(imageUri: Uri?): Flow<Pair<Bitmap?, File?>?>
1010
fun getStoragePDF(pdfUri: Uri?): Flow<Pair<String?, File>?>
1111
fun getStorageFile(pdfUri: Uri?): Flow<Pair<String?, File>?>
12-
fun createCameraOutputUri() : Uri
12+
fun saveStorageImage(bitmap: Bitmap): Flow<Pair<Bitmap?, File>?>
1313
}

filepicker/src/main/java/com/atwa/filepicker/decoder/UriDecoder.kt

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ import android.net.Uri
99
import android.provider.OpenableColumns
1010
import com.atwa.filepicker.stream.FileStreamer
1111
import com.atwa.filepicker.stream.Streamer
12+
import kotlinx.coroutines.flow.Flow
1213
import kotlinx.coroutines.flow.flow
13-
import java.io.File
14-
import java.io.FileInputStream
15-
import java.io.FileOutputStream
16-
import java.io.IOException
14+
import java.io.*
15+
import java.nio.ByteBuffer
1716
import java.util.concurrent.TimeUnit
1817

18+
1919
internal class UriDecoder(
2020
private val context: Context?,
2121
private val streamer: Streamer = FileStreamer()
@@ -60,11 +60,30 @@ internal class UriDecoder(
6060
emit(result)
6161
}
6262

63-
override fun createCameraOutputUri(): Uri {
64-
val timeStamp = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toString()
65-
return Uri.parse("${context?.cacheDir}$timeStamp")
63+
override fun saveStorageImage(bitmap: Bitmap): Flow<Pair<Bitmap?, File>?> = flow {
64+
val result = try {
65+
getFile(bitmap)
66+
} catch (ex: IOException) {
67+
println(ex.message)
68+
null
69+
}
70+
emit(result)
6671
}
6772

73+
private fun getFile(bitmap: Bitmap): Pair<Bitmap, File> {
74+
val fileName = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()).toString()
75+
val imageFile = File(context?.cacheDir, fileName)
76+
77+
val byteArray = (bitmap.allocationByteCount * bitmap.height).run {
78+
ByteBuffer.allocate(this)
79+
}.apply { bitmap.copyPixelsToBuffer(this) }.array()
80+
81+
val byteStream = ByteArrayInputStream(byteArray)
82+
val outputStream = FileOutputStream(imageFile)
83+
84+
streamer.copyFile(byteStream, outputStream)
85+
return Pair(bitmap, imageFile)
86+
}
6887

6988
private fun getBitMap(): Pair<Bitmap?, File?>? {
7089
return uri?.let { uri ->

filepicker/src/main/java/com/atwa/filepicker/request/ImageCameraRequest.kt

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,24 @@ package com.atwa.filepicker.request
22

33
import android.content.Intent
44
import android.graphics.Bitmap
5-
import android.net.Uri
6-
import android.os.Environment
75
import android.provider.MediaStore
86
import com.atwa.filepicker.decoder.Decoder
97
import kotlinx.coroutines.Dispatchers
108
import kotlinx.coroutines.flow.collect
119
import kotlinx.coroutines.withContext
1210
import java.io.File
13-
import java.util.concurrent.TimeUnit
1411

1512
internal class ImageCameraRequest(
1613
private val decoder: Decoder,
1714
private val onPhotoTaken: (Pair<Bitmap?, File?>?) -> Unit
18-
) : PickerRequest {
15+
) {
1916

20-
private val outputUri : Uri by lazy { decoder.createCameraOutputUri() }
17+
val intent: Intent
18+
get() = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
2119

22-
override val intent: Intent
23-
get() = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
24-
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
25-
putExtra(MediaStore.EXTRA_OUTPUT, outputUri)
26-
}
27-
28-
29-
override suspend fun invokeCallback(uri: Uri) {
20+
suspend fun invokeCameraCallback(bitmap: Bitmap) {
3021
var result: Pair<Bitmap?, File?>? = null
31-
decoder.getStorageImage(outputUri).collect { result = it }
22+
decoder.saveStorageImage(bitmap).collect { result = it }
3223
withContext(Dispatchers.Main) {
3324
onPhotoTaken(result)
3425
}

0 commit comments

Comments
 (0)