I have a Room app which displays a list of presets, and the user has the option of adding them by pressing a 'New Quick Preset' button:
Code for inserting new item into Room database (in ViewModel):
fun insertQuickPreset(quickPreset: QuickPreset) {
viewModelScope.launch {
repository.insertQuickPreset(quickPreset)
}
}
State:
data class NewScreenState(
@StringRes val nameError: Int? = null,
@StringRes val widthError: Int? = null,
@StringRes val heightError: Int? = null,
val name: String = "",
val width: String = "",
val height: String = "",
val quickPresets: List<QuickPreset>
)
Repo:
suspend fun insertQuickPreset(quickPreset: QuickPreset) {
return withContext(Dispatchers.IO) {
dao.insert(quickPreset)
}
}
Composable:
Button(
modifier = Modifier.align(Alignment.End),
onClick = {
viewModel.insertQuickPreset(QuickPreset(55,52))
}
) {
Text(
"New Quick Preset"
)
}
The issue is, when the user taps 'New Quick Preset', the state doesn't get updated, so for the user to see the results they need to go back and then press the button to enter the screen again.
I took a course in Compose and they never demonstrated how to add items, only how to fetch them. I have the code for adding an item, although I have no idea how I would update the state from here to reflect the added values? I usually utilize the .copy
method but this is only for when the database contents are first fetched.
Any help would be appreciated.
CodePudding user response:
Use SnapshotStateList
.
val quickPresets: SnapShotStateList
and initializing it this way
val list = mutableStateListOf( your quick presets )
Any updates you do to a SnapshotStateList
, such as
- add new quickPreset
- remove a quickPreset
- update a quickPreset via
.copy()
is guaranteed to perform a re-composition
, assuming its being observed by a composable somewehere
Edit: Assuming you're using Room
database, here is a snippet of my own implementation
Repository
override fun fetchPeople(): Flow<List<People>> =
peopleDao.getPeople().map { entityList ->
entityList.map { entity ->
entity.toModel()
}
}
override suspend fun savePerson(PersonModel: PersonModel): Long {
return peopleDao.insertPerson(PersonModel.toEntity())
}
override suspend fun deletePerson(PersonModel: PersonModel) {
peopleDao.deletePerson(PersonModel.toEntity())
}
And I'm just observing it via ViewModel
private val _people = mutableStateListOf<Person>()
val people: List<Person> = _people
...
...
// no need for any 'get/fectch' call, changes being made
// to the repository (e.g add or delete) will be propagated back via `flow`
viewModelScope.launch {
repository.fetchPeople()
.collect {
_people.addAll(it)
}
}
For your scrolling issue, you can do something like this,
val scrollState = rememberLazyListState()
val coroutineScope = rememberCoroutineScope()
// scrollToItem after a successful `re-composition`
SideEffect {
coroutineScope.launch {
scrollState.scrollToItem(index)
}
}
Let the composable
that contains your list
finish what ever it needs to do, and do the scrollToItem
after its successful re-composition