Hi, I'm wondering if anyone would be willing to lo...
# compose
n
Hi, I'm wondering if anyone would be willing to look at my code (a couple of composables) on Pastebin. The problem is that I am trying to pass my accentColor.value down from my first to my second Composable, and for some reason, this is only working for the last of my four accentColor values. I'm still learning and would be grateful for the help... 😊
z
If you post a link, i’m sure someone will look at it 😉
n
I did, click on Pastebin. 🙂
r
It looks like you're modifying the MutableState during the composition, which is not what you want. Is accentColor really state? It looks like it could be a local
val
, different for each of the "options".
n
Thanks for looking. I think it is a state because the color changes depending on which button I click in the QuickOptions Composable.
So basically I worked out that state hoisting would be the best way. But obviously I could be completely wrong.
z
My bad, apparently i don’t see links unless they start with http 🙈
😁 2
Copy code
accentColor.value = when (index) {
                0 -> if (isEnabled) Color(0xff81C784) else disabledColor
                1 -> if (isEnabled) Color(0xff9575CD) else disabledColor
                2 -> if (isEnabled) Color(0xffFF8A65) else disabledColor
                3 -> if (isEnabled) Color(0xff5C6BC0) else disabledColor
                else -> Color.Unspecified
            }
That looks like code that should be in an event handler somewhere instead of in the composition directly
j
As stated above, the problem is that you are changing accentColor.value on composition inside the forEachIndexed so the first time the composable is created the states is changed four times and only the last one seems to be applied. I think what you want is to move the assignment to the onClick callback.
Copy code
onClick = {
    if (isSelectable == true) {
        accentColor.value = when (index) {
            0 -> if (isEnabled) Color(0xff81C784) else disabledColor
            1 -> if (isEnabled) Color(0xff9575CD) else disabledColor
            2 -> if (isEnabled) Color(0xffFF8A65) else disabledColor
            3 -> if (isEnabled) Color(0xff5C6BC0) else disabledColor
            else -> Color.Unspecified
        }
        ...
    }
}
Oops you beat me to it xD
n
Thank you all, that's really helpful! You guys are very kind! 😀
j
There might be special cases, but I think that whenever you are updating a variable or doing something that causes a change, it should be on a callback or event handler and not directly in composition because you can't control when composition will happen
👍 1
Also, I noticed you are passing the context down from your top composable to where you actually use it. You can easily access the context from AmbientContext.current
n
Ah ok great, I'll look it up! Cheers.
👍 1
j
Which button do you want to be colored initially?
n
Initially, the ones in the composable called QuickOptions.
j
All of them? There are four
n
yes, they each have their own color when pressed, and depending on which one is pressed, I want the toggles further down to have that color too.
j
Ok, couple of things, the reason why they show without any color initially is because accentColor is initialized like this
*val* accentColor = remember { mutableStateOf(Color.Unspecified) }
So they will initially all have
Color.Unspecified
n
The thing is I can't specify the colors at this stage because I have no access to the index.
I'm sure it's quite simple to pass a color down between two composables, but I just can't do it for some reason...
r
Remove the color state and don't pass it. Lift the selected index state up one level and pass that down. Then use that to select the color for the toggles.
j
You are already doing it with the accentColor, the problem is that you actually don't need it in the QuickOptions compoosable
this block
Copy code
when (index) {
                0 -> if (isEnabled) Color(0xff81C784) else disabledColor
                1 -> if (isEnabled) Color(0xff9575CD) else disabledColor
                2 -> if (isEnabled) Color(0xffFF8A65) else disabledColor
                3 -> if (isEnabled) Color(0xff5C6BC0) else disabledColor
                else -> Color.Unspecified
            }
should be directly assigned to the backgroundColor of each button
n
Ok, so pass the index as a parameter rather than the color?
j
Copy code
colors = ButtonConstants.defaultButtonColors(
    backgroundColor = when (index) {
        0 -> if (isEnabled) Color(0xff81C784) else disabledColor
        1 -> if (isEnabled) Color(0xff9575CD) else disabledColor
        2 -> if (isEnabled) Color(0xffFF8A65) else disabledColor
        3 -> if (isEnabled) Color(0xff5C6BC0) else disabledColor
        else -> Color.Unspecified
    }
),
n
@Jeisson Sáchica Ok, I understand, makes sense!
j
Then remove the MutableState from the composable and just take a lambda
Copy code
fun QuickOptions(context: Context, onColorChanged: (Color) -> Unit) {
    ...
}
n
briiliant, thanks for this, will try it now 😊
j
And on the callback of the
Button
call the lambda with the new color:
Copy code
onClick = {
    if (isSelectable == true) {
        val newColor = when (index) {
            0 -> if (isEnabled) Color(0xff81C784) else disabledColor
            1 -> if (isEnabled) Color(0xff9575CD) else disabledColor
            2 -> if (isEnabled) Color(0xffFF8A65) else disabledColor
            3 -> if (isEnabled) Color(0xff5C6BC0) else disabledColor
            else -> Color.Unspecified
        }
        onColorChanged(newColor)
        ...
    }
}
And finally you can pass the lambda on your top composable:
Copy code
QuickOptions(context = context, accentColor) { newColor ->
    accentColor.value = newColor
}
n
@Jeisson Sáchica Just to say that it is now working perfectly. Thanks again for your help! 👍
🙌 1