I want to emit 6 times the same composable (Card),...
# compose
o
I want to emit 6 times the same composable (Card), but in the middle, I want a Divider. So I want to get something like: C C C D C C C How would one do this?
f
Copy code
repeat(3) { C() }
D()
repeat(3) { C() }

//or maybe

repeat(7) {
  if (it == 3) D() else C()
}
o
I have the first one already, but I think it could be cleaner so I don't have to duplicate the logic I'm writing in the two repeat blocks. I was thinking about doing something like: repeat(6) { C }.add(3, D)
But that obviously doesn't work in Compose
f
You can make something like that work. You have the full power of Kotlin, the possibilities are endless 😄
o
@Filip Wiesner I was thinking about that, but it's not that easy. I think the problem here is, that Compose doesn't return anything, but emits things. I think it would be easy to do something like this in a return-based system like ReactJS, but in Compose, every time you call a Composable, it runs. It's like a side effect
f
Couldn't you return a @Composable function? 🤔
o
Hmm gonna try
f
Something like movableContentOf()
o
Copy code
buildList {
            repeat(6) { index ->
                add(
                    @Composable {
                        C(...)
                    }
                )
            }
        }
This gives me the following error: Internal Error occurred while analyzing this expression
c
Do not oversimplify things, they just get messy after a certain point
👍 1
I think there is nothing wrong with the 1st suggestion
but if you want you can have a
Copy code
@Composable
fun CardGroup(count: Int) {
    repeat(count) { Card() }
}
and then write
Copy code
CardGroup(count = 3)
Divider()
CardGroup(count = 3)
o
@Csaba Szugyiczki
Copy code
Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = modifier.fillMaxWidth(),
    ) {

        repeat(3) { index ->

            Cell(
                value = value[index],
                onValueChange = { newNumber ->
                    val newValue = value.toMutableList().apply { set(index, newNumber) }
                    val newNumberWasEntered = value != newValue && newNumber != null

                    onValueChange(newValue)

                    if (newNumberWasEntered) {
                        focusManager.moveFocus(FocusDirection.Right)
                    }
                },
                imeAction = ImeAction.Next,
                onKeyboardAction = {
                    focusManager.moveFocus(FocusDirection.Right)
                },
                modifier = Modifier
                    .weight(1f)
                    .padding(end = 10.dp)
                    .onFocusChanged { focusState ->
                        if (focusState.isFocused) {
                            val newValue = value
                                .toMutableList()
                                .apply { set(index, null) }
                                .toList()
                            onValueChange(newValue)
                        }
                    },
            )
        }

        Divider(
            color = MaterialTheme.colors.primary,
            thickness = 2.dp,
            modifier = Modifier
                .width(10.dp)
        )

        repeat(3) { loopIndex ->

            val digitIndex = loopIndex + 3

            val isLastCell = digitIndex == value.lastIndex

            Cell(
                value = value[digitIndex],
                onValueChange = { newNumber ->
                    val newValue = value
                        .toMutableList()
                        .apply { set(digitIndex, newNumber) }
                        .toList()
                    val newNumberWasEntered = value != newValue && newNumber != null
                    onValueChange(newValue)
                    if (newNumberWasEntered) {
                        focusManager.moveFocus(FocusDirection.Right)
                    }
                },
                imeAction =
                if (isLastCell) {
                    ImeAction.Done
                } else {
                    ImeAction.Next
                },
                onKeyboardAction = {
                    if (isLastCell) {
                        focusManager.clearFocus()
                    } else {
                        focusManager.moveFocus(FocusDirection.Right)
                    }
                },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(start = 10.dp)
                    .weight(1f)
                    .onFocusChanged { focusState ->
                        if (focusState.isFocused) {
                            val newValue = value
                                .toMutableList()
                                .apply { set(digitIndex, null) }
                                .toList()
                            onValueChange(newValue)
                        }
                    },
            )
        }
    }
c
What you mean by composable lambda is I think referred to as Slot in Compose and looks like this:
content: @Composable () -> Unit
This concept is all over compose
o
Above is my real code
c
Ohh, I think I know what you want to create. Is it a 6 digit input box? I think it is much easier to have only one invisible Input box, and just display the entered digits however you want
o
@Csaba Szugyiczki In react, you can do something like
Copy code
const items = Array(6) { C() }
items.splice(3, 0, D())
// items is now C C C D C C C
How would you do this in Compose?
c
That is not possible in Compose Im affraid
o
@Csaba Szugyiczki yes it is a 6 digit input box. Could you elaborate on the one invisible input box part?
@Csaba Szugyiczki that's unfortunate, and a bit dissappointing IMO. It reduces the power of Compose if that's the case in my eyes. I'm open to be proven wrong
c
Basically you would have an input field covering your whole view. But make it transparent. And below it you could draw the 6 boxes in a Row, and have whatever decoration on the boxes, or between them. You just have to make sure the user knows which digit is typed at the moment
Composable functions return nothing. They are plain kotlin functions without a return value, so there is nothing that you could add to a list either
o
Not sure if it is easier to build something like this into one view
(Just the 6 boxes part)
Yes, they return nothing indeed. Which can be an advantage in some cases: like being able to write:
Copy code
if (showButton) {
    Button()
}
instead of
Copy code
if (showButton) {
    Button()
} else {
    null
}
but it also has it's flaws, as you now lose the power of the regular programming power of transforming and mapping values. Example is that we can't achieve my React example few messages above
It loses the purity of functional programming
f
The Composable functions are intended for "Data -> UI" transformation. You can still "transform and map" the data before you emit UI based on it.
o
Hmm I guess so, but that means I now have to create a new data model for each UI component, which is more work
a
Something like
Copy code
val card = @Composable { Card() }
repeat(3) { card() }
D()
repeat(3) { card() }
will work.
☝️ 1
👍 1
o
Yep that's what I've sticked with