Skip to content

Commit

Permalink
Migrate Compose UI Row+Column away from subtype
Browse files Browse the repository at this point in the history
When widgets switch to abstract classes, this will no longer be allowed.
  • Loading branch information
JakeWharton committed Oct 25, 2024
1 parent 7443ba1 commit fcc1b2d
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,19 @@ final val app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_Bo
final val app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_BoxMeasurePolicy$stableprop // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_BoxMeasurePolicy$stableprop|#static{}app_cash_redwood_layout_composeui_BoxMeasurePolicy$stableprop[0]
final val app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeMeasureCallback$stableprop // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeMeasureCallback$stableprop|#static{}app_cash_redwood_layout_composeui_ComposeMeasureCallback$stableprop[0]
final val app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiBox$stableprop // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiBox$stableprop|#static{}app_cash_redwood_layout_composeui_ComposeUiBox$stableprop[0]
final val app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiColumn$stableprop // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiColumn$stableprop|#static{}app_cash_redwood_layout_composeui_ComposeUiColumn$stableprop[0]
final val app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiFlexContainer$stableprop // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiFlexContainer$stableprop|#static{}app_cash_redwood_layout_composeui_ComposeUiFlexContainer$stableprop[0]
final val app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiRedwoodLayoutWidgetFactory$stableprop // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiRedwoodLayoutWidgetFactory$stableprop|#static{}app_cash_redwood_layout_composeui_ComposeUiRedwoodLayoutWidgetFactory$stableprop[0]
final val app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiRow$stableprop // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiRow$stableprop|#static{}app_cash_redwood_layout_composeui_ComposeUiRow$stableprop[0]
final val app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiSpacer$stableprop // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiSpacer$stableprop|#static{}app_cash_redwood_layout_composeui_ComposeUiSpacer$stableprop[0]

