Skip to content

Instantly share code, notes, and snippets.

@zamahaka
Last active October 30, 2021 16:58
Show Gist options
  • Save zamahaka/ecacb7abcd47a1e05dde3fdff7a54d39 to your computer and use it in GitHub Desktop.
Save zamahaka/ecacb7abcd47a1e05dde3fdff7a54d39 to your computer and use it in GitHub Desktop.
// TODO:
// Notify about focus
@Composable
fun CodeInput(
requiredLength: Int,
code: String,
onSymbolSelected: (String) -> Unit,
onDelete: () -> Unit,
) {
// BaseInputConnection
var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = code)) }
val textFieldValue = textFieldValueState.copy(text = code)
val textInputService = LocalTextInputService.current
var textInputSession by remember { mutableStateOf<TextInputSession?>(null) }
val focusRequester = FocusRequester()
val interactionSource = remember { MutableInteractionSource() }
val isFocused by interactionSource.collectIsFocusedAsState()
Log.d(
"myLog",
"CodeInput(requiredLength=$requiredLength, code=$code) { isFocused = $isFocused }",
)
val focusMod = Modifier
.focusRequester(focusRequester)
.onFocusChanged { focusState ->
Log.d("myLog", "onFocusChanged: $focusState")
if (focusState.isFocused) {
textInputSession = textInputService?.startInput(
value = TextFieldValue(text = code),
imeOptions = ImeOptions(
singleLine = true,
autoCorrect = false,
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done,
),
onEditCommand = {
Log.d("myLog", "onEditCommand: $it")
},
onImeActionPerformed = {
Log.d("myLog", "onImeActionPerformed: $it")
}
)
Log.d("myLog", "textInputSession.isOpen: ${textInputSession?.isOpen}")
textInputSession?.showSoftwareKeyboard()
} else {
textInputSession?.hideSoftwareKeyboard()
textInputSession?.dispose()
}
}
.focusable(enabled = true, interactionSource = interactionSource)
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier
.wrapContentSize()
.clickable(
interactionSource = interactionSource,
indication = null,
) {
Log.d("myLog", "clickable")
focusRequester.requestFocus()
if (isFocused) textInputSession?.showSoftwareKeyboard()
}
.then(focusMod)
.onKeyEvent {
Log.d("myLog", "onKeyEvent: $it")
true
}
) {
(0 until requiredLength).rightPadZip(textFieldValue.text.toList()).forEach { (index, symbol) ->
SymbolView(
symbol = symbol,
isSelected = isFocused && index == code.length,
)
}
}
}
@Composable
fun SymbolView(
symbol: Char?,
isSelected: Boolean,
strokeWidth: Dp = dimensionResource(R.dimen.dividerThickness),
) {
val density = LocalDensity.current
val resourceLoader = LocalFontLoader.current
val strokeWidthPx = with(density) { strokeWidth.toPx() }
val color by animateColorAsState(
targetValue = colorResource(if (isSelected) R.color.divideDark else R.color.divideLight02),
)
val style = LocalTextStyle.current.copy(fontSize = 38.sp)
val emWidth = remember(style) {
with(density) {
Paragraph(
text = "M",
style = style,
width = Float.MAX_VALUE,
density = density,
resourceLoader = resourceLoader,
).minIntrinsicWidth.toDp()
}
}
Box(
modifier = Modifier
.wrapContentHeight()
.defaultMinSize(minWidth = emWidth)
.drawBehind {
val y = size.height - strokeWidthPx
drawLine(
color = color,
start = Offset(0f, y),
end = Offset(size.width, y),
strokeWidth = strokeWidthPx,
)
}
) {
Text(
modifier = Modifier.align(Alignment.Center),
text = symbol?.toString() ?: "",
style = style,
)
}
}
@Preview("Empty")
@Composable
fun PreviewEmpty() {
CodeInput(requiredLength = 4, code = "", onSymbolSelected = {}, onDelete = {})
}
@Preview("Some")
@Composable
fun PreviewSome() {
CodeInput(requiredLength = 4, code = "12", onSymbolSelected = {}, onDelete = {})
}
@Preview("Full")
@Composable
fun PreviewFull() {
CodeInput(requiredLength = 4, code = "1234", onSymbolSelected = {}, onDelete = {})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment