changeset 44:2b91619da650

No cruft file; just use standard file names always and avoid double-saving.
author David Barts <n5jrn@me.com>
date Sun, 11 Apr 2021 20:55:03 -0700
parents 9cb9bb5da247
children 44848342c321
files app/src/main/java/com/bartsent/simpleresizer/EditImage.kt
diffstat 1 files changed, 74 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/app/src/main/java/com/bartsent/simpleresizer/EditImage.kt	Sat Apr 10 17:29:08 2021 -0700
+++ b/app/src/main/java/com/bartsent/simpleresizer/EditImage.kt	Sun Apr 11 20:55:03 2021 -0700
@@ -1,7 +1,6 @@
 package com.bartsent.simpleresizer
 
 import android.Manifest
-import android.content.ContentUris
 import android.content.ContentValues
 import android.content.Intent
 import android.content.pm.PackageManager
@@ -41,8 +40,8 @@
         var uri: Uri? = null
         var bitmap: Bitmap? = null
         var reader: Future<Unit>? = null
-        var permissionsCallback: (() -> Unit)? = null
         var sharable: Boolean = false
+        var savedAs: Uri? = null
     }
     private lateinit var viewModel: State
 
@@ -50,8 +49,6 @@
         sort()
     }
 
-    private val IMAGE_TO_SEND = "simple_resizer_sent_image.jpg"
-
     private lateinit var binding: ActivityEditImageBinding
 
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -246,6 +243,7 @@
                 binding.progressBar.visibility = ProgressBar.INVISIBLE
                 setImage(newBitmap)
                 makeFabulous()
+                viewModel.savedAs = null
             }
         }
     }
@@ -317,6 +315,7 @@
             runOnUiThread {
                 binding.progressBar.visibility = ProgressBar.INVISIBLE
                 setImage(newBitmap)
+                viewModel.savedAs = null
             }
         }
     }
@@ -337,147 +336,101 @@
         viewModel.sharable = false
     }
 
-    private val REQUEST_WRITE_EXTERNAL = 42
+    private val SHARE_OPERATION = 43
+    private val DONE_OPERATION = 77
 
     override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray): Unit {
-        if (requestCode != REQUEST_WRITE_EXTERNAL) {
-            Log.e("EditImage", "unexpected request code in onRequestPermissionsResult!")
-            return
-        }
         if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
-            val cb = viewModel.permissionsCallback
-            if (cb != null) {
-                viewModel.permissionsCallback = null
-                cb()
-            }
+            saveOperation(requestCode)
         } else {
             showError(getString(R.string.error_unable_no_permissions))
         }
     }
 
-    private fun requestWritePermission(): Unit {
-        requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_EXTERNAL)
+    private fun requestWritePermission(requestCode: Int): Unit {
+        requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), requestCode)
+    }
+
+    fun shareClicked(view: View): Unit = saveOperation(SHARE_OPERATION)
+
+    private fun doShare(uri: Uri): Unit  {
+        val shareIntent: Intent = Intent().apply {
+            action = Intent.ACTION_SEND
+            putExtra(Intent.EXTRA_STREAM, uri)
+            type = "image/jpeg"
+        }
+        startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.share_text)))
     }
 
-    private fun needsWritePermission(callback: () -> Unit): Boolean {
+    fun doneClicked(view: View): Unit = saveOperation(DONE_OPERATION)
+
+    private fun doDone(): Unit {
+        unsetImage()
+        makeMundane()
+        finish()
+    }
+
+    private fun doSaveOperation(requestCode: Int, uri: Uri) {
+        when (requestCode) {
+            SHARE_OPERATION -> doShare(uri)
+            DONE_OPERATION -> doDone()
+            else -> Log.e("EditImage", "invalid requestCode: $requestCode")
+        }
+    }
+
+    private fun saveOperation(requestCode: Int): Unit {
+        // Trivial case: no edits since the last save.
+        val savedAs = viewModel.savedAs
+        if (savedAs != null) {
+            doSaveOperation(requestCode, savedAs)
+            return
+        }
+
+        // If we get here, we must save. We might need (but lack)
+        // WRITE_EXTERNAL_STORAGE permission. If so, request it, and arrange to
+        // be called again when it is granted.
         if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.Q) {
             if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
-                viewModel.permissionsCallback = callback
                 if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE))
                     AlertDialog.Builder(this).also {
-                        it.setMessage(
-                            getString(
-                                R.string.permission_needed,
-                                getString(R.string.app_name)
-                            )
-                        )
+                        it.setMessage(getString(R.string.permission_needed, getString(R.string.app_name)))
                         it.setNeutralButton(R.string.ok_text) { dialog, _ ->
                             dialog.dismiss()
-                            requestWritePermission()
+                            requestWritePermission(requestCode)
                         }
                         it.create()
                     }.show()
                 else
-                    requestWritePermission()
-                return true
+                    requestWritePermission(requestCode)
+                return
             }
         }
-        return false
-    }
 
