JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.96k stars 1.16k forks source link

AlertDialog + LazyColumn causes crash or weird behaviour #2531

Closed felixdivo closed 1 year ago

felixdivo commented 1 year ago

The following code crashes:

    @OptIn(ExperimentalMaterialApi::class)
    AlertDialog(
        onDismissRequest = { },
        dismissButton = {
            Button(onClick = { }) { Text("Close") }
        },
        confirmButton = {
            Button(onClick = { }) { Text("Yay") }
        },
        title = {
            Text("Heading")
        },
        text = {
            val state = rememberLazyListState()
            Box {
                LazyColumn(
                    modifier = Modifier.padding(end = LocalScrollbarStyle.current.thickness),
                    state = state,
                ) {
                    items(500) { index ->
                        Text(
                            text = "Row $index",
                            modifier = Modifier.padding(16.dp),
                        )
                    }
                }
                VerticalScrollbar(
                    modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(),
                    adapter = rememberScrollbarAdapter(scrollState = state),
                )
            }
        },
    )

with

Stack trace ``` Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Asking for intrinsic measurements of SubcomposeLayout layouts is not supported. This includes components that are built on top of SubcomposeLayout, such as lazy lists, BoxWithConstraints, TabRow, etc. To mitigate this: - if intrinsic measurements are used to achieve 'match parent' sizing,, consider replacing the parent of the component with a custom layout which controls the order in which children are measured, making intrinsic measurement not needed - adding a size modifier to the component, in order to fast return the queried intrinsic measurement. at androidx.compose.ui.node.LayoutNode$NoIntrinsicsMeasurePolicy.minIntrinsicWidth(LayoutNode.kt:445) at androidx.compose.ui.node.LayoutNode$NoIntrinsicsMeasurePolicy.minIntrinsicWidth(LayoutNode.kt:441) at androidx.compose.ui.node.IntrinsicsPolicy.minIntrinsicWidth(IntrinsicsPolicy.kt:42) at androidx.compose.ui.node.InnerPlaceable.minIntrinsicWidth(InnerPlaceable.kt:52) at androidx.compose.ui.layout.MeasuringIntrinsics$DefaultIntrinsicMeasurable.measure-BRTryo0(LayoutModifier.kt:206) at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:405) at androidx.compose.ui.layout.MeasuringIntrinsics.minWidth$ui(LayoutModifier.kt:131) at androidx.compose.ui.layout.LayoutModifier.minIntrinsicWidth(LayoutModifier.kt:68) at androidx.compose.ui.node.ModifiedLayoutNode.minIntrinsicWidth(ModifiedLayoutNode.kt:63) at androidx.compose.ui.layout.MeasuringIntrinsics$DefaultIntrinsicMeasurable.measure-BRTryo0(LayoutModifier.kt:206) at androidx.compose.foundation.layout.PaddingModifier.measure-3p2s80s(Padding.kt:364) at androidx.compose.ui.layout.MeasuringIntrinsics.minWidth$ui(LayoutModifier.kt:131) at androidx.compose.ui.layout.LayoutModifier.minIntrinsicWidth(LayoutModifier.kt:68) at androidx.compose.ui.node.ModifiedLayoutNode.minIntrinsicWidth(ModifiedLayoutNode.kt:63) at androidx.compose.ui.node.OuterMeasurablePlaceable.minIntrinsicWidth(OuterMeasurablePlaceable.kt:178) at androidx.compose.ui.node.LayoutNode.minIntrinsicWidth(LayoutNode.kt:1442) at androidx.compose.ui.layout.DefaultIntrinsicMeasurable.measure-BRTryo0(Layout.kt:314) at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:145) at androidx.compose.ui.layout.MeasurePolicy.minIntrinsicWidth(MeasurePolicy.kt:105) at androidx.compose.ui.node.IntrinsicsPolicy.minIntrinsicWidth(IntrinsicsPolicy.kt:42) at androidx.compose.ui.node.InnerPlaceable.minIntrinsicWidth(InnerPlaceable.kt:52) at androidx.compose.ui.node.OuterMeasurablePlaceable.minIntrinsicWidth(OuterMeasurablePlaceable.kt:178) at androidx.compose.ui.node.LayoutNode.minIntrinsicWidth(LayoutNode.kt:1442) at androidx.compose.ui.layout.DefaultIntrinsicMeasurable.measure-BRTryo0(Layout.kt:314) at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:123) at androidx.compose.ui.layout.MeasurePolicy.minIntrinsicWidth(MeasurePolicy.kt:105) at androidx.compose.ui.node.IntrinsicsPolicy.minIntrinsicWidth(IntrinsicsPolicy.kt:42) at androidx.compose.ui.node.InnerPlaceable.minIntrinsicWidth(InnerPlaceable.kt:52) at androidx.compose.ui.layout.MeasuringIntrinsics$DefaultIntrinsicMeasurable.measure-BRTryo0(LayoutModifier.kt:206) at androidx.compose.foundation.layout.PaddingModifier.measure-3p2s80s(Padding.kt:364) at androidx.compose.ui.layout.MeasuringIntrinsics.minWidth$ui(LayoutModifier.kt:131) at androidx.compose.ui.layout.LayoutModifier.minIntrinsicWidth(LayoutModifier.kt:68) at androidx.compose.ui.node.ModifiedLayoutNode.minIntrinsicWidth(ModifiedLayoutNode.kt:63) at androidx.compose.ui.node.OuterMeasurablePlaceable.minIntrinsicWidth(OuterMeasurablePlaceable.kt:178) at androidx.compose.ui.node.LayoutNode.minIntrinsicWidth(LayoutNode.kt:1442) at androidx.compose.ui.layout.DefaultIntrinsicMeasurable.measure-BRTryo0(Layout.kt:314) at androidx.compose.material.AlertDialogKt$AlertDialogBaselineLayout$2.measure-3p2s80s(AlertDialog.kt:117) at androidx.compose.ui.layout.MeasurePolicy.minIntrinsicWidth(MeasurePolicy.kt:105) at androidx.compose.ui.node.IntrinsicsPolicy.minIntrinsicWidth(IntrinsicsPolicy.kt:42) at androidx.compose.ui.node.InnerPlaceable.minIntrinsicWidth(InnerPlaceable.kt:52) at androidx.compose.ui.node.OuterMeasurablePlaceable.minIntrinsicWidth(OuterMeasurablePlaceable.kt:178) at androidx.compose.ui.node.LayoutNode.minIntrinsicWidth(LayoutNode.kt:1442) at androidx.compose.foundation.layout.IntrinsicMeasureBlocks$VerticalMinWidth$1$1.invoke(RowColumnImpl.kt:591) at androidx.compose.foundation.layout.IntrinsicMeasureBlocks$VerticalMinWidth$1$1.invoke(RowColumnImpl.kt:589) at androidx.compose.foundation.layout.RowColumnImplKt.intrinsicCrossAxisSize(RowColumnImpl.kt:758) at androidx.compose.foundation.layout.RowColumnImplKt.intrinsicSize(RowColumnImpl.kt:684) at androidx.compose.foundation.layout.RowColumnImplKt.access$intrinsicSize(RowColumnImpl.kt:1) at androidx.compose.foundation.layout.IntrinsicMeasureBlocks$VerticalMinWidth$1.invoke(RowColumnImpl.kt:589) at androidx.compose.foundation.layout.IntrinsicMeasureBlocks$VerticalMinWidth$1.invoke(RowColumnImpl.kt:588) at androidx.compose.foundation.layout.RowColumnImplKt$rowColumnMeasurePolicy$1.minIntrinsicWidth(RowColumnImpl.kt:268) at androidx.compose.ui.node.IntrinsicsPolicy.minIntrinsicWidth(IntrinsicsPolicy.kt:42) at androidx.compose.ui.node.InnerPlaceable.minIntrinsicWidth(InnerPlaceable.kt:52) at androidx.compose.ui.node.OuterMeasurablePlaceable.minIntrinsicWidth(OuterMeasurablePlaceable.kt:178) at androidx.compose.ui.node.LayoutNode.minIntrinsicWidth(LayoutNode.kt:1442) at androidx.compose.ui.layout.DefaultIntrinsicMeasurable.measure-BRTryo0(Layout.kt:314) at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:123) at androidx.compose.ui.layout.MeasurePolicy.minIntrinsicWidth(MeasurePolicy.kt:105) at androidx.compose.ui.node.IntrinsicsPolicy.minIntrinsicWidth(IntrinsicsPolicy.kt:42) at androidx.compose.ui.node.InnerPlaceable.minIntrinsicWidth(InnerPlaceable.kt:52) at androidx.compose.ui.layout.MeasuringIntrinsics$DefaultIntrinsicMeasurable.measure-BRTryo0(LayoutModifier.kt:206) at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:405) at androidx.compose.ui.layout.MeasuringIntrinsics.minWidth$ui(LayoutModifier.kt:131) at androidx.compose.ui.layout.LayoutModifier.minIntrinsicWidth(LayoutModifier.kt:68) at androidx.compose.ui.node.ModifiedLayoutNode.minIntrinsicWidth(ModifiedLayoutNode.kt:63) at androidx.compose.foundation.layout.MinIntrinsicWidthModifier.calculateContentConstraints-l58MMJ0(Intrinsic.kt:117) at androidx.compose.foundation.layout.IntrinsicSizeModifier.measure-3p2s80s(Intrinsic.kt:252) at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:53) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1428) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1427) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2117) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:113) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:78) at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:66) at androidx.compose.ui.node.LayoutNode.performMeasure-BRTryo0$ui(LayoutNode.kt:1427) at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:94) at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:75) at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1366) at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:123) at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:44) at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:405) at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:53) at androidx.compose.ui.graphics.BlockGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:342) at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:53) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1428) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1427) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2117) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:113) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:78) at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:66) at androidx.compose.ui.node.LayoutNode.performMeasure-BRTryo0$ui(LayoutNode.kt:1427) at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:94) at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:75) at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1366) at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:123) at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:44) at androidx.compose.foundation.layout.FillModifier.measure-3p2s80s(Size.kt:658) at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:53) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1428) at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1427) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2117) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:113) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:78) at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:66) at androidx.compose.ui.node.LayoutNode.performMeasure-BRTryo0$ui(LayoutNode.kt:1427) at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:94) at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:75) at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1366) at androidx.compose.ui.window.PopupLayout_skikoKt$PopupLayout$6$composition$1$1$measure$1.invoke(PopupLayout.skiko.kt:91) at androidx.compose.ui.window.PopupLayout_skikoKt$PopupLayout$6$composition$1$1$measure$1.invoke(PopupLayout.skiko.kt:89) at androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren(MeasureScope.kt:70) at androidx.compose.ui.node.LayoutNode$layoutChildren$1.invoke(LayoutNode.kt:968) at androidx.compose.ui.node.LayoutNode$layoutChildren$1.invoke(LayoutNode.kt:953) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2117) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:113) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:78) at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutSnapshotReads$ui(OwnerSnapshotObserver.kt:52) at androidx.compose.ui.node.LayoutNode.layoutChildren$ui(LayoutNode.kt:953) at androidx.compose.ui.node.LayoutNode.onNodePlaced$ui(LayoutNode.kt:938) at androidx.compose.ui.node.InnerPlaceable.placeAt-f8xVGno(InnerPlaceable.kt:79) at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:31) at androidx.compose.ui.layout.Placeable$PlacementScope.placeWithLayer-aW-9-wM(Placeable.kt:398) at androidx.compose.ui.node.OuterMeasurablePlaceable.placeOuterWrapper-f8xVGno(OuterMeasurablePlaceable.kt:163) at androidx.compose.ui.node.OuterMeasurablePlaceable.access$placeOuterWrapper-f8xVGno(OuterMeasurablePlaceable.kt:28) at androidx.compose.ui.node.OuterMeasurablePlaceable$placeAt$1.invoke(OuterMeasurablePlaceable.kt:149) at androidx.compose.ui.node.OuterMeasurablePlaceable$placeAt$1.invoke(OuterMeasurablePlaceable.kt:148) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2117) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:113) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:78) at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutModifierSnapshotReads$ui(OwnerSnapshotObserver.kt:59) at androidx.compose.ui.node.OuterMeasurablePlaceable.placeAt-f8xVGno(OuterMeasurablePlaceable.kt:148) at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:31) at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelativeWithLayer(Placeable.kt:387) at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelativeWithLayer$default(Placeable.kt:246) at androidx.compose.ui.layout.RootMeasurePolicy$measure$2.invoke(RootMeasurePolicy.kt:40) at androidx.compose.ui.layout.RootMeasurePolicy$measure$2.invoke(RootMeasurePolicy.kt:39) at androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren(MeasureScope.kt:70) at androidx.compose.ui.node.LayoutNode$layoutChildren$1.invoke(LayoutNode.kt:968) at androidx.compose.ui.node.LayoutNode$layoutChildren$1.invoke(LayoutNode.kt:953) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2117) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:113) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:78) at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutSnapshotReads$ui(OwnerSnapshotObserver.kt:52) at androidx.compose.ui.node.LayoutNode.layoutChildren$ui(LayoutNode.kt:953) at androidx.compose.ui.node.LayoutNode.onNodePlaced$ui(LayoutNode.kt:938) at androidx.compose.ui.node.InnerPlaceable.placeAt-f8xVGno(InnerPlaceable.kt:79) at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:31) at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50(Placeable.kt:372) at androidx.compose.ui.node.OuterMeasurablePlaceable.placeOuterWrapper-f8xVGno(OuterMeasurablePlaceable.kt:161) at androidx.compose.ui.node.OuterMeasurablePlaceable.access$placeOuterWrapper-f8xVGno(OuterMeasurablePlaceable.kt:28) at androidx.compose.ui.node.OuterMeasurablePlaceable$placeAt$1.invoke(OuterMeasurablePlaceable.kt:149) at androidx.compose.ui.node.OuterMeasurablePlaceable$placeAt$1.invoke(OuterMeasurablePlaceable.kt:148) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2117) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:113) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:78) at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutModifierSnapshotReads$ui(OwnerSnapshotObserver.kt:59) at androidx.compose.ui.node.OuterMeasurablePlaceable.placeAt-f8xVGno(OuterMeasurablePlaceable.kt:148) at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:31) at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative(Placeable.kt:361) at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative$default(Placeable.kt:179) at androidx.compose.ui.node.LayoutNode.place$ui(LayoutNode.kt:811) at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:278) at androidx.compose.ui.node.MeasureAndLayoutDelegate.access$remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:38) at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:208) at androidx.compose.ui.platform.SkiaBasedOwner.measureAndLayout(SkiaBasedOwner.skiko.kt:266) at androidx.compose.ui.node.Owner.measureAndLayout$default(Owner.kt:196) at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:416) at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:326) at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:325) at androidx.compose.ui.awt.ComposeLayer.catchExceptions(ComposeLayer.desktop.kt:109) at androidx.compose.ui.awt.ComposeLayer.access$catchExceptions(ComposeLayer.desktop.kt:87) at androidx.compose.ui.awt.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:325) at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:510) at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54) at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invokeSuspend(Direct3DRedrawer.kt:40) at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt) at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt) at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at java.desktop/java.awt.event.InvocationEvent.dispatch$$$capture(InvocationEvent.java:316) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@5cef8269, SwingDispatcher@3ec7c776] ```

