compose-richtext icon indicating copy to clipboard operation
compose-richtext copied to clipboard

Printable composable doesn't play well with subcomposition

Open halilozercan opened this issue 2 years ago • 2 comments

From https://twitter.com/richp_2003/status/1507732205241610245

I have Tabs, a lazy column and a sticky button on the bottom of screen. Now lazy column has a view that can be dismissed by user. I made lazy column Printable and it works fine.

Except, when the user dismisses that one item from lazy column and the recomposition happens and it crashes with error “Composable already registered” . I tried to move around the printable area. But the screen is complicated, I have many columns for the screen.

When I change the Printable position, sometime I will get error saying “nested scrolling isn’t allowed for lazy column and column”. Sometime everything will work but my sticky button will disappear. Or everything will work but then when i click print, it will be blank.

halilozercan avatar Mar 26 '22 20:03 halilozercan

Can you please share a minimum repro code or project?

halilozercan avatar Mar 26 '22 20:03 halilozercan

`AppTheme {
        val printController = rememberPrintableController()
        Column(
            Modifier.fillMaxSize()
        ) {
            val showAlertMessage = remember { mutableStateOf(someBoolean) }
            Printable(controller = printController) {
                AppTheme(forceLightMode = isBeingPrinted) {
                    LazyColumn(
                        modifier = Modifier
                            .weight(1f)
                            .background(color = AppTheme.colors.background)
                    ) {
                        if (showAlertMessage.value) {
                            item { GeneralAlertMessage(showAlertMessage) }
                        }
                        item {
                            Surface(
                                elevation = 8.dp,
                                shape = RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp),
                                modifier = Modifier
                                    .padding(top = 16.dp, start = 16.dp, end = 16.dp)
                            ) {
                                Column() {
                                    Composable1()
                                    Composable2()
                                    Composable3()
                                    Divider()
                                    Composable4(
                                       icon = R.drawable.some.drawableRes,
                                       label = R.string.some.stringRes,
                                       modifier = Modifier.padding(start = 16.dp)
                                    )
                                }
                            }
                        }
                        items(listOfThings) { thing ->
                            val padding = 16.dp
                            val density = LocalDensity.current
                            Surface(
                                shape = RectangleShape,
                                elevation = 8.dp,
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .padding(start = 16.dp, end = 16.dp)
                                    .drawWithContent {
                                        val paddingPx = with(density) { padding.toPx() }
                                        clipRect(
                                            left = -paddingPx,
                                            top = 0f,
                                            right = size.width + paddingPx,
                                            bottom = size.height + paddingPx
                                        ) {
                                            [email protected]()
                                        }
                                    }
                            ) {
                                Composable5(thing, someBoolean)
                            }
                        }
                        item {
                            val padding = 16.dp
                            val density = LocalDensity.current
                            Surface(
                                elevation = 8.dp,
                                shape = RoundedCornerShape(bottomStart = 8.dp, bottomEnd = 8.dp),
                                modifier = Modifier
                                    .padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
                                    .drawWithContent {
                                        val paddingPx = with(density) { padding.toPx() }
                                        clipRect(
                                            left = -paddingPx,
                                            top = 0f,
                                            right = size.width + paddingPx,
                                            bottom = size.height + paddingPx
                                        ) {
                                            [email protected]()
                                        }
                                    }
                            ) {
                                Column() {
                                    Divider()
                                    Composable6()
                                    Divider()
                                    Composable7()
                                    Divider()
                                    FooterComposable()
                                }
                            }
                        }
                    }
                    if (condition) {
                        StickyButtonAtBottom { printController.print("document name") }
                    }
                }

            }
        }
    }`

So I have this code that works fine and as expected without "Printable" and "AppTheme" within printable. After applying Printable and AppTheme, the StickyButtonAtBottom goes on top of the screen and is drawn over the lazyColumn (main content and the stuff that needs to be printed). Also, I have a view that is dismissible and also has to be scrollable so I have to make it an item of the lazyColumn and based on some state, I have to show/hide. You can also ignore drawWithContent part, that is just to give partial elevation. so this code doesn't only puts the sticky button all the way on top but when click print, it just crashes with the below message:

java.lang.IllegalStateException: Nesting scrollable in the same direction layouts like LazyColumn and Column(Modifier.verticalScroll()) is not allowed. If you want to add a header before the list of items please take a look on LazyColumn component which has a DSL api which allows to first add a header via item() function and then the list of items via items().

richp-2003 avatar Apr 01 '22 18:04 richp-2003