Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ private const val NOT_ENTERED_VALUE = '₺'
* Whenever the user edits the text, [onValueChange] is called with the most up to date state
* including the empty values that represented by [OhTeePeeConfigurations.placeHolder].
*
* When the user fills all the cells, [onValueChange]'s isValid parameter will be `true`,
* When the user fills all the cells, [onValueChange]'s isValid parameter will be `true`
* (if the [OhTeePeeConfigurations.checkValidOnLastCellInput] is `false` or if the last cell is just filled),
* otherwise it will be `false`.
*
* To customize the appearance of cells you can pass [configurations] parameter with
Expand Down Expand Up @@ -180,6 +181,7 @@ fun OhTeePeeInput(
horizontalArrangement = horizontalArrangement,
onCellInputChange = { currentCellIndex, newValue ->
handleCellInputChange(
checkValidOnLastCellInput = configurations.checkValidOnLastCellInput,
otpValueCharArray = otpValueCharArray,
currentCellIndex = currentCellIndex,
newValue = newValue,
Expand Down Expand Up @@ -280,6 +282,7 @@ private fun getOtpValueCharArray(
}

private fun handleCellInputChange(
checkValidOnLastCellInput: Boolean,
otpValueCharArray: CharArray,
currentCellIndex: Int,
newValue: String,
Expand All @@ -304,20 +307,26 @@ private fun handleCellInputChange(
return
}

var focusTargetIndex: Int? = null
if (formattedNewValue.isNotEmpty()) {
otpValueCharArray[currentCellIndex] = formattedNewValue.last()
moveFocus(currentCellIndex, currentCellIndex + 1)
focusTargetIndex = currentCellIndex + 1
moveFocus(currentCellIndex, focusTargetIndex)
} else if (currentCellText != NOT_ENTERED_VALUE.toString()) {
otpValueCharArray[currentCellIndex] = NOT_ENTERED_VALUE
} else {
val previousIndex = (currentCellIndex - 1).coerceIn(0, cellsCount)
otpValueCharArray[previousIndex] = NOT_ENTERED_VALUE
moveFocus(currentCellIndex, previousIndex)
focusTargetIndex = (currentCellIndex - 1).coerceIn(0, cellsCount)
otpValueCharArray[focusTargetIndex] = NOT_ENTERED_VALUE
moveFocus(currentCellIndex, focusTargetIndex)
}
val otpValueAsString = otpValueCharArray.joinToString(String.EMPTY) {
if (it == NOT_ENTERED_VALUE) " " else it.toString()
}
onValueChange(otpValueAsString, otpValueAsString.none { it == placeHolderAsChar })
onValueChange(
otpValueAsString,
otpValueAsString.none { it == placeHolderAsChar }
&& (!checkValidOnLastCellInput || focusTargetIndex == cellsCount),
)
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ private const val DEFAULT_PLACE_HOLDER = " "
* @param errorCellConfig [OhTeePeeCellConfiguration] cell ui configuration when an error occurred.
* @param emptyCellConfig [OhTeePeeCellConfiguration] cell ui configuration when it's empty & not focused.
* @param filledCellConfig [OhTeePeeCellConfiguration] cell ui configuration when it's filled.
* @param checkValidOnLastCellInput when set to `true`, the valid input value will be checked only
* when the last cell is filled.
* @param clearInputOnError when set to `true`, the input will be cleared and the focus will be reset to the first char
* when an error occurred.
* @param enableBottomLine when set to `true`, a bottom line will be drawn for each
Expand All @@ -55,6 +57,7 @@ data class OhTeePeeConfigurations(
val errorCellConfig: OhTeePeeCellConfiguration,
val emptyCellConfig: OhTeePeeCellConfiguration,
val filledCellConfig: OhTeePeeCellConfiguration,
val checkValidOnLastCellInput: Boolean,
val clearInputOnError: Boolean,
val enableBottomLine: Boolean,
val errorAnimationConfig: OhTeePeeErrorAnimationConfig?,
Expand All @@ -77,6 +80,7 @@ data class OhTeePeeConfigurations(
elevation: Dp = 0.dp,
cursorColor: Color = Color.Transparent,
clearInputOnError: Boolean = true,
checkValidOnLastCellInput: Boolean = false,
enableBottomLine: Boolean = false,
obscureText: String = String.EMPTY,
placeHolder: String = DEFAULT_PLACE_HOLDER,
Expand All @@ -89,6 +93,7 @@ data class OhTeePeeConfigurations(
emptyCellConfig = emptyCellConfig,
filledCellConfig = filledCellConfig,
cursorColor = cursorColor,
checkValidOnLastCellInput = checkValidOnLastCellInput,
clearInputOnError = clearInputOnError,
enableBottomLine = enableBottomLine,
placeHolder = placeHolder,
Expand Down
11 changes: 9 additions & 2 deletions sample/src/main/java/com/composeuisuite/ohteepee/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.composeuisuite.ohteepee

import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.ExperimentalFoundationApi
Expand Down Expand Up @@ -40,6 +41,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RadialGradientShader
import androidx.compose.ui.graphics.Shader
import androidx.compose.ui.graphics.ShaderBrush
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
Expand Down Expand Up @@ -306,6 +308,7 @@ private fun Sample1(
private fun Sample2(
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val backgroundColor = Color(0xFF1A1E22)
var otpValue: String by remember { mutableStateOf("") }
val defaultConfig = OhTeePeeCellConfiguration.withDefaults(
Expand Down Expand Up @@ -339,7 +342,7 @@ private fun Sample2(
Spacer(modifier = Modifier.height(16.dp))

Text(
text = "(Keep input on error)",
text = "(Keep input on error + Check Valid on last input)",
color = Color.White,
textAlign = TextAlign.Center,
)
Expand All @@ -354,8 +357,11 @@ private fun Sample2(

OhTeePeeInput(
value = otpValue,
onValueChange = { newValue, _ ->
onValueChange = { newValue, isValid ->
otpValue = newValue
if (isValid) {
Toast.makeText(context, "Validate the value here...", Toast.LENGTH_SHORT).show()
}
},
isValueInvalid = otpValue == "1111",
configurations = OhTeePeeConfigurations.withDefaults(
Expand All @@ -365,6 +371,7 @@ private fun Sample2(
cellModifier = Modifier
.padding(horizontal = 4.dp)
.size(48.dp),
checkValidOnLastCellInput = true,
clearInputOnError = false,
),
autoFocusByDefault = false,
Expand Down