简体   繁体   中英

How to filter data from a viewmodel in a Jetpack Compose dialog?

I have a main screen where I have retrieved a list string in a viewmodel. I also have a button that opens a Dialog. In this dialog I have a text field for the user to write the word that he want to filter (potato name field), and buttons to filter and cancel. How can I apply the filter in the viewmodel when the user clicks on the button to accept that on the main screen the list is already filtered?

MainScreen:

@Composable
fun PotatosScreen(
    viewModel: PotatosViewModel,
    state: Success<PotatosData>
) {
    val expandedItem = viewModel.expandedCardList.collectAsState()

    Box(
        modifier = Modifier.fillMaxSize()
    ) {

        LazyColumn(
            modifier = Modifier
                .fillMaxSize()
                .padding(vertical = 8.dp)
        ) {
            items(state.data.potatos) { potato ->
                potatoCard(
                    potato = potato,
                    onCardArrowClick = { viewModel.itemArrowClick(potato.id) },
                    expanded = expandedItem.value.contains(potato.id)
                )
            }
        }
        
        
        var showCustomDialogWithResult by remember { mutableStateOf(true) }
    
        // Text button for open Dialog
        Text(
            text = "Filter",
            modifier = Modifier
                .clickable { 
                    if (showCustomDialogWithResult) {
                        DialogFilter(
                            onDismiss = {
                                showCustomDialogWithResult = !showCustomDialogWithResult
                            },
                            onNegativeClick = {
                                showCustomDialogWithResult = !showCustomDialogWithResult
                            },
                            onPositiveClick = {
                                showCustomDialogWithResult = !showCustomDialogWithResult
                            }
                        )
                    }
                }
        ) 
    }
}

Dialog:

@Composable
fun DialogFilter(
    onDismiss: () -> Unit,
    onNegativeClick: () -> Unit,
    onPositiveClick: () -> Unit
) {

    var text by remember { mutableStateOf("") }
    
    Dialog(onDismissRequest = onDismiss) {

        Card(
            shape = RoundedCornerShape(10.dp),
            modifier = Modifier.padding(10.dp, 5.dp, 10.dp, 10.dp),
            elevation = 8.dp
        ) {

            Column(
                Modifier.background(Color.White)
            ) {

                Text(
                    text = stringResource("Filter")
                )
                        
                TextField(
                    value = text
                )
                        
                TextButton(onClick = onNegativeClick) {
                    Text(
                        text = "Cancel                      
                    )
                }
                // How apply filter in viewModel here?
                TextButton(onClick = onPositiveClick) {
                    Text(
                        text = "Filter"
                    )
                }
            }
        }
    }
}

ViewModel:

@HiltViewModel
class PotatosViewModel @Inject constructor(
    private val getPotatosDataUseCase: GetPotatosData
) : ViewModel() {

    private val _state = mutableStateOf<Response<PotatosData>>(Loading)
    val state: State<Response<PotatosData>> = _state

    private val _expandedItemList = MutableStateFlow(listOf<Int>())
    val expandedCardList: StateFlow<List<Int>> get() = _expandedItemList

    private val _isRefreshing = MutableStateFlow(false)

    val isRefreshing: StateFlow<Boolean>
        get() = _isRefreshing.asStateFlow()

    init {
        getPotatos()
    }

    fun refresh() {
        viewModelScope.launch {
            _isRefreshing.emit(true)
            getPotatos()
            _isRefreshing.emit(false)
        }
    }

    private fun getPotatos() {
        viewModelScope.launch {

            getPotatosDataUseCase().collect { response ->
                _state.value = response
            }
        }
    }

    fun containsItem(potatoId: Int): Boolean {

        return _expandedItemList.value.toMutableList().contains(potatoId)
    }

    fun itemArrowClick(potatoId: Int) {

        _expandedItemList.value = _expandedItemList.value.toMutableList().also { list ->
            if (list.contains(potatoId)) {
                list.remove(potatoId)
            } else {
                list.add(potatoId)
            }
        }
    }
}

State:

data class PotatosState(
    val potatoes: List<Potato>,
)

Potato:

data class Potato(
    val id: Int,
    val name: String)

You can change the onPositiveClick callback to accept a String and pass it to the ViewModel in order to apply your filter, something like this:

fun DialogFilter(
    onDismiss: () -> Unit,
    onNegativeClick: () -> Unit,
    onPositiveClick: (String) -> Unit
)

And then the callback would call your ViewModel with the text

onPositiveClick = { filter ->
    showCustomDialogWithResult = !showCustomDialogWithResult
    viewModel.applyFilter(filter)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM