diff --git a/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/RedwoodComposition.kt b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/RedwoodComposition.kt index d15fdbce86..3e296a6cb6 100644 --- a/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/RedwoodComposition.kt +++ b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/RedwoodComposition.kt @@ -28,7 +28,6 @@ import androidx.compose.runtime.currentComposer import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshots.Snapshot -import app.cash.redwood.LayoutModifier import app.cash.redwood.RedwoodCodegenApi import app.cash.redwood.widget.Widget import app.cash.redwood.widget.compose.ComposeWidgetChildren @@ -73,12 +72,12 @@ public fun RedwoodComposition( provider: Widget.Provider, onEndChanges: () -> Unit = {}, ): RedwoodComposition { - return WidgetRedwoodComposition(scope, WidgetApplier(provider, container, onEndChanges)) + return WidgetRedwoodComposition(scope, NodeApplier(provider, container, onEndChanges)) } private class WidgetRedwoodComposition( private val scope: CoroutineScope, - applier: WidgetApplier<*>, + applier: NodeApplier<*>, ) : RedwoodComposition { private val recomposer = Recomposer(scope.coroutineContext) private val composition = Composition(applier, recomposer) @@ -128,7 +127,7 @@ public interface RedwoodApplier { @RedwoodCodegenApi public inline fun

, W : Widget<*>> RedwoodComposeNode( crossinline factory: (P) -> W, - update: @DisallowComposableCalls Updater.() -> Unit, + update: @DisallowComposableCalls Updater>.() -> Unit, content: @Composable RedwoodComposeContent.() -> Unit, ) { // NOTE: You MUST keep the implementation of this function (or more specifically, the interaction @@ -140,13 +139,13 @@ public inline fun

, W : Widget<*>> RedwoodComposeNode( val applier = currentComposer.applier as RedwoodApplier

currentComposer.createNode { @Suppress("UNCHECKED_CAST") // Safe so long as you use generated composition function. - factory(applier.provider as P) + WidgetNode(factory(applier.provider as P) as Widget) } } else { currentComposer.useNode() } - Updater(currentComposer).update() + Updater>(currentComposer).update() RedwoodComposeContent.Instance.content() currentComposer.endNode() @@ -162,10 +161,10 @@ public class RedwoodComposeContent> { accessor: (W) -> Widget.Children<*>, content: @Composable () -> Unit, ) { - ComposeNode, Applier<*>>( + ComposeNode, Applier<*>>( factory = { @Suppress("UNCHECKED_CAST") - ChildrenWidget(accessor as (Widget) -> Widget.Children) + ChildrenNode(accessor as (Widget) -> Widget.Children) }, update = {}, content = content, @@ -176,26 +175,3 @@ public class RedwoodComposeContent> { public val Instance: RedwoodComposeContent = RedwoodComposeContent() } } - -/** - * A synthetic widget which allows the applier to differentiate between multiple groups of children. - * - * Compose's tree assumes each node only has single list of children. Or, put another way, even if - * you apply multiple children Compose treats them as a single list of child nodes. In order to - * differentiate between these children lists we introduce synthetic nodes. Every real node which - * supports one or more groups of children will have one or more of these synthetic nodes as its - * direct descendants. The nodes which are produced by each group of children will then become the - * descendants of those synthetic nodes. - */ -internal class ChildrenWidget private constructor( - var accessor: ((Widget) -> Widget.Children)?, - var children: Widget.Children?, -) : Widget { - constructor(accessor: (Widget) -> Widget.Children) : this(accessor, null) - constructor(children: Widget.Children) : this(null, children) - - override val value: Nothing get() = throw AssertionError() - override var layoutModifiers: LayoutModifier - get() = throw AssertionError() - set(_) { throw AssertionError() } -} diff --git a/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/WidgetApplier.kt b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/WidgetApplier.kt index 8c878a1042..86bb348153 100644 --- a/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/WidgetApplier.kt +++ b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/WidgetApplier.kt @@ -17,40 +17,45 @@ package app.cash.redwood.compose import androidx.compose.runtime.AbstractApplier import androidx.compose.runtime.Applier +import app.cash.redwood.LayoutModifier import app.cash.redwood.RedwoodCodegenApi import app.cash.redwood.widget.Widget /** - * An [Applier] for a tree of [Widget]s. + * An [Applier] for Redwood's tree of nodes. * - * This applier has special handling for emulating nodes which contain multiple children. Nodes in - * the tree are required to alternate between [ChildrenWidget] instances and user [Widget] subtypes - * starting at the root. This invariant is maintained by virtue of the fact that all of the input - * `@Composables` should be generated Redwood code. + * This applier has special handling for emulating widgets which contain multiple children. + * Nodes in the tree are required to alternate between [WidgetNode] and [ChildrenNode] starting + * from the root. This invariant is maintained by virtue of the fact that all of the input + * `@Composable`s should bottom out in generated Redwood code. * * For example, a widget tree may look like this: * ``` - * Children(tag=1) - * / \ - * / \ - * ToolbarNode ListNode - * · · · - * · · · - * Children(tag=1) Children(tag=2) Children(tag=1) - * | | / \ - * | | / \ - * ButtonNode ButtonNode TextNode TextNode + * ChildrenNode(root) + * / \ + * / \ + * WidgetNode WidgetNode + * / \ \ + * / \ \ + * ChildrenNode(tag=1) ChildrenNode(tag=2) ChildrenNode(tag=1) + * | | / \ + * | | / \ + * WidgetNode