LazyColumn not recomposing based on Boolean

65 Views Asked by At

I have the fololwing viewmodel with the variable called isFilterActive, which is being stored as a Boolean-value inside the data class FilterProductUiState.

class ProductViewModel(productRepository: ProductRepository) : ViewModel() {

    val productHomeUiState: StateFlow<ProductHomeUiState> =
        productRepository.getAllProductsStream().map { ProductHomeUiState(it) }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(TIMEOUT_MILLIS),
                initialValue = ProductHomeUiState()
            )


    companion object {
        private const val TIMEOUT_MILLIS = 5_000L
    }

    private var isFilterActive = false

    private fun isFilterActive(): Boolean {
        return isFilterActive
    }
    
    private val categoryStringStateFlow = MutableStateFlow<List<String>>(emptyList())
    private val currencyStateFlow = MutableStateFlow("")
    private val startPriceStateFlow = MutableStateFlow(0.0)
    private val endPriceStateFlow = MutableStateFlow(0.0)
    private val startDateStateFlow = MutableStateFlow("")
    private val endDateStateFlow = MutableStateFlow("")
    private val companyStateFlow = MutableStateFlow("")



    fun applyProductFilter(
        category: List<Category?>,
        currency: String,
        startPrice: Double,
        endPrice: Double,
        startDate: String,
        endDate: String,
        company: String
    ) {
        isFilterActive = true

        val stringValues: List<String> = category
            .mapNotNull { it?.value }

        categoryStringStateFlow.value = stringValues
        currencyStateFlow.value = currency
        startPriceStateFlow.value = startPrice
        endPriceStateFlow.value = endPrice
        startDateStateFlow.value = startDate
        endDateStateFlow.value = endDate
        companyStateFlow.value = company


        Log.d("Filterstate", "Filtered Results: ${isFilterActive()}")
        Log.d("Core category", "Category=${categoryStringStateFlow}")
    }


    @OptIn(ExperimentalCoroutinesApi::class)
    val filteredProductUiState: StateFlow<FilterProductUiState> =
        categoryStringStateFlow
            .flatMapLatest { productRepository.filterCategory(
                category = categoryStringStateFlow.value
            )}
            .map { FilterProductUiState(it, isFilterActive = isFilterActive()) }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(TIMEOUT_MILLIS),
                initialValue = FilterProductUiState(),
            )

}

    data class ProductHomeUiState(
        val productList: List<Product> = listOf()
    )

    data class FilterProductUiState(
        val filterProductList: List<Product> = listOf(),
        var isFilterActive: Boolean = false
    )

I am using the isFilterActive() Function, to track the value of isFilterActive inside the Logcat.

My Problem is, that in my MainScreen, I have a TopBar that shows an InputChip, when the Filter is active, and when being pressed, this Chip should invoke a recomposition of the LazyColumn, that either shows the productlist of the ProductHomeUiState or the filterProductList of the FilterProductUiState, based on the value of isFilterActive of FilterProductUiState

TopBar:

Scaffold(
    modifier = modifier
        .nestedScroll(scrollBehavior.nestedScrollConnection),
    topBar = {
        TopAppBarMain(
            navController = navController,
            selectedItems =  if (selectedTabIndex == 0) selectedProducts else selectedServices,
            resetSelectionMode = resetSelectionMode,
            isInSelectionMode = isInSelectionMode,
            scrollBehavior = scrollBehavior,
            toggleDeleteConfirmation = {
                deleteConfirmationRequired = !deleteConfirmationRequired
            },
            isFilterActive = filterProductUiState.isFilterActive,
            onClearFilter = {
                coroutineScope.launch {
                    filterProductUiState.isFilterActive = false

                }
                Log.d("ClearFilter2", "Filter State: ${filterProductUiState.isFilterActive}")
            },

        )
    },

The Problem is that the OnClick is not triggering a recomposition in the LazyColumn.

LazyColumn:

@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun ProductList(
    productList: List<Product>,
    filterList: List<Product>,
    modifier: Modifier = Modifier,
    isInSelectionMode: Boolean,
    selectedItems: SnapshotStateList<Product>,
    onProductClick: (Product) -> Unit,
    toggleSelectionMode: () -> Unit,
    isFilterActive: Boolean
) {
    LazyColumn(
        modifier = modifier,
    ) {
        items(
            items = if (isFilterActive) { //here it should deside what list to use
                filterList
                }
            else{
                productList
                },
            key = { it.id}
        ) { product ->
            val isSelected = selectedItems.contains(product)
            ProductItem(
                product = product,
                modifier = Modifier
                    .padding(
                        top = 8.dp,
                        bottom = 8.dp,
                        start = 24.dp,
                        end = 24.dp
                    )
                    .combinedClickable(
                        onClick = {
                            if (isInSelectionMode) {
                                if (isSelected) {
                                    selectedItems.remove(product)
                                } else {
                                    selectedItems.add(product)
                                }
                            } else {
                                onProductClick(product)
                                // Click action if required when not in selection mode
                            }
                        },
                        onLongClick = {
                            if (isInSelectionMode) {
                                if (isSelected) {
                                    selectedItems.remove(product)
                                } else {
                                    selectedItems.add(product)
                                }
                            } else {
                                toggleSelectionMode()
                                selectedItems.add(product)
                            }
                        }
                    ),
                backgroundColor = if (isSelected) {
                    if (isInSelectionMode) {
                        MaterialTheme.colorScheme.primary.copy(alpha = 0.2f)
                    } else {
                        MaterialTheme.colorScheme.primary.copy(alpha = 0f)
                    }
                } else {
                    MaterialTheme.colorScheme.primary.copy(alpha = 0f)
                },
            )
        }
    }
}
1

There are 1 best solutions below

0
On

Make your isFilterActive MutableState observable.

var isFilterActiveL: MutableState<Boolean> = mutableStateOf(true)

Read about the State here. This helps for re-composition on a value change