comparison app/src/main/java/com/bartsent/simpleresizer/EditImage.kt @ 16:3ed74dc0e34a

Fix error messages, make scaling menu more user-friendly, fix return from settings.
author David Barts <n5jrn@me.com>
date Sun, 21 Feb 2021 21:43:54 -0800
parents 20da616dcda0
children eedf995462d9
comparison
equal deleted inserted replaced
15:20da616dcda0 16:3ed74dc0e34a
16 import android.view.Menu 16 import android.view.Menu
17 import android.view.MenuItem 17 import android.view.MenuItem
18 import android.view.View 18 import android.view.View
19 import android.widget.EditText 19 import android.widget.EditText
20 import android.widget.ProgressBar 20 import android.widget.ProgressBar
21 import android.widget.Toast
21 import androidx.appcompat.app.AlertDialog 22 import androidx.appcompat.app.AlertDialog
22 import androidx.appcompat.app.AppCompatActivity 23 import androidx.appcompat.app.AppCompatActivity
23 import androidx.appcompat.widget.PopupMenu 24 import androidx.appcompat.widget.PopupMenu
24 import com.bartsent.simpleresizer.databinding.ActivityEditImageBinding 25 import com.bartsent.simpleresizer.databinding.ActivityEditImageBinding
25 import com.bartsent.simpleresizer.lib.getScaledInstance 26 import com.bartsent.simpleresizer.lib.getScaledInstance
76 result = uriPath?.substring(uriPath.lastIndexOf('/') + 1) 77 result = uriPath?.substring(uriPath.lastIndexOf('/') + 1)
77 } 78 }
78 return result 79 return result
79 } 80 }
80 81
81 private fun showError(message: String): Unit { 82 private fun showFatalError(message: String): Unit {
82 AlertDialog.Builder(this).also { 83 AlertDialog.Builder(this).also {
83 it.setMessage(message) 84 it.setMessage(message)
84 it.setNeutralButton(R.string.ok_text) { dialog, _ -> 85 it.setNeutralButton(R.string.ok_text) { dialog, _ ->
85 dialog.dismiss() 86 dialog.dismiss()
86 } 87 }
95 super.onResume() 96 super.onResume()
96 97
97 // Read the URI, die if we can't. 98 // Read the URI, die if we can't.
98 val imageUri = intent?.data 99 val imageUri = intent?.data
99 if (imageUri == null) { 100 if (imageUri == null) {
100 showError(getString(R.string.error_no_uri)) 101 if (State.bitmap == null)
102 showFatalError(getString(R.string.error_no_uri))
103 else
104 setImage(State.bitmap!!)
101 return 105 return
102 } 106 }
103 107
104 // Being stateful stops data loss when the phone gets rotated. 108 // Being stateful stops data loss when the phone gets rotated.
105 if (imageUri != State.uri) { 109 if (imageUri != State.uri) {
107 State.bitmap = contentResolver.openInputStream(imageUri).use { 111 State.bitmap = contentResolver.openInputStream(imageUri).use {
108 BitmapFactory.decodeStream(it) 112 BitmapFactory.decodeStream(it)
109 } 113 }
110 } 114 }
111 if (State.bitmap == null) { 115 if (State.bitmap == null) {
112 showError(getString(R.string.error_bad_image)) 116 showFatalError(getString(R.string.error_bad_image))
113 return 117 return
114 } 118 }
115 setImage(State.bitmap!!) 119 setImage(State.bitmap!!)
116 } 120 }
117 121
119 binding.imageSize.text = getString(R.string.image_size_text, image.width, image.height) 123 binding.imageSize.text = getString(R.string.image_size_text, image.width, image.height)
120 binding.image.setImageBitmap(image) 124 binding.image.setImageBitmap(image)
121 State.bitmap = image 125 State.bitmap = image
122 } 126 }
123 127
128 private val CUSTOM = 999998
129 private val CANCEL = 999999
130
124 fun scaleClicked(view: View): Unit { 131 fun scaleClicked(view: View): Unit {
125 val maxSize = State.bitmap!!.run { maxOf(width, height) } 132 val (maxSize, horizontal) = State.bitmap!!.run {
133 if (width > height) Pair(width, true) else Pair(height, false)
134 }
126 PopupMenu(this, view).apply { 135 PopupMenu(this, view).apply {
127 menu.run { 136 menu.run {
128 STDDIMS.filter { it < maxSize }.forEach { add(it.toString()) } 137 STDDIMS.filter { it < maxSize }.forEach { major ->
129 add(getString(R.string.custom_text)) 138 val minor = major * 3 / 4
130 add(getString(R.string.cancel_text)) 139 add(Menu.NONE, major, Menu.NONE,
140 if (horizontal) "$major ✕ $minor" else "$minor ✕ $major")
141 }
142 add(Menu.NONE, CUSTOM, Menu.NONE, R.string.custom_text)
143 add(Menu.NONE, CANCEL, Menu.NONE, R.string.cancel_text)
131 } 144 }
132 setOnMenuItemClickListener(::scaleMenuItemClicked) 145 setOnMenuItemClickListener(::scaleMenuItemClicked)
133 show() 146 show()
134 } 147 }
135 } 148 }
136 149
137 fun scaleMenuItemClicked(item: MenuItem) : Boolean { 150 fun scaleMenuItemClicked(item: MenuItem) : Boolean =
138 val itString = item.title.toString() 151 when (item.itemId) {
139 var itVal = itString.toIntOrNull() 152 CUSTOM -> { showCustomScaleDialog(); true }
140 if (itVal == null) { 153 CANCEL -> true
141 return when (itString) { 154 in STDDIMS -> { doScale(item.itemId); true }
142 getString(R.string.cancel_text) -> true 155 else -> false
143 getString(R.string.custom_text) -> { showCustomScaleDialog(); true } 156 }
144 else -> false
145 }
146 }
147 doScale(itVal)
148 return true
149 }
150 157
151 private fun copyColorSpace(old: Bitmap, new: Bitmap): Unit { 158 private fun copyColorSpace(old: Bitmap, new: Bitmap): Unit {
152 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { 159 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
153 val oldColorSpace = old.colorSpace 160 val oldColorSpace = old.colorSpace
154 if (oldColorSpace != null) 161 if (oldColorSpace != null)
178 setImage(newBitmap) 185 setImage(newBitmap)
179 } 186 }
180 } 187 }
181 } 188 }
182 189
183 // is there any way to remember the last scale value?
184 // if so: should we?
185
186 fun showCustomScaleDialog(): Unit { 190 fun showCustomScaleDialog(): Unit {
187 val image = State.bitmap!! 191 val image = State.bitmap!!
188 val curMaxDim = maxOf(image.width, image.height) 192 val curMaxDim = maxOf(image.width, image.height)
189 val dialogView = layoutInflater.inflate(R.layout.dialog_custom_scale, null) 193 val dialogView = layoutInflater.inflate(R.layout.dialog_custom_scale, null)
190 AlertDialog.Builder(this).also { 194 AlertDialog.Builder(this).also {
191 it.setPositiveButton(R.string.ok_text) { dialog, _ -> 195 it.setPositiveButton(R.string.ok_text) { dialog, _ ->
192 val maxDim = dialogView.findViewById<EditText>(R.id.custom_scale)?.text.toString().toIntOrNull() 196 val maxDim = dialogView.findViewById<EditText>(R.id.custom_scale)?.text.toString().toIntOrNull()
193 dialog.dismiss() 197 dialog.dismiss()
194 if (maxDim == null || maxDim < 8 || maxDim >= curMaxDim) { 198 if (maxDim == null || maxDim < 8 || maxDim >= curMaxDim) {
195 AlertDialog.Builder(this).also { 199 Toast.makeText(applicationContext, R.string.bad_scale, Toast.LENGTH_LONG).show()
196 it.setMessage(R.string.bad_scale)
197 it.setNeutralButton(R.string.ok_text) { dialog, _ ->
198 dialog.dismiss()
199 }
200 it.create()
201 }.show()
202 } else { 200 } else {
203 doScale(maxDim) 201 doScale(maxDim)
204 } 202 }
205 } 203 }
206 it.setNegativeButton(R.string.cancel_text) { dialog, _ -> 204 it.setNegativeButton(R.string.cancel_text) { dialog, _ ->
306 if (!State.bitmap!!.compress(Bitmap.CompressFormat.JPEG, quality, it)) { 304 if (!State.bitmap!!.compress(Bitmap.CompressFormat.JPEG, quality, it)) {
307 throw IOException(getString(R.string.error_save_bitmap)) 305 throw IOException(getString(R.string.error_save_bitmap))
308 } 306 }
309 } 307 }
310 } catch (ioe: IOException) { 308 } catch (ioe: IOException) {
311 showError(ioe.message ?: getString(R.string.error_io)) 309 Toast.makeText(applicationContext, ioe.message ?: getString(R.string.error_io), Toast.LENGTH_LONG).show()
312 } 310 }
313 finish() 311 finish()
314 } 312 }
315 } 313 }