I need to control the visibility of "save" button on my "settings" screen:
val enableSaveButton = remember(
modifiedUser,
originalUser,
changePasswordData,
modifiedExtraSettingsData,
originalExtraSettingsData,
) {
val userModifications = if (isLoggedIn) {
modifiedUser.value != originalUser.value
} else {
false
}
val passwordModifications = changePasswordData.value != ChangePasswordData.NULL_OBJECT
val isPasswordDataConsistent = if (isLoggedIn && passwordModifications) {
changePasswordData.value.isValidData()
} else {
true
}
val extraModifications = modifiedExtraSettingsData.value != originalExtraSettingsData.value
(userModifications || extraModifications || passwordModifications) && isPasswordDataConsistent
}
My problem is that this remember block is not re-evaluated when changePasswordData mutable state changes. It does re-evaluate when modifiedExtraSettingsData changes, however.
I used breakpoints in the code to verify that changePasswordData is indeed changed and that change triggers re-composition of the respective Composables, but not re-evaluation of the above expression.
As far as I can tell, I use the same approach for changePasswordData and modifiedExtraSettings, yet get different behavior.
These are the declarations of the respective mutable states:
private val originalUser = mutableStateOf(User.NULL_USER)
private val modifiedUser = mutableStateOf(User.NULL_USER)
private val changePasswordData = mutableStateOf(ChangePasswordData.NULL_OBJECT)
private val originalExtraSettingsData = mutableStateOf(ExtraSettingsData.NULL_OBJECT)
private val modifiedExtraSettingsData = mutableStateOf(ExtraSettingsData.NULL_OBJECT)
And that's how I mutate changePasswordData and modifiedExtraSettings:
MyTextField(
modifier = Modifier.fillMaxWidth(),
text = changePasswordData.value.currentPassword,
label = stringResource(id = R.string.settings_current_password),
enabled = true,
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Next),
onValueChanged = {
changePasswordData.value = changePasswordData.value.copy(
currentPassword = it
)
}
)
MyTextField(
modifier = Modifier.fillMaxWidth(0.5f),
label = stringResource(id = R.string.settings_server_base_url_label),
text = extraSettingsData.value.baseServerUrl,
onValueChanged = {
extraSettingsData.value = extraSettingsData.value.copy(
baseServerUrl = it
)
}
)
So, why the difference in behavior?
After spending another 30 mins on this, I figured out that I had to use the values of mutable states as keys, rather than the states themselves:
val enableSaveButton = remember(
modifiedUser.value,
originalUser.value,
changePasswordData.value,
modifiedExtraSettingsData.value,
originalExtraSettingsData.value,
) {
val userModifications = if (isLoggedIn) {
modifiedUser.value != originalUser.value
} else {
false
}
val passwordModifications = changePasswordData.value != ChangePasswordData.NULL_OBJECT
val isPasswordDataConsistent = if (isLoggedIn && passwordModifications) {
changePasswordData.value.isValidData()
} else {
true
}
val extraModifications = modifiedExtraSettingsData.value != originalExtraSettingsData.value
(userModifications || extraModifications || passwordModifications) && isPasswordDataConsistent
}
It's very odd that the wrong approach worked for some of the mutable states, but not others.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With