Skip to content

Instantly share code, notes, and snippets.

View root-ansh's full-sized avatar
🔍
curiously exploring problems and their solutions

Ansh Sachdeva root-ansh

🔍
curiously exploring problems and their solutions
View GitHub Profile
// converts any uri(content/file) to a local temp file first in cache directory for easy read/write
suspend fun Uri.toLocalFile(context: Context,localFileLocation:File = context.cacheDir): File? {
val uri = this
return withContext(Dispatchers.IO) {
try {
val fileInfo = FileInfo.fromSAFUri(context,uri)
val fileName = fileInfo?.nameWithExtension?: "${System.currentTimeMillis()}.bin"
val tempFile = File(localFileLocation, fileName)
context.contentResolver.openInputStream(uri)?.use { inputStream ->
FileOutputStream(tempFile).use { outputStream ->
data class FileInfo(
val nameWithExtension: String,
val extension: String?,
val mimeType: String?,
val size: Long?,
val sizeFormatted: String?,
val createdOn: Long?,
val modifiedOn: Long?,
val originalLocationPath: String?
){
private val saveFileToSystemSAF: ActivityResultLauncher<String> = registerForActivityResult(CreateDocument(mimeType = "*/*")) { result -> // or mimeType = "application/pdf" / "image/*"
val uri = result
val file = state.fileToBeSaved // the file/bitmap that needs to be writteen to user selected uri
val context = this
if (uri!=null && file!=null){
lifecycleScope.launch {
context.saveFileToUserSelectedPath(uri,file) // writing file to user selected uri
Snackbar
.make(binding.root,"Saved file :${file.name} to user selected directory", Snackbar.LENGTH_SHORT)
.setAction("show"){context.openSystemViewerForSAFUri(uri)} //check next section for info on this
state = state.copy(fileToBeSaved = state.mediaFile) // state.copy(bitmapToBeSaved = getCurrentImageViewBitmap())
saveFileToSystemSAF.launch("MyFile.pdf")
lifecycleScope.launch {
val uri = context.saveBitmapToUserMemory(getCurrentImageViewBitmap())
val uri = context.saveFileToUserMemory(file)
Snackbar
.make(binding.root,"Saved file :currentlyVisibleImage to downloads", Snackbar.LENGTH_SHORT)
.setAction("show"){context.openSystemViewerForSAFUri(uri)} //check next section for info on this
.show()
}
private fun getCurrentImageViewBitmap(): Bitmap{
val drawable = binding.imagePreviewPlaceholder.drawable
val bitmap = if (drawable is BitmapDrawable) {
drawable.bitmap
} else {
val bitmap = createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
bitmap
fun File.imageFileToBitmap(): Bitmap? { // wont work for content uri files. first create to local file
val localNonSAFFile = this
return if (localNonSAFFile.exists()) {
BitmapFactory.decodeFile(localNonSAFFile.absolutePath)
} else {
null
}
}
@Throws
suspend fun Context.saveFileToUserSelectedPath(uri: Uri, sourceFile: File): Uri {
return withContext(Dispatchers.IO) {
contentResolver.openOutputStream(uri)?.use { outputStream ->
sourceFile.inputStream().use { inputStream ->
inputStream.copyTo(outputStream)
}
}
uri
}
@Throws
suspend fun Context.saveFileToUserMemory(
sourceFile: File,
targetDirectory: String = Environment.DIRECTORY_DOWNLOADS
): Uri {
return withContext(Dispatchers.IO){
if (!sourceFile.exists()) error("Source file does not exist")
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.Q) error("Saving to public directories is only supported on Android Q and above")
val extension = sourceFile.extension.lowercase()
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) ?: "application/octet-stream"
fun Context.openSystemViewerForSAFUri(uri: Uri?) {
uri?:return
val mimeType1 = FileInfo.fromSAFUri(this,uri)?.mimeType
val extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString())
val mimeType2 = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.lowercase())
val mimeType3 = "*/*"
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, mimeType1?:mimeType2?:mimeType3)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}