HeliBoard/app/src/main/java/helium314/keyboard/settings/dialogs/TextInputDialog.kt

97 lines
3.6 KiB
Kotlin
Raw Normal View History

// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings.dialogs
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.window.DialogProperties
// mostly taken from StreetComplete / SCEE
/** Dialog with which to input text. OK button is only clickable if [checkTextValid] returns true. */
@Composable
fun TextInputDialog(
onDismissRequest: () -> Unit,
onConfirmed: (text: String) -> Unit,
modifier: Modifier = Modifier,
title: @Composable (() -> Unit)? = null,
onNeutral: () -> Unit = { },
neutralButtonText: String? = null,
confirmButtonText: String = stringResource(android.R.string.ok),
initialText: String = "",
textInputLabel: @Composable (() -> Unit)? = null,
singleLine: Boolean = true,
keyboardType: KeyboardType = KeyboardType.Unspecified,
properties: DialogProperties = DialogProperties(),
2025-02-15 13:30:48 +01:00
reducePadding: Boolean = false,
checkTextValid: (text: String) -> Boolean = { it.isNotBlank() }
) {
val focusRequester = remember { FocusRequester() }
// crappy workaround because otherwise we get a disappearing dialog and a crash
// but doesn't work perfectly, dialog doesn't nicely show up again...
// todo: understand why it works in ExpandableSearchField, but not here
var done by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(initialText) {
if (done) return@LaunchedEffect
focusRequester.requestFocus()
done = true
}
var value by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue(initialText, selection = TextRange(if (singleLine) initialText.length else 0)))
}
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
onConfirmed = { onConfirmed(value.text) },
confirmButtonText = confirmButtonText,
checkOk = { checkTextValid(value.text) },
neutralButtonText = neutralButtonText,
2025-02-09 14:36:01 +01:00
onNeutral = { onDismissRequest(); onNeutral() },
modifier = modifier,
title = title,
text = {
OutlinedTextField(
value = value,
onValueChange = { value = it },
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester),
label = textInputLabel,
keyboardOptions = KeyboardOptions(keyboardType = keyboardType),
singleLine = singleLine
)
},
2025-02-15 13:30:48 +01:00
properties = properties,
reducePadding = reducePadding,
)
}
@Preview
@Composable
private fun Preview() {
TextInputDialog(
onDismissRequest = {},
onConfirmed = {},
title = { Text("Title") },
initialText = "some text\nand another line",
singleLine = false,
textInputLabel = { Text("fill it") }
)
}