fun savePictures(contentResolver: ContentResolver, uris: Array<String>, onUploaded: (ArrayList<String>) -> Unit) {
timeStart = System.currentTimeMillis() / 1000
val storage = FirebaseStorage.getInstance()
val resultUris = mutableMapOf<Int, String>()
val tasks = mutableMapOf<Int, Task<Uri>>()
uris.forEachIndexed { position, path ->
if (isInStorageAlready(path)) {
resultUris[position] = path
} else {
val uri = Uri.parse(path)
val bytes = MediaStore.Images.Media.getBitmap(contentResolver, uri)
.scaleDown(800f, false)
.modifyOrientation(contentResolver, uri)
.compress(80)
val imageRef = storage.getReference(filePath).child(uri.lastPathSegment)
val uploadTask = imageRef.putStream(ByteArrayInputStream(bytes))
val urlTask = uploadTask.continueWithTask<Uri> { task ->
task.exception?.let {
throw it
}
imageRef.downloadUrl
}
// one approach is to use this callback here to get result uris
.addOnCompleteListener { task ->
if (task.isSuccessful) {
resultUris[position] = task.result?.toString() ?: ""
Log.d(_tag, "savePictures, onComplete, upload uri: ${task.result?.toString() ?: ""}")
} else {
task.exception?.printStackTrace()
}
}
// tasks[position] = uploadTask
tasks[position] = urlTask
}
}
Log.d(_tag, "savePictures, resultUris: $resultUris (size: ${resultUris.size}), tasks: $tasks")
Tasks.whenAll(tasks.values).addOnCompleteListener { allTask ->
if (allTask.isSuccessful) {
tasks.entries.forEach { (index, task) ->
// another one is to use this callback here to get result uris
// resultUris[index] = task.result.toString()
Log.d(_tag, "savePictures whenAll, upload uri: ${task.result?.toString() ?: ""}, index: $index")
}
val time = System.currentTimeMillis() / 1000 - timeStart
val list = resultUris.toSortedMap().map { (_, value) -> value }
Log.d(_tag, "savePictures, resultUris: $resultUris, list: $list, time: $time")
onUploaded(ArrayList(list))
} else {
val e = allTask.exception
e?.printStackTrace()
}
}
}
private fun removeOldPicFromFireStorage() {
if (category.picPath.isEmpty()) return
val picName = extractNameFromPath(category.picPath)
val picPath = "categories/$site/$picName"
val storageRef = storage.getReference(picPath)
storageRef.delete().addOnSuccessListener {
Log.d("Category", "onSuccess() removing file: ${category.picPath}")
}.addOnFailureListener { ex ->
val errorCode = (ex as? StorageException)?.errorCode
val errorMessage = ex.message
Log.d("Category", "onFailure() removing file: ${category.picPath}, errorCode: $errorCode, message: $errorMessage")
Log.d("Category", "onFailure() fileName: $picName")
Snackbar.make(root, R.string.error_message, Snackbar.LENGTH_SHORT).show()
}
}
private fun extractNameFromPath(picPath: String): String {
val decodedUrl = URLDecoder.decode(picPath, "UTF-8")
val path = URL(decodedUrl).path
return File(path).name
}
private fun uploadPicToFireStorage() {
// show spinner
val progressDialog = progressDialog(getString(R.string.dialog_saving))
progressDialog.show()
// optimize an image
val bytes = MediaStore.Images.Media.getBitmap(this.contentResolver, selectedImageUri)
.scaleDown(800f, false)
.compress(80)
// save image to Ferebase Storage
val picName = "img_${UUID.randomUUID()}.jpg"
val picPath = "categories/$site/$picName"
val storageRef = storage.getReference(picPath)
val uploadTask = storageRef.putBytes(bytes)
uploadTask.addOnSuccessListener(this) { snap ->
progressDialog.dismiss()
category.picPath = snap.downloadUrl?.toString() ?: ""
saveCategoryToFireDb()
}.addOnFailureListener(this) { ex ->
progressDialog.dismiss()
val errorCode = (ex as? StorageException)?.errorCode
val errorMessage = ex.message
Log.d("Category", "onFailure() uploading file: $picPath, errorCode: $errorCode, message: $errorMessage")
Snackbar.make(root, R.string.error_message, Snackbar.LENGTH_SHORT).show()
}
}