Introduce DialogState.awaitInputText
This commit is contained in:
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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user