Introduce DialogState.awaitInputText

This commit is contained in:
tarsin committed 2023-08-02 10:14:41 +08:00
1 parent 39b896e1b9
commit 1bfda83665
3 files changed
+88 -44

No files matched your search

@@ -144,7 +144,6 @@ import com.hippo.ehviewer.ui.addToFavorites
import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder
import com.hippo.ehviewer.ui.legacy.CheckBoxDialogBuilder
import com.hippo.ehviewer.ui.legacy.CoilImageGetter
import com.hippo.ehviewer.ui.legacy.EditTextDialogBuilder
import com.hippo.ehviewer.ui.legacy.GalleryRatingBar.OnUserRateListener
import com.hippo.ehviewer.ui.legacy.calculateSuitableSpanCount
import com.hippo.ehviewer.ui.main.EhPreviewItem
@@ -361,16 +360,13 @@ class GalleryDetailScene : BaseScene() {
showTip(R.string.sign_in_first, LENGTH_LONG)
return
}
val builder =
EditTextDialogBuilder(requireContext(), "", getString(R.string.action_add_tag_tip))
builder.setPositiveButton(android.R.string.ok, null)
val dialog = builder.setTitle(R.string.action_add_tag)
.show()
dialog.getButton(DialogInterface.BUTTON_POSITIVE)
.setOnClickListener {
voteTag(builder.text.trim { it <= ' ' }, 1)
dialog.dismiss()
}
lifecycleScope.launchIO {
val text = dialogState.awaitInputText(
title = getString(R.string.action_add_tag),
hint = getString(R.string.action_add_tag_tip),
)
voteTag(text.trim(), 1)
}
}
override fun onCreateView(
@@ -20,7 +20,6 @@ import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.os.Parcelable
import android.text.InputType
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
@@ -628,31 +627,31 @@ class GalleryListScene : SearchBarScene() {
}
private fun showGoToDialog() {
val context = context ?: return
mAdapter ?: return
if (mIsTopList) {
val page = 1
val pages = 200
val hint = getString(R.string.go_to_hint, page, pages)
val builder = EditTextDialogBuilder(context, null, hint)
builder.editText.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
val dialog = builder.setTitle(R.string.go_to).setPositiveButton(android.R.string.ok, null).show()
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
val text = builder.text.trim { it <= ' ' }
val goTo: Int = try {
text.toInt() - 1
} catch (e: NumberFormatException) {
builder.setError(getString(R.string.error_invalid_number))
return@setOnClickListener
}
if (goTo < 0 || goTo >= pages) {
builder.setError(getString(R.string.error_out_of_range))
return@setOnClickListener
}
builder.setError(null)
mUrlBuilder.setJumpTo(goTo.toString())
val title = getString(R.string.go_to)
val hint = getString(R.string.go_to_hint, 1, 200)
lifecycleScope.launch {
val text = dialogState.awaitInputText(
title = title,
hint = hint,
isNumber = true,
) { oriText ->
val text = oriText.trim()
val goTo = runCatching {
text.toInt() - 1
}.onFailure {
return@awaitInputText getString(R.string.error_invalid_number)
}.getOrThrow()
if (goTo < 0 || goTo >= pages) {
getString(R.string.error_out_of_range)
} else {
null
}
}.trim().toInt() - 1
mUrlBuilder.setJumpTo(text.toString())
mAdapter?.refresh()
dialog.dismiss()
}
} else {
val local = LocalDateTime.of(2007, 3, 21, 0, 0)
@@ -14,8 +14,10 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Info
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.AlertDialogDefaults
import androidx.compose.material3.Icon
@@ -23,6 +25,7 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.ShapeDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
@@ -43,8 +46,10 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.jamal.composeprefs3.ui.ifNotNullThen
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
@@ -69,20 +74,23 @@ class DialogState {
suspend inline fun <R> dialog(crossinline block: @Composable (CancellableContinuation<R>) -> Unit) = suspendCancellableCoroutine<R> { cont ->
cont.invokeOnCancellation { dismiss() }
content = { block(cont) }
val realContinuation = object : CancellableContinuation<R> by cont {
override fun resumeWith(result: Result<R>) {
dismiss()
cont.resumeWith(result)
}
}
content = { block(realContinuation) }
}
suspend fun <R> show(initial: R, @StringRes title: Int? = null, block: @Composable DialogScope<R>.() -> Unit): R {
suspend fun <R> awaitResult(initial: R, @StringRes title: Int? = null, block: @Composable DialogScope<R>.() -> Unit): R {
return dialog { cont ->
val state = remember(cont) { mutableStateOf(initial) }
val impl = remember(cont) { object : DialogScope<R> { override var expectedValue by state } }
AlertDialog(
onDismissRequest = { cont.cancel() },
confirmButton = {
TextButton(onClick = {
dismiss()
cont.resume(state.value)
}) {
TextButton(onClick = { cont.resume(state.value) }) {
Text(text = stringResource(id = android.R.string.ok))
}
},
@@ -92,6 +100,51 @@ class DialogState {
}
}
suspend fun awaitInputText(
initial: String = "",
title: String? = null,
hint: String? = null,
isNumber: Boolean = false,
invalidator: ((String) -> String?)? = null,
): String {
return dialog { cont ->
var state by remember(cont) { mutableStateOf(initial) }
var error by remember(cont) { mutableStateOf<String?>(null) }
AlertDialog(
onDismissRequest = { cont.cancel() },
confirmButton = {
TextButton(onClick = {
error = invalidator?.invoke(state)
error ?: cont.resume(state)
}) {
Text(text = stringResource(id = android.R.string.ok))
}
},
title = title?.let { { Text(text = title) } },
text = {
OutlinedTextField(
value = state,
onValueChange = { state = it },
label = hint.ifNotNullThen {
Text(text = hint!!)
},
trailingIcon = error.ifNotNullThen {
Icon(
imageVector = Icons.Filled.Info,
contentDescription = null,
)
},
supportingText = error.ifNotNullThen {
Text(text = error!!)
},
isError = error != null,
keyboardOptions = if (isNumber) KeyboardOptions(keyboardType = KeyboardType.Number) else KeyboardOptions.Default,
)
},
)
}
}
suspend fun awaitPermissionOrCancel(
@StringRes confirmText: Int? = null,
@StringRes dismissText: Int? = null,
@@ -102,10 +155,7 @@ class DialogState {
AlertDialog(
onDismissRequest = { cont.cancel() },
confirmButton = {
TextButton(onClick = {
dismiss()
cont.resume(Unit)
}) {
TextButton(onClick = { cont.resume(Unit) }) {
Text(text = stringResource(id = confirmText ?: android.R.string.ok))
}
},
@@ -126,7 +176,6 @@ class DialogState {
return dialog { cont ->
val impl = remember(cont) {
DismissDialogScope<R> {
dismiss()
cont.resume(it)
}
}