I'm new to jetpack compose, this is my first project so far and I'm using StateFlow to update the compose views:
Model:
@Parcelize
@Entity
data class User(
var firstName: String = "",
var lastName: String = "",
var gender: String = "",
var age: String = "",
var height: String = "",
var weight: String = "",
var activity: String = "",
var calories: String = "",
var goal: String = "",
@PrimaryKey val id: Int? = null
): Parcelable
Dao:
@Update
suspend fun updateUser(user: User)
RepoImpl:
override suspend fun updateUser(user: User) {
return dao.updateUser(user)
}
UserRepository:
suspend fun updateUser(user: User)
UserUpdateUseCase:
suspend operator fun invoke(user: User) {
return repository.updateUser(user)
}
UserViewModel:
private val _userState = MutableStateFlow<User?>(null)
val userState = _userState.asStateFlow()
init {
getUser()
}
fun updateUser(updatedUser: User) {
viewModelScope.launch {
userUseCases.updateUser(updatedUser)
_userState.value = _userState.value?.copy(
firstName = updatedUser.firstName,
lastName = updatedUser.lastName,
gender = updatedUser.gender,
age = updatedUser.age,
height = updatedUser.height,
weight = updatedUser.weight,
calories = updatedUser.calories,
goal = updatedUser.goal,
id = updatedUser.id
)
}
}
private fun getUser() {
viewModelScope.launch {
val user = userUseCases.getUser()
_userState.value = user
}
}
Now what I want to achieve is, when I update the user via one of my screens and when I navigate to another screen, it should check one of the properties and whether it has changed(updated) its value it should change the color of the screen appropriately.
(UserViewModel is initialized via hiltViewModel() and the User class is taken via screen's constructor using raam's costa destinations navigation library) The screen's code where the update takes part:
private fun validateSignUpThirdScreen(
context: Context,
viewModel: UserViewModel,
navigator: DestinationsNavigator,
selectedIndexResults: Int,
resultsList: List<String>,
user: User
) {
if (selectedIndexResults <= -1) {
showToast(context, "Select one of the options please")
return
}
val selectedResult = resultsList[selectedIndexResults]
val calories =
selectedResult.substringBefore(" calories") //It takes the number before "calories"
val goal = selectedResult.substringAfter(" -> ") //It takes the word after the "->"
user.calories = calories
user.goal = goal
if (user.id != null) {
viewModel.updateUser(user)
} else {
viewModel.addUser(user)
}
navigator.navigate(CalorieTrackerScreenDestination) {
popUpTo(SignUpThirdScreenDestination.route) {
inclusive = true
}
}
}
The magic should happen in this composable, which is basically called inside MainActivity and it is composed on every screens' navigation:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun App() {
val viewModel: UserViewModel = hiltViewModel()
val engine = rememberNavHostEngine()
val navController = engine.rememberNavController()
val currentDestination = navController.appCurrentDestinationAsState().value
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
val shouldShowScaffoldBar = remember { mutableStateOf(false) }
val user by viewModel.userState.collectAsState()
val base = remember { mutableStateOf("") }
LaunchedEffect(user?.goal) {
base.value = when (user?.goal) {
"Maintaining" -> "M"
"Losing" -> "L"
"Gaining" -> "G"
else -> ""
}
}......rest of the code
I checked on debug that when I navigate to the next screen, the _userState is successfully updating its value as well as the record in the database. Also App() is recomposed and even though _userState has changed its value in the UserViewModel, the variable 'user' that it is collecting its state has been collecting its old value.
I tried with emitting the value using enum status class, but same thing happens.
I also tried to launch the validation function via coroutine and delay some time before navigating to the next screen, since I suspected that maybe update takes a little bit more before it is navigated and meanwhile the 'user' is collecting the old state value, but that was not the case either.
Thanks in advance for any kind of help or idea.