Hey! I am trying to use ViewModel with a list of a...
# compose
m
Hey! I am trying to use ViewModel with a list of alarms. As I can't use a mutable List because it doesn't change and therefore does not update the UI, I am using a mutable List called "alarms" in the viewModel and then pushing it to the _state variable with .toList():
Copy code
private val _state = MutableStateFlow(AlarmsScreenState());
    val state : StateFlow<AlarmsScreenState> = _state.asStateFlow()

    var alarms : MutableList<Alarm> = mutableListOf();

    // Events
    fun toggleAlarm(alarm: Alarm) {
        alarms.find { it == alarm }?.let {
            it.enabled = !it.enabled
        }
        _state.value = _state.value.copy(alarms = alarms.toList())

        println(_state.value.alarms.find{it == alarm }?.enabled)
    }
And even though the println statement prints text alternating between true and false, the Switch in the UI does not update. Even though the _state.value gets updated. What am I missing here? Relevant passages in the UI:
Copy code
@Composable
fun AlarmsScreen(
    viewModel: AlarmViewModel = viewModel(),
) {
    val state by viewModel.state.collectAsState()
    Box(modifier = Modifier.fillMaxSize()) {
        AlarmCardList(alarms = state.alarms, onToggleAlarm = viewModel::toggleAlarm )
and
Copy code
@Composable
fun AlarmCardList(
    alarms: List<Alarm>,
    onToggleAlarm: (Alarm) -> Unit
) {
    LazyColumn(
        modifier = Modifier.padding(8.dp),
        verticalArrangement = Arrangement.spacedBy(2.dp)
    ) {
        items(alarms) { alarm ->
            AlarmCard(alarm) { onToggleAlarm(alarm) }
        }
    }
}
Let me know if I forgot to give some information, it would be amazing if you could help me 🙂
z
is
AlarmsScreenState.enabled
a snapshot state object?
m
My AlarmsScreenState looks like this
Copy code
data class AlarmsScreenState(
    val alarms: List<Alarm> = emptyList(),
    val isAlarmCreationOpen: Boolean = false,
    val currentEditedAlarm: Alarm? = null,
)
and my Alarm looks like this (annotations from Room)
Copy code
@Entity
data class Alarm(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    val schedule: Schedule? = null,
    var enabled: Boolean = true,
)
So enabled is just a Boolean
z
So inside your list item you’re getting the same alarm object and it’s probably skipping
m
That was the problem. Thanks. My new code looks like this:
Copy code
val index = alarms.indexOfFirst { it == alarm }
        if (index != -1) {
            alarms[index] = alarms[index].copy(enabled = !alarms[index].enabled)
        }
        _state.value = _state.value.copy(alarms = alarms.toList())