https://kotlinlang.org logo
#compose
Title
# compose
j

jaqxues

10/09/2020, 8:02 PM
I have a Card + Switch. How do I handle the state so it toggles on onClick of the Card, and I can use an onCheckedChange correctly?
Current solution
Copy code
fun SwitchPreference(pref: Preference<Boolean>, text: @Composable () -> Unit) {
    var switchedState = true
    var active by remember {
        switchedState = false
        mutableStateOf(pref.getPref())
    }
    if (active) {
        pref.putPref(active)
    }
    Card(
        Modifier.fillMaxWidth().clickable(onClick = { active = !active}),
        shape = RoundedCornerShape(8.dp)
    ) {
        Row(Modifier.padding(16.dp)) {
            text()
            Spacer(Modifier.weight(1f))

            if (switchedState) {
                pref.putPref(active)
            }
            Switch(checked = active, onCheckedChange = {
                active = it
            })
        }
    }
}
a

allan.conda

10/09/2020, 8:06 PM
use
Modifier.toggleable()
should be easier
j

jaqxues

10/09/2020, 8:07 PM
on the card?
a

allan.conda

10/09/2020, 8:07 PM
replace clickable() basically
removed switchState, you don’t need it
j

jaqxues

10/09/2020, 8:09 PM
in that case, if you click directly on the switch, nothing happens
a

allan.conda

10/09/2020, 8:11 PM
Copy code
var toggled by remember{mutableStateOf(true)}
Modifier.toggleable(value = toggled, onValueChange = { toggled = it })
j

jaqxues

10/09/2020, 8:13 PM
mhm, doesnt help a lot ig, the clickable is even shorter tbh
a

allan.conda

10/09/2020, 8:14 PM
actually you seems you don’t need it, Switch already has toggleable inside
Copy code
Card(
        Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(8.dp)
    ) {
        Row(Modifier.padding(16.dp)) {
            text()
            Spacer(Modifier.weight(1f))

            var toggle by remember { mutableStateOf(pref.getPref()) }
            Switch(checked = active, onCheckedChange = {
                toggle = it
                pref.putPref(toggle)
            })
        }
    }
j

jaqxues

10/09/2020, 8:16 PM
... In that case the entire card is not clickable and you have to click exactly on the switch
Copy code
@Composable
fun SwitchPreference(pref: Preference<Boolean>, text: @Composable () -> Unit) {
    var switchedState = true
    var active by remember {
        switchedState = false
        mutableStateOf(pref.getPref())
    }
    Card(
        Modifier.fillMaxWidth().toggleable(active) { active = it },
        shape = RoundedCornerShape(8.dp)
    ) {
        if (switchedState)
            pref.putPref(active)

        Row(Modifier.padding(16.dp)) {
            text()
            Spacer(Modifier.weight(1f))
            Switch(checked = active, onCheckedChange = {
                active = it
            })
        }
    }
}
ended up with this, using and changing the state in both, card and switch
a

allan.conda

10/09/2020, 8:18 PM
try:
Copy code
var toggle by remember { mutableStateOf(pref.getPref()) }
    Card(
        Modifier.fillMaxWidth()
            .toggleable(value = toggle, {
                toggle = it
                pref.putPref(toggle)
            }),
        shape = RoundedCornerShape(8.dp)
    ) {
        Row(Modifier.padding(16.dp)) {
            text()
            Spacer(Modifier.weight(1f))

            Switch(checked = active, onCheckedChange = {
                toggle = it
                pref.putPref(toggle)
            })
        }
    }
I don’t get this part of your code:
Copy code
if (switchedState)
            pref.putPref(active)
if it checks switched to true once, it will never turn off
j

jaqxues

10/09/2020, 8:19 PM
then i have 2 putPrefs in 2 different "onToggle"/ "onCheckedChange"
a

allan.conda

10/09/2020, 8:20 PM
it should be fine, your goal is that the card click and switch click works the same
j

jaqxues

10/09/2020, 8:20 PM
switchedState is false for the initial value, true when its switched. (the remember { ... } is only executed on initial composition
so any recomposition (when "active" state changes) will trigger switchedState to be true
yeah it works, was just hoping for a more elegant solution
a

allan.conda

10/09/2020, 8:22 PM
then that’s worse, it calls putPref on every recomposition
Copy code
var toggle by remember { mutableStateOf(pref.getPref()) }
    val onToggle = { 
      toggle = it
      pref.putPref(it)
    }
    Card(
        Modifier.fillMaxWidth()
            .toggleable(value = toggle, onToggle),
        shape = RoundedCornerShape(8.dp)
    ) {
        Row(Modifier.padding(16.dp)) {
            text()
            Spacer(Modifier.weight(1f))

            Switch(checked = active, onCheckedChange = onToggle)
        }
    }
j

jaqxues

10/09/2020, 8:23 PM
putPref should be executed on every recomposition recomposition means the "active" state is changed, which is what i want
a

allan.conda

10/09/2020, 8:23 PM
you shouldn’t expect that, the devs say recomposition can happen at any time, you shouldn’t trust it only happens when you change active
✔️ 1
j

jaqxues

10/09/2020, 8:24 PM
true Switching back to local functions then ig