(There is also one comma too much in the error message.)

If I change Modifier.padding(end = LocalScrollbarStyle.current.thickness) to Modifier.width(300.dp).height(300.dp).padding(end = LocalScrollbarStyle.current.thickness) the exception disappears, but the bahaviour is even weirder:

Animation

m-sasha commented 1 year ago

Putting scrollable content inside an AlertDialog is actually not a supported use-case. This is the case in Android too: https://issuetracker.google.com/issues/217151230#comment7

We do have plans to add a non-opinionated, "clean" dialog widget where you could put any content, and you can follow that effort here: https://github.com/JetBrains/compose-jb/issues/933

In the meanwhile, you could use this basic implementation that uses Popup:

import androidx.compose.foundation.LocalScrollbarStyle
import androidx.compose.foundation.VerticalScrollbar
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollbarAdapter
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.type
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.*
import androidx.compose.ui.window.*
import kotlinx.coroutines.*

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun PopupDialog(
    onDismissRequest: () -> Unit,
    content: @Composable () -> Unit
) {
    Popup(
        popupPositionProvider = object : PopupPositionProvider {
            override fun calculatePosition(
                anchorBounds: IntRect,
                windowSize: IntSize,
                layoutDirection: LayoutDirection,
                popupContentSize: IntSize
            ): IntOffset = IntOffset.Zero
        },
        focusable = true,
        onDismissRequest = onDismissRequest,
        onKeyEvent = {
            if ((it.type == KeyEventType.KeyDown) && (it.key == Key.Escape)) {
                onDismissRequest()
                true
            } else {
                false
            }
        },
    ) {
        val scrimColor = Color.Black.copy(alpha = 0.32f)
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(scrimColor)
                .pointerInput(onDismissRequest) {
                    detectTapGestures(onPress = { onDismissRequest() })
                },
            contentAlignment = Alignment.Center
        ) {
            Surface(Modifier.pointerInput(onDismissRequest) {
                detectTapGestures(onPress = {
                    // Workaround to disable clicks on Surface background https://github.com/JetBrains/compose-jb/issues/2581
                })
            }, elevation = 24.dp) {
                content()
            }
        }
    }
}