-    fun shareClicked(view: View): Unit {
-        // If we need WRITE_EXTERNAL_STORAGE, request it and bail. We will be called again
-        // (with the permission) if it is granted.
-        if (needsWritePermission({ shareClicked(view) }))
-            return
-
-        // If we get here, we have permission to save (if we need it).
-        val contentValues = makeContentValues(IMAGE_TO_SEND)
-
-        // Delete any old file(s)
-        val cols = arrayOf<String>(MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.MIME_TYPE)
-        val query = StringBuilder().run {
-            for (col in cols) {
-                if (isNotEmpty())
-                    append(" and ")
-                append(col)
-                append(" = ?")
-            }
-            toString()
-        }
-        try {
-            val cursor = contentResolver.query(
-                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-                arrayOf<String>(MediaStore.MediaColumns._ID),
-                query,
-                cols.map { contentValues.getAsString(it) }.toTypedArray(),
-                null)
-            var deleted = 0
-            cursor?.use {
-                // Log.d("EditImage", "${it.count} entries matched")
-                while (it.moveToNext()) {
-                    val uri =
-                        ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, it.getLong(0))
-                    deleted += contentResolver.delete(uri, null, null)
-                }
-            }
-            // Log.d("EditImage", "$deleted entries deleted")
-        } catch (e: Exception) {
-            Log.e("EditImage", "unexpected exception when sharing!", e)
-        }
-
-        // Save new file, use it to share data.
-        saveAs(contentValues) {
-            val shareIntent: Intent = Intent().apply {
-                action = Intent.ACTION_SEND
-                putExtra(Intent.EXTRA_STREAM, it)
-                type = "image/jpeg"
-            }
-            startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.share_text)))
-        }
-    }
-
-    fun doneClicked(view: View): Unit {
-        // If we need WRITE_EXTERNAL_STORAGE, request it and bail. We will be called again
-        // (with the permission) if it is granted.
-        if (needsWritePermission({ doneClicked(view) }))
-            return
-
-        // If we get here, we have permission to save (if we need it).
-        val image = viewModel.bitmap!!
-        var fileName = getFileName(viewModel.uri!!)
-        if (fileName == null) {
-            val d = java.util.Date()
-            fileName = "IMG_%tY%tm%td_%tH%tM%tS".format(d, d, d, d, d, d)
-        }
-        val dot = fileName.lastIndexOf('.')
-        if (dot != -1)
-            fileName = fileName.substring(0, dot)
-        fileName = "${fileName}_${image.width}x${image.height}.jpg"
-        saveAs(makeContentValues(fileName)) {
-            unsetImage()
-            makeMundane()
-            finish()
-        }
-    }
-
-    private fun makeContentValues(fileName: String): ContentValues = ContentValues().apply {
-        put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
-        put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
-            put(MediaStore.MediaColumns.RELATIVE_PATH,
-                File(Environment.DIRECTORY_PICTURES, getString(R.string.app_name)).path)
-        }
-    }
-
-    private fun saveAs(contentValues: ContentValues, callback: (Uri) -> Unit) {
+        // If we get here, we both need to save, and have permission to save.
         val image = viewModel.bitmap!!
         binding.progressBar.visibility = ProgressBar.VISIBLE
         ThreadPools.WORKERS.execute {
+            val contentValues = ContentValues().apply {
+                var fileName = getFileName(viewModel.uri!!)
+                if (fileName == null) {
+                    val d = java.util.Date()
+                    fileName = "IMG_%tY%tm%td_%tH%tM%tS".format(d, d, d, d, d, d)
+                }
+                val dot = fileName.lastIndexOf('.')
+                if (dot != -1)
+                    fileName = fileName.substring(0, dot)
+                fileName = "${fileName}_${image.width}x${image.height}.jpg"
+                put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
+                put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
+                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
+                    put(MediaStore.MediaColumns.RELATIVE_PATH,
+                        File(Environment.DIRECTORY_PICTURES, getString(R.string.app_name)).path)
+                }
+            }
             var errorMessage: String? = null
             val myUri = try {
                 contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
-            } catch(e: Exception) {
+            } catch (e: Exception) {
                 Log.e("EditImage", "unexpected exception when saving!", e)
                 null
             }
@@ -490,9 +443,9 @@
                     throw IOException(getString(R.string.error_get_output))
                 }
                 val quality = maxOf(0, minOf(100,
-                        PreferenceManager.getDefaultSharedPreferences(applicationContext).getInt(
-                                "jpeg_quality", 85)))
-                // Log.d("EditImage", "saving, jpeg_quality = $quality")
+                    PreferenceManager.getDefaultSharedPreferences(applicationContext).getInt(
+                        "jpeg_quality", 85)))
+                Log.d("EditImage", "saving, jpeg_quality = $quality")
                 stream.use {
                     if (!image.compress(Bitmap.CompressFormat.JPEG, quality, it)) {
                         throw IOException(getString(R.string.error_save_bitmap))
@@ -509,7 +462,8 @@
             runOnUiThread {
                 binding.progressBar.visibility = ProgressBar.INVISIBLE
                 if (errorMessage == null) {
-                    callback(myUri!!)
+                    viewModel.savedAs = myUri
+                    doSaveOperation(requestCode, myUri!!)
                 } else {
                     showError(errorMessage)
                 }