-1

I have a problem with displaying the card when the checkbox is checked. I would like a given card in one activity to be displayed only when the user selects a given checkbox in another activity. But when I created a visibility condition, this card does not show even when this condition is met.
Here is code of the activity with checkboxes

package com.example.drzewogenealogiczne20.questionnaire

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.navigation.NavHostController


data class CheckboxItem(
    val id: String,
    val label: String,
    val isChecked: Boolean
)

data class CardItem(
    val id: String,
    val title: String,
    val checkboxes: List<CheckboxItem>,
    val exclusiveCheckboxes: Boolean = false,
    val visibleCondition: ((List<CardItem>) -> Boolean)? = null
)

class QuestionnaireViewModel : ViewModel() {

    var cards by mutableStateOf<List<CardItem>>(emptyList())
        private set

    fun setAnswers(list: List<CardItem>) {
        cards = list
    }
}


@Composable
fun QuestionScreen(navController: NavHostController, viewModel: QuestionnaireViewModel) {

    var cards by remember {
        mutableStateOf(
            listOf(

                CardItem(
                    id = "card1",
                    title = "W którym wieku żyła poszukiwana osoba?",
                    exclusiveCheckboxes = false,
                    checkboxes = listOf(
                        CheckboxItem(
                            id = "checkbox1",
                            label = "XVIII (1701-1800)",
                            isChecked = false
                        ),
                        CheckboxItem(
                            id = "checkbox2",
                            label = "XIX (1801-1900)",
                            isChecked = false
                        ),
                        CheckboxItem(
                            id = "checkbox3",
                            label = "XX (1901-2000)",
                            isChecked = false
                        ),
                        CheckboxItem(
                            id = "checkbox4",
                            label = "XXI (2001-2100)",
                            isChecked = false
                        ),
                    )
                ),

                    visibleCondition = { allCards ->
                        allCards.find { it.id == "card1" }
                            ?.checkboxes
                            ?.find { it.id == "checkbox3" }?.isChecked == true
                    }
                ),
            )


        )



    }

    var validationError by remember { mutableStateOf<String?>(null) }

    fun validate(): Boolean {
        val visibleCards = cards.filter { it.visibleCondition?.invoke(cards) != false }

        return visibleCards.all { card ->
            card.checkboxes.any { it.isChecked }
        }
    }


    fun onCheckboxChange(cardId: String, checkboxId: String, checked: Boolean) {
        cards = cards.map { card ->
            if (card.id == cardId) {
                if (card.exclusiveCheckboxes) {
                card.copy(
                    checkboxes = card.checkboxes.map {
                        if (it.id == checkboxId) it.copy(isChecked = checked)
                        else it.copy(isChecked = false)
                    }
                )

            } else {
               card.copy(
                     checkboxes = card.checkboxes.map {
                         if (it.id == checkboxId) it.copy(isChecked = checked)
                         else it
                      }
                  )
              }
            } else card
        }

        viewModel.setAnswers(cards)

        if (!validate()) {
            validationError = "Zaznacz co najmniej jedną odpowiedź w każdej widocznej sekcji."
        } else {
            validationError = null
        }
    }



    val visibleCards = cards.filter { it.visibleCondition?.invoke(cards) != false }


    Column(Modifier.fillMaxSize()) {



        LazyColumn(modifier =  Modifier.weight(1f)) {
            items(visibleCards) { card ->
                CardItemView(card = card, onCheckboxChange = ::onCheckboxChange)
            }
        }

            Button(
                onClick = {
                    if (validate()) {
                        navController.navigate("result")
                    } else {
                        validationError = "Zaznacz co najmniej jedną odpowiedź w każdej widocznej sekcji."
                    }
                },
                enabled = validate(), // blokada przycisku
                modifier = Modifier.fillMaxWidth()
            ) {
                Text("Pokaż wynik")
            }

            validationError?.let { errorMsg ->
                Text(
                    text = errorMsg,
                    color = Color.Red,
                    modifier = Modifier.padding(top = 8.dp)
                )
            }
        }
    }


@Composable
fun CardItemView(
    card: CardItem,
    onCheckboxChange: (String, String, Boolean) -> Unit
) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 8.dp),
        elevation = CardDefaults.cardElevation(6.dp)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(text = card.title, style = MaterialTheme.typography.titleMedium)
            Spacer(modifier = Modifier.height(8.dp))

            card.checkboxes.forEach { checkbox ->
                Row(verticalAlignment = Alignment.CenterVertically) {
                    Checkbox(
                        checked = checkbox.isChecked,
                        onCheckedChange = { checked ->
                            onCheckboxChange(card.id, checkbox.id, checked)
                        }
                    )
                    Text(text = checkbox.label)
                }
            }
        }
    }
}

And the second activity with card I want to display depending of checkboxes

package com.example.drzewogenealogiczne20.questionnaire

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.drzewogenealogiczne20.questionnaire.QuestionScreen




data class CardResult(
    val id: String,
    val title: String,
    val visibleCondition: ((List<CardItem>) -> Boolean)? = null
)


@Composable
fun ViewResults(
    navController: NavHostController,
    viewModel: QuestionnaireViewModel = viewModel()
) {

    val answers = viewModel.cards

    var cards by remember {
        mutableStateOf(
            listOf(

                CardResult(
                    id = "FamilySearch",
                    title = "Family Search",
                    visibleCondition = { allCards ->
                        allCards.find { it.id == "card1" }
                            ?.checkboxes
                            ?.find { it.id == "checkbox1" }?.isChecked == true
                    }
                ),

               
            )
        )
    }

    val filteredCards = cards.filter { card ->
        card.visibleCondition?.invoke(answers) ?: true
    }


    Column(
        Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        LazyColumn(modifier = Modifier.weight(1f)) {
            items(filteredCards
                     ) { card ->
                CardResultView(card)
            }
        }
    }
}



@Composable
fun CardResultView(
    card: CardResult
) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 8.dp),
        elevation = CardDefaults.cardElevation(6.dp)
    ) {
        Column(Modifier.padding(16.dp)) {
            Text(text = card.title, style = MaterialTheme.typography.titleMedium)
            Spacer(modifier = Modifier.height(8.dp))
        }
    }
}
8
  • Please check your first code block, there are some serious compile errors near visibleCondition. You can edit your question to fix it. Make sure you provide all code in the form of a minimal reproducible example. Commented Nov 14 at 19:08
  • Also, why do you even use multiple activities? Compose is best used with a single activity only. If you still need multiple activities (f.e., during the migration of legacy code), then please also provide the means of how you pass data between those activities - like via intents or by using the same repository and the likes. Commented Nov 14 at 19:10
  • And the NavHost is missing, including how you create the view model instances. Commented Nov 14 at 19:20
  • So should I put these functions in one file? And I can't find the errors Commented Nov 14 at 19:24
  • 1
    Please read the link in my first comment about how a minimal reproducible example should look like. Then edit the question to make sure all code necessary to reproduce your issue is there, and remove everything else that isn't strictly necessary. Probably the easiest way to do that is by creating a new project and only copy the code from the question there. Then add everything until the problem is reproducible, and then remove everything that can be removed without affecting the reproducibility. Then replace the code from your question with that. Commented Nov 14 at 19:28

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.