https://kotlinlang.org logo
#compose-android
Title
# compose-android
h

Henri

12/13/2023, 2:14 PM
Hello everyone. I hope you are all well. Help me understand why my OutlinedTextField loses its cursor after a questionAndResponse state change.
😯 3
🧵 1
t

Timo Drick

12/13/2023, 2:22 PM
You should put the code into this thread and put it inside of a codeblock. Than maybe we could read it.
h

Henri

12/13/2023, 2:24 PM
Copy code
@Composable
fun Digit(
    feedbackId: String,
    questionAndResponse: QuestionAndResponse,
    onSaveResponse: (String, Question, Any) -> Unit,
    onAutomaticSaveResponse: (String, Question, Any) -> Unit,
    onRememberState: (String, (Response?) -> Unit) -> Unit,
    modifier: Modifier = Modifier
) {
    var isDisplayedTextAlreadyChanged by remember {
        mutableStateOf(false)
    }
    val mapper by remember {
        mutableStateOf(ResponseValueToString())
    }
    var displayedText by rememberSaveable {
        val response = mapper.map(questionAndResponse.response?.value, questionAndResponse.type)
        if (response == "")
            mutableStateOf("")
        else
            mutableStateOf(response)
    }
    LaunchedEffect(
        key1 = questionAndResponse.response?.value,
        block = {
            if (questionAndResponse.question.isComputed()){
                displayedText = mapper.map(questionAndResponse.response?.value, questionAndResponse.type)
            }
        }
    )
    val configs by remember {
        mutableStateOf(questionAndResponse.configs as Configs.Digit)
    }
    var isError: Boolean by rememberSaveable {
        mutableStateOf(false)
    }
    LaunchedEffect(
        key1 = Unit,
        block = {
            if (questionAndResponse.question.rememberState == true){
                onRememberState(
                    questionAndResponse.question.id
                ) { response ->
                    if (response != null && questionAndResponse.response == null) {
                        onAutomaticSaveResponse(
                            feedbackId,
                            questionAndResponse.question,
                            response.valueAsString ?: ""
                        )
                    }
                }
            }
        }
    )
    LaunchedEffect(
        key1 = displayedText,
        block = {
            if (!isError && isDisplayedTextAlreadyChanged){
                onSaveResponse(
                    feedbackId,
                    questionAndResponse.question,
                    displayedText.evalExpression()?:"0"
                )
            }
        }
    )
    Column(modifier = modifier) {
        OutlinedTextField(
            value = displayedText,
            onValueChange = { newText ->
                //text = it
                isDisplayedTextAlreadyChanged = true
                if(!questionAndResponse.question.isComputed() && isDisplayedTextAlreadyChanged){
                    displayedText = newText
                }
                isError = if (newText.isNotBlank()) {
                    try {
                        (newText.toBigDecimal().compareTo(configs.maxValue?.toBigDecimal())) == 1 || (newText.toBigDecimal().compareTo(configs.minValue?.toBigDecimal())) == -1
                    }catch (e: Exception){
                        false
                    }
                } else {
                    false
                }
            },
            keyboardOptions = KeyboardOptions(keyboardType =
            if(configs.allowComputations == true)
                KeyboardType.Text
            else KeyboardType.Number
            ),
            textStyle = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.W400),
            modifier = Modifier
                .fillMaxWidth()
                .height(60.dp)
                .background(color = Color.White),
            enabled = !questionAndResponse.question.isComputed(),
            //.padding(bottom = 7.dp),
            trailingIcon = {
                if (isError)
                    Icon(Icons.Default.Warning, "error", tint = MaterialTheme.colors.error)
            },
            placeholder = {
                Text(text = configs.hint ?: "")
            },
            isError = isError,
            shape = RoundedCornerShape(5.dp),
            singleLine = true,
            colors = TextFieldDefaults.outlinedTextFieldColors(
                textColor = Color(0xFF082444),
                focusedBorderColor = Color(0xFFCDDBEC),
                unfocusedBorderColor = Color(0xFFCDDBEC),
                cursorColor = Color(0xFF082444),
                backgroundColor = Color.White,
                placeholderColor = Color(0xFFBABFCC),
            ),
        )
        if (configs.allowComputations == true &&
            displayedText.isEval()
        ) {
            Text(
                text = displayedText.evalExpression().let {
                    if(it == null) "Invalid operation"
                    else "RESULT = $it"
                },
                color = if(displayedText.evalExpression() == null)
                    MaterialTheme.colors.error else Color(0xFF259705),
                style = MaterialTheme.typography.caption,
                modifier = Modifier.padding(start = 16.dp)
            )
        }
        if (isError) {
            Text(
                text = "The nombre entered must range in ${configs.minValue} et ${configs.maxValue}.",
                color = MaterialTheme.colors.error,
                style = MaterialTheme.typography.caption,
                modifier = Modifier.padding(start = 16.dp)
            )
        }
    }
}
@Immutable
data class QuestionAndResponse(
    @Embedded val question: Question,
    @Embedded val response: Response?
)
@Immutable
@Entity(primaryKeys = ["id", "form_id"])
data class Question(
    override val id: String,
    val name: String? = null,
    val help: String? = null,
    val configs: Configs? = null,
    val type: QuestionType,
    val position: Int = 0,
    @ColumnInfo(name = "is_mandatory") val isMandatory: Boolean? = null,
    @ColumnInfo(name = "is_hidden") val isHidden: Boolean? = null,
    @ColumnInfo(name = "is_display_question") val isDisplayQuestion: Boolean? = null,
    @ColumnInfo(name = "section_id") val sectionId: String? = null,
    @ColumnInfo(name = "form_id") val formId: String,
    @ColumnInfo(name = "form_version") val formVersion: String? = null,
    @ColumnInfo(name = "computed_value") val computedValue: String? = null,
    @ColumnInfo(name = "remember_state") val rememberState: Boolean? = null
)
@Immutable
@Entity(
    primaryKeys = ["question_id", "feedback_id"],
    indices = [
        Index(value = ["value", "value_as_string"])
    ]
)
data class Response(
    @ColumnInfo(name = "question_id") val questionId: String,
    @ColumnInfo(name = "feedback_id") val feedbackId: String,
    @ColumnInfo(name = "response_type") val responseType: QuestionType,
    @ColumnInfo(name = "value") val value: String,
    @ColumnInfo(name = "value_as_string") val valueAsString: String?,
    @ColumnInfo(name = "onlineId") override val onlineId: String? = null,
    @ColumnInfo(name = "pending_action") override val pendingAction: PendingAction = PendingAction.NOTHING,
    @ColumnInfo(name = "actions_types") override val actionsType: List<ActionType> = emptyList(),
    @ColumnInfo(name = "is_valid") val isValid: Boolean = true,
    val error: DaggaError? = null,
    @ColumnInfo(name = "updated_at") val updateAt: OffsetDateTime = OffsetDateTime.now()
)
t

Timo Drick

12/13/2023, 2:42 PM
Nice now remove the code from your first post. So the main thread is not cluttered with that.
h

Henri

12/13/2023, 2:47 PM
Done
👍 1
t

Timo Drick

12/13/2023, 2:51 PM
The code is difficult to understand would be nice if you could build a minimum reproducer of your issue.
h

Henri

12/13/2023, 2:55 PM
A video can help ?
t

Timo Drick

12/13/2023, 2:57 PM
For me the problem is clear but i do not see any obvious errors in your code.
So if you are creating a minimum reproducer maybe you can fix it yourself. Or if it is really a bug you could create an issue in the issuetracker
h

Henri

12/13/2023, 3:00 PM
What do you call reproducer ? I don't understand
t

Timo Drick

12/13/2023, 3:01 PM
Just reduce the complexity of the code. So only include Composables which are necessary to reproduce the problem.
And also states
h

Henri

12/13/2023, 3:02 PM
Okay!
2 Views