97 lines
3.1 KiB
Kotlin
97 lines
3.1 KiB
Kotlin
package jp.juggler.subwaytooter.dialog
|
|
|
|
import android.app.Dialog
|
|
import androidx.appcompat.app.AppCompatActivity
|
|
import androidx.lifecycle.lifecycleScope
|
|
import jp.juggler.subwaytooter.databinding.DlgSuspendProgressBinding
|
|
import jp.juggler.util.coroutine.AppDispatchers
|
|
import jp.juggler.util.log.LogCategory
|
|
import jp.juggler.util.ui.dismissSafe
|
|
import jp.juggler.util.ui.vg
|
|
import kotlinx.coroutines.CancellationException
|
|
import kotlinx.coroutines.channels.ClosedReceiveChannelException
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
import kotlinx.coroutines.launch
|
|
|
|
private val log = LogCategory("SuspendProgress")
|
|
|
|
class SuspendProgress(val activity: AppCompatActivity) {
|
|
|
|
private val views = DlgSuspendProgressBinding.inflate(activity.layoutInflater)
|
|
private val dialog = Dialog(activity)
|
|
|
|
suspend fun <T : Any?> run(
|
|
message: String,
|
|
title: String,
|
|
cancellable: Boolean,
|
|
block: suspend (Reporter) -> T,
|
|
): T = Reporter().use { reporter ->
|
|
try {
|
|
dialog.setContentView(views.root)
|
|
reporter.setMessage(message)
|
|
reporter.setTitle(title)
|
|
dialog.setCancelable(cancellable)
|
|
dialog.setCanceledOnTouchOutside(cancellable)
|
|
dialog.show()
|
|
block(reporter)
|
|
} finally {
|
|
dialog.dismissSafe()
|
|
}
|
|
}
|
|
|
|
inner class Reporter : AutoCloseable {
|
|
private val flowMessage = MutableStateFlow<CharSequence>("")
|
|
private val flowTitle = MutableStateFlow<CharSequence>("")
|
|
|
|
private val jobMessage = activity.lifecycleScope.launch(AppDispatchers.MainImmediate) {
|
|
try {
|
|
flowMessage.collect {
|
|
views.tvMessage.vg(it.isNotEmpty())?.text = it
|
|
}
|
|
} catch (ex: Throwable) {
|
|
when (ex) {
|
|
is CancellationException, is ClosedReceiveChannelException -> Unit
|
|
else -> log.w(ex, "error.")
|
|
}
|
|
}
|
|
}
|
|
private val jobTitle = activity.lifecycleScope.launch(AppDispatchers.MainImmediate) {
|
|
try {
|
|
flowTitle.collect {
|
|
views.tvTitle.vg(it.isNotEmpty())?.text = it
|
|
}
|
|
} catch (ex: Throwable) {
|
|
when (ex) {
|
|
is CancellationException, is ClosedReceiveChannelException -> Unit
|
|
else -> log.w(ex, "error.")
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun close() {
|
|
jobMessage.cancel()
|
|
jobTitle.cancel()
|
|
}
|
|
|
|
fun setMessage(msg: CharSequence) {
|
|
flowMessage.value = msg
|
|
}
|
|
|
|
fun setTitle(title: CharSequence) {
|
|
flowTitle.value = title
|
|
}
|
|
}
|
|
}
|
|
|
|
suspend fun <T : Any?> AppCompatActivity.runInProgress(
|
|
message: String = "please wait…",
|
|
title: String = "",
|
|
cancellable: Boolean = true,
|
|
block: suspend (SuspendProgress.Reporter) -> T,
|
|
): T = SuspendProgress(this).run(
|
|
message = message,
|
|
title = title,
|
|
cancellable = cancellable,
|
|
block = block
|
|
)
|