SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgFocusPoint.kt

115 lines
3.7 KiB
Kotlin

package jp.juggler.subwaytooter.dialog
import android.app.Dialog
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import jp.juggler.subwaytooter.api.*
import jp.juggler.subwaytooter.api.entity.TootAttachment
import jp.juggler.subwaytooter.databinding.DlgFocusPointBinding
import jp.juggler.util.*
import jp.juggler.util.coroutine.launchMain
import jp.juggler.util.data.*
import jp.juggler.util.log.*
import jp.juggler.util.ui.*
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
private val log = LogCategory("DlgFocusPoint")
fun decodeAttachmentBitmap(
data: ByteArray,
@Suppress("SameParameterValue") pixelMax: Int,
): Bitmap? {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
options.inScaled = false
options.outWidth = 0
options.outHeight = 0
BitmapFactory.decodeByteArray(data, 0, data.size, options)
var w = options.outWidth
var h = options.outHeight
if (w <= 0 || h <= 0) {
log.e("can't decode bounds.")
return null
}
var bits = 0
while (w > pixelMax || h > pixelMax) {
++bits
w = w shr 1
h = h shr 1
}
options.inJustDecodeBounds = false
options.inSampleSize = 1 shl bits
return BitmapFactory.decodeByteArray(data, 0, data.size, options)
}
suspend fun AppCompatActivity.focusPointDialog(
attachment: TootAttachment,
callback: suspend (x: Float, y: Float) -> Boolean,
) {
var bitmap: Bitmap? = null
try {
val url = attachment.preview_url
if (url == null) {
showToast(false, "missing preview_url")
return
}
val result = runApiTask { client ->
try {
val (result, data) = client.getHttpBytes(url)
data?.let {
bitmap = decodeAttachmentBitmap(it, 1024)
?: return@runApiTask TootApiResult("image decode failed.")
}
result
} catch (ex: Throwable) {
TootApiResult(ex.withCaption("preview loading failed."))
}
}
result ?: return
if (bitmap == null) {
showToast(true, result.error ?: "error")
return
} else if (!isLiveActivity) {
return
}
val dialog = Dialog(this)
val views = DlgFocusPointBinding.inflate(layoutInflater)
dialog.setContentView(views.root)
views.ivFocus.setAttachment(attachment, bitmap!!)
dialog.window?.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
views.btnCancel.setOnClickListener {
dialog.dismissSafe()
}
views.btnOk.setOnClickListener {
launchMain {
try {
if (callback(views.ivFocus.focusX, views.ivFocus.focusY)) {
dialog.dismissSafe()
}
} catch (ex: Throwable) {
showToast(ex, "can't set focus point.")
}
}
}
// dialogが閉じるまで待ってからbitmapをリサイクルする
suspendCancellableCoroutine { cont ->
dialog.setOnDismissListener {
if (cont.isActive) cont.resume(Unit)
}
cont.invokeOnCancellation {
dialog.dismissSafe()
}
dialog.show()
}
} finally {
bitmap?.recycle()
bitmap = null
}
}