final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_BoxChildLayoutInfo$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_BoxChildLayoutInfo$stableprop_getter|app_cash_redwood_layout_composeui_BoxChildLayoutInfo$stableprop_getter(){}[0]
final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_BoxChildrenLayoutInfo$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_BoxChildrenLayoutInfo$stableprop_getter|app_cash_redwood_layout_composeui_BoxChildrenLayoutInfo$stableprop_getter(){}[0]
final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_BoxMeasurePolicy$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_BoxMeasurePolicy$stableprop_getter|app_cash_redwood_layout_composeui_BoxMeasurePolicy$stableprop_getter(){}[0]
final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeMeasureCallback$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeMeasureCallback$stableprop_getter|app_cash_redwood_layout_composeui_ComposeMeasureCallback$stableprop_getter(){}[0]
final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiBox$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiBox$stableprop_getter|app_cash_redwood_layout_composeui_ComposeUiBox$stableprop_getter(){}[0]
final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiColumn$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiColumn$stableprop_getter|app_cash_redwood_layout_composeui_ComposeUiColumn$stableprop_getter(){}[0]
final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiFlexContainer$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiFlexContainer$stableprop_getter|app_cash_redwood_layout_composeui_ComposeUiFlexContainer$stableprop_getter(){}[0]
final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiRedwoodLayoutWidgetFactory$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiRedwoodLayoutWidgetFactory$stableprop_getter|app_cash_redwood_layout_composeui_ComposeUiRedwoodLayoutWidgetFactory$stableprop_getter(){}[0]
final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiRow$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiRow$stableprop_getter|app_cash_redwood_layout_composeui_ComposeUiRow$stableprop_getter(){}[0]
final fun app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiSpacer$stableprop_getter(): kotlin/Int // app.cash.redwood.layout.composeui/app_cash_redwood_layout_composeui_ComposeUiSpacer$stableprop_getter|app_cash_redwood_layout_composeui_ComposeUiSpacer$stableprop_getter(){}[0]
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ import app.cash.paparazzi.DeviceConfig
import app.cash.paparazzi.Paparazzi
import app.cash.redwood.layout.AbstractFlexContainerTest
import app.cash.redwood.layout.TestFlexContainer
import app.cash.redwood.layout.api.Constraint
import app.cash.redwood.layout.api.Overflow
import app.cash.redwood.layout.widget.Column
import app.cash.redwood.layout.widget.Row
import app.cash.redwood.layout.widget.Spacer
import app.cash.redwood.snapshot.testing.ComposeSnapshotter
import app.cash.redwood.snapshot.testing.ComposeUiTestWidgetFactory
import app.cash.redwood.ui.Px
import app.cash.redwood.widget.compose.ComposeWidgetChildren
import app.cash.redwood.yoga.FlexDirection
import com.android.resources.LayoutDirection
import kotlinx.coroutines.runBlocking
Expand All @@ -51,18 +54,26 @@ class ComposeUiFlexContainerTest(
override fun flexContainer(
direction: FlexDirection,
backgroundColor: Int,
): ComposeTestFlexContainer {
): TestFlexContainer<@Composable () -> Unit> {
return ComposeTestFlexContainer(direction, backgroundColor)
.apply { applyDefaults() }
.apply { (this as TestFlexContainer<*>).applyDefaults() }
}

override fun row() = flexContainer(FlexDirection.Row)
override fun row(): Row<@Composable () -> Unit> = ComposeUiRow()
.apply {
container.testOnlyModifier = Modifier.background(Color(defaultBackgroundColor))
applyDefaults()
}

override fun column() = flexContainer(FlexDirection.Column)
override fun column(): Column<@Composable () -> Unit> = ComposeUiColumn()
.apply {
container.testOnlyModifier = Modifier.background(Color(defaultBackgroundColor))
applyDefaults()
}

override fun spacer(backgroundColor: Int): Spacer<@Composable () -> Unit> {
// TODO: honor backgroundColor.
return ComposeUiRedwoodLayoutWidgetFactory().Spacer()
return ComposeUiSpacer()
}

override fun snapshotter(widget: @Composable () -> Unit) = ComposeSnapshotter(paparazzi, widget)
Expand All @@ -71,17 +82,22 @@ class ComposeUiFlexContainerTest(
private val delegate: ComposeUiFlexContainer,
) : TestFlexContainer<@Composable () -> Unit>,
YogaFlexContainer<@Composable () -> Unit> by delegate {
override val children: ComposeWidgetChildren = delegate.children

constructor(direction: FlexDirection, backgroundColor: Int) : this(
ComposeUiFlexContainer(direction).apply {
testOnlyModifier = Modifier.background(Color(backgroundColor))
},
)

override fun onScroll(onScroll: ((Px) -> Unit)?) {
delegate.onScroll(onScroll)
}
override val value get() = delegate.value
override var modifier by delegate::modifier

override val children get() = delegate.children

override fun width(width: Constraint) = delegate.width(width)
override fun height(height: Constraint) = delegate.height(height)
override fun overflow(overflow: Overflow) = delegate.overflow(overflow)
override fun onScroll(onScroll: ((Px) -> Unit)?) = delegate.onScroll(onScroll)

override fun scroll(offset: Px) {
runBlocking {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import app.cash.redwood.layout.api.Constraint
import app.cash.redwood.layout.api.CrossAxisAlignment
import app.cash.redwood.layout.api.MainAxisAlignment
import app.cash.redwood.layout.api.Overflow
import app.cash.redwood.layout.widget.Column
import app.cash.redwood.layout.widget.Row
import app.cash.redwood.ui.Density
import app.cash.redwood.ui.Margin
import app.cash.redwood.ui.Px
Expand All @@ -56,6 +58,38 @@ import app.cash.redwood.yoga.Node
import app.cash.redwood.yoga.Size
import app.cash.redwood.yoga.isHorizontal

internal class ComposeUiColumn : Column<@Composable () -> Unit> {
internal val container = ComposeUiFlexContainer(FlexDirection.Column)

override val value get() = container.value
override var modifier by container::modifier
override val children get() = container.children

override fun width(width: Constraint) = container.width(width)
override fun height(height: Constraint) = container.height(height)
override fun margin(margin: Margin) = container.margin(margin)
override fun overflow(overflow: Overflow) = container.overflow(overflow)
override fun horizontalAlignment(horizontalAlignment: CrossAxisAlignment) = container.horizontalAlignment(horizontalAlignment)
override fun verticalAlignment(verticalAlignment: MainAxisAlignment) = container.verticalAlignment(verticalAlignment)
override fun onScroll(onScroll: ((Px) -> Unit)?) = container.onScroll(onScroll)
}

internal class ComposeUiRow : Row<@Composable () -> Unit> {
internal val container = ComposeUiFlexContainer(FlexDirection.Row)

override val value get() = container.value
override var modifier by container::modifier
override val children get() = container.children

override fun width(width: Constraint) = container.width(width)
override fun height(height: Constraint) = container.height(height)
override fun margin(margin: Margin) = container.margin(margin)
override fun overflow(overflow: Overflow) = container.overflow(overflow)
override fun horizontalAlignment(horizontalAlignment: MainAxisAlignment) = container.horizontalAlignment(horizontalAlignment)
override fun verticalAlignment(verticalAlignment: CrossAxisAlignment) = container.verticalAlignment(verticalAlignment)
override fun onScroll(onScroll: ((Px) -> Unit)?) = container.onScroll(onScroll)
}

internal class ComposeUiFlexContainer(
private val flexDirection: FlexDirection,
) : YogaFlexContainer<@Composable () -> Unit> {
Expand Down Expand Up @@ -85,6 +119,7 @@ internal class ComposeUiFlexContainer(
}

override fun margin(margin: Margin) {
super.margin(margin)
this.margin = margin
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ import app.cash.redwood.layout.widget.Column
import app.cash.redwood.layout.widget.RedwoodLayoutWidgetFactory
import app.cash.redwood.layout.widget.Row
import app.cash.redwood.layout.widget.Spacer
import app.cash.redwood.yoga.FlexDirection

public class ComposeUiRedwoodLayoutWidgetFactory : RedwoodLayoutWidgetFactory<@Composable () -> Unit> {
override fun Box(): Box<@Composable () -> Unit> = ComposeUiBox()
override fun Column(): Column<@Composable () -> Unit> = ComposeUiFlexContainer(FlexDirection.Column)
override fun Row(): Row<@Composable () -> Unit> = ComposeUiFlexContainer(FlexDirection.Row)
override fun Column(): Column<@Composable () -> Unit> = ComposeUiColumn()
override fun Row(): Row<@Composable () -> Unit> = ComposeUiRow()
override fun Spacer(): Spacer<@Composable () -> Unit> = ComposeUiSpacer()
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ import kotlin.test.assertTrue
abstract class AbstractFlexContainerTest<T : Any> {
abstract val widgetFactory: TestWidgetFactory<T>

protected val defaultBackgroundColor = argb(51, 0, 0, 255)

abstract fun flexContainer(
direction: FlexDirection,
backgroundColor: Int = argb(51, 0, 0, 255),
backgroundColor: Int = defaultBackgroundColor,
): TestFlexContainer<T>

/**
Expand All @@ -63,6 +65,36 @@ abstract class AbstractFlexContainerTest<T : Any> {
onScroll(null)
}

/**
* Yoga node’s default values for properties like alignment are different from Redwood's default
* values, so we explicitly apply those defaults here. This is only necessary in tests; in
* production the framework explicitly sets every property.
*/
protected fun Row<*>.applyDefaults() {
width(Constraint.Wrap)
height(Constraint.Wrap)
margin(Margin.Zero)
overflow(Overflow.Clip)
verticalAlignment(CrossAxisAlignment.Start)
horizontalAlignment(MainAxisAlignment.Start)
onScroll(null)
}

/**
* Yoga node’s default values for properties like alignment are different from Redwood's default
* values, so we explicitly apply those defaults here. This is only necessary in tests; in
* production the framework explicitly sets every property.
*/
protected fun Column<*>.applyDefaults() {
width(Constraint.Wrap)
height(Constraint.Wrap)
margin(Margin.Zero)
overflow(Overflow.Clip)
horizontalAlignment(CrossAxisAlignment.Start)
verticalAlignment(MainAxisAlignment.Start)
onScroll(null)
}

protected fun <T : Any> TestFlexContainer<T>.add(widget: Widget<T>) {
addAt(children.widgets.size, widget)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class UIViewFlexContainerTest(
}
}

applyDefaults()
(this as TestFlexContainer<*>).applyDefaults()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class ViewFlexContainerTest(
value.setBackgroundColor(backgroundColor)
}
return ViewTestFlexContainer(delegate)
.apply { applyDefaults() }
.apply { (this as TestFlexContainer<*>).applyDefaults() }
}

override fun row() = flexContainer(FlexDirection.Row)
Expand Down

0 comments on commit fcc1b2d

Please sign in to comment.