fun main() = singleWindowApplication(
    state = WindowState(width = 640.dp, height = 480.dp)
) {
    var dialogVisible by remember { mutableStateOf(true) }
    if (dialogVisible){
        PopupDialog(
            onDismissRequest = { dialogVisible = false },
        ) {
            Box(
                modifier = Modifier.size(300.dp, 200.dp)
            ) {
                val state = rememberLazyListState()
                LazyColumn(
                    modifier = Modifier.padding(end = LocalScrollbarStyle.current.thickness),
                    state = state,
                ) {
                    items(500) { index ->
                        Text(
                            text = "Row $index",
                            modifier = Modifier.padding(16.dp).fillMaxWidth(),
                        )
                    }
                }
                VerticalScrollbar(
                    modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(),
                    adapter = rememberScrollbarAdapter(scrollState = state),
                )
            }
        }
    }
}
cbeyls commented 1 year ago

@m-sasha Support for scrollable content inside AlertDialog is actually mandatory because there is no warranty that a simple text will always fit on screen, especially in landscape mode. And yes, the native and AppCompat AlertDialog support scrolling text when it's too long, so Compose AlertDialog should support this use case too.

itsReward commented 8 months ago

With the introduction of compose for desktop they should consider making possible to have scrollable content inside an alert dialog

okushnikov commented 2 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.