Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Compose UI Row+Column away from subtype #2410

Merged
merged 1 commit into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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