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)
},
)
}
}
}
Make your
isFilterActive
MutableState observable.Read about the State here. This helps for re-composition on a value change