Bom dia a todos
Tentei fazer o desafio Desafio: campo de busca na tela inicial, fazendo a busca do meu jeito, realizando os métodos do Dao dentro do view Model e a lista ser atualizado de acordo com a mudança do texto. Até um certo nível deu certo. Mas o problema é que na hora de pesquisar, algumas vezes o resultado retorna vazio, mesmo que o texto seja igual ao pesquisado.
Acredito que seja pelo fato do view model pegar o resultado antes do dao realize a pesquisa. Código do view Model:
@HiltViewModel
class ListaContatosViewModel @Inject constructor(
private val contatoDao: ContatoDao,
) : ViewModel() {
private val _uiState = MutableStateFlow(ListaContatosUiState())
val uiState: StateFlow<ListaContatosUiState>
get() = _uiState.asStateFlow()
init {
viewModelScope.launch {
_uiState.update { state ->
state.copy(
alteracaoDoTextoDeBusca = {
_uiState.value = uiState.value.copy(
textoDeBusca = it,
// método de busca seja atualizado junto com o texto da barra de pesquisa
buscaDeContatos = buscaDeContatos(it)
)
}
)
}
viewModelScope.launch {
contatoDao.buscaTodos().collect {
_uiState.value = _uiState.value.copy(
contatos = it
)
}
}
}
}
// método da busca de contatos, deve ta mandando o empty antes da busca do dao ser feita
private fun buscaDeContatos(nome: String): List<Contato> {
var contatosBuscados: List<Contato> = emptyList()
viewModelScope.launch {
// eu acho que eu precisaria garantir que isso seja buscado antes que o view model pegue o resultado
contatosBuscados = contatoDao.buscaPorNome(nome).first()
}
return contatosBuscados
}
}
Já tentei com outros métodos com o contatoDao.buscaPorNome(nome)
, já tentei o first()
, o firstOrNull()
, collect()
. Também tentei o viewModelScope.async{}
no lugar do viewModelScope.launch{}
e mesmo assim as vezes dá certo, as vezes a lista volta nulo.
O que eu devo fazer para a busca ser feita e só depois ter o retorno da busca?
vou deixar o resto do código abaixo:
Código da Screen
@Composable
fun ListaContatosTela(
state: ListaContatosUiState,
modifier: Modifier = Modifier,
onClickDesloga: () -> Unit = {},
onClickAbreDetalhes: (Long) -> Unit = {},
onClickAbreCadastro: () -> Unit = {},
) {
Scaffold(
topBar = { ...}
}) { paddingValues ->
Column {
Spacer(modifier = Modifier.padding(paddingValues))
Column (...){
IconeDeBusca(state = state)
val lista = if (state.textoDeBuscaEstaEmBranco()) {
state.contatos
} else {
state.buscaDeContatos
}
LazyColumn(verticalArrangement = Arrangement.spacedBy(16.dp)) {
items(lista) { contato ->
ContatoItem(contato) { idContato ->
onClickAbreDetalhes(idContato)
}
}
}
}
}
}
}
Código do UI State
data class ListaContatosUiState(
val contatos: List<Contato> = emptyList(),
val buscaDeContatos: List<Contato> = emptyList(),
val logado: Boolean = true,
val textoDeBusca: String = "",
val alteracaoDoTextoDeBusca: (String) -> Unit = {}
){
fun textoDeBuscaEstaEmBranco() = textoDeBusca.isBlank()
}
código da barra de busca:
@Composable
private fun IconeDeBusca(
modifier: Modifier = Modifier,
state: ListaContatosUiState = ListaContatosUiState(),
) {
OutlinedTextField(
modifier = modifier
.fillMaxWidth(),
shape = RoundedCornerShape(100),
value = state.textoDeBusca,
onValueChange = state.alteracaoDoTextoDeBusca,
leadingIcon = {
Icon(imageVector = Icons.Default.Search, contentDescription = "icone de busca")
},
label = {
Text(text = "Contato")
},
placeholder = {
Text(text = "Procurar pelo nome do Contato")
},
colors = TextFieldDefaults.colors(
focusedTextColor = Color.Gray,
focusedPlaceholderColor = Color.LightGray,
focusedContainerColor = Color.White
),
)
}