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

Add support for Modifier.flex. #1699

Merged
merged 9 commits into from
Dec 4, 2023
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 @@ -18,6 +18,7 @@ package com.example
import app.cash.redwood.Modifier
import app.cash.redwood.layout.api.CrossAxisAlignment
import app.cash.redwood.layout.api.MainAxisAlignment
import app.cash.redwood.layout.modifier.Flex as FlexModifier
import app.cash.redwood.layout.modifier.Grow as GrowModifier
import app.cash.redwood.layout.modifier.Height as HeightModifier
import app.cash.redwood.layout.modifier.HorizontalAlignment as HorizontalAlignmentModifier
Expand Down Expand Up @@ -97,6 +98,12 @@ internal fun Node.applyModifier(parentModifier: Modifier, density: Density) {
requestedMinHeight = height
requestedMaxHeight = height
}
is FlexModifier -> {
val flex = childModifier.value.coerceAtLeast(0.0).toFloat()
flexGrow = flex
flexShrink = 1.0f
flexBasis = if (flex > 0) 0.0f else -1.0f
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,10 @@ import app.cash.redwood.Modifier
* Call this in [ColumnScope] or [RowScope].
*/
@Stable
@Deprecated(
message = "This extension function is obselete now that RowScope and " +
"ColumnScope support flex directly. Remove the import for this function.",
level = DeprecationLevel.ERROR,
)
public fun Modifier.flex(`value`: Double): Modifier =
then(GrowImpl(`value`)).then(ShrinkImpl(`value`))

This file was deleted.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions redwood-layout-schema/redwood-api.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,7 @@
<property name="height" type="app.cash.redwood.ui.Dp"/>
<property name="width" type="app.cash.redwood.ui.Dp"/>
</modifier>
<modifier tag="9" type="app.cash.redwood.layout.Flex">
<property name="value" type="kotlin.Double"/>
</modifier>
</schema>
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,15 @@ public data class Size(
val width: Dp,
val height: Dp,
)

/**
* This value acts as a weight for the width/height of a widget along the main axis.
*
* For instance, setting `flex(1.0)` on each widget in a layout will create equally sized widgets.
*
* https://developer.mozilla.org/en-US/docs/Web/CSS/flex
*/
@Modifier(9, RowScope::class, ColumnScope::class)
public data class Flex(
val value: Double,
)
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import app.cash.redwood.schema.Schema
// Next tag: 5

// Modifiers
Flex::class,
Grow::class,
Height::class,
HorizontalAlignment::class,
Expand All @@ -35,7 +36,7 @@ import app.cash.redwood.schema.Schema
Size::class,
VerticalAlignment::class,
Width::class,
// Next tag: 9
// Next tag: 10
],
)
public interface RedwoodLayout
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import app.cash.redwood.Modifier
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.modifier.Flex
import app.cash.redwood.layout.modifier.Grow
import app.cash.redwood.layout.modifier.Height
import app.cash.redwood.layout.modifier.HorizontalAlignment
import app.cash.redwood.layout.modifier.Margin as MarginModifier
import app.cash.redwood.layout.modifier.Shrink
import app.cash.redwood.layout.modifier.Size
import app.cash.redwood.layout.modifier.VerticalAlignment
Expand Down Expand Up @@ -495,6 +497,30 @@ abstract class AbstractFlexContainerTest<T : Any> {
verifySnapshot(parent, "single")
}

@Test
fun testFlexDistributesWeightEqually() {
val container = flexContainer(FlexDirection.Row)
container.width(Constraint.Fill)
container.height(Constraint.Fill)
container.add(widget("REALLY LONG TEXT", FlexImpl(1.0)))
container.add(widget("SHORTER TEXT", FlexImpl(1.0)))
container.add(widget("A", FlexImpl(1.0)))
container.add(widget("LINE1\nLINE2\nLINE3", FlexImpl(1.0)))
verifySnapshot(container)
}

@Test
fun testFlexDistributesWeightUnequally() {
val container = flexContainer(FlexDirection.Row)
container.width(Constraint.Fill)
container.height(Constraint.Fill)
container.add(widget("REALLY LONG TEXT", FlexImpl(3.0)))
container.add(widget("SHORTER TEXT", FlexImpl(1.0)))
container.add(widget("A", FlexImpl(1.0)))
container.add(widget("LINE1\nLINE2\nLINE3", FlexImpl(1.0)))
verifySnapshot(container)
}

/** We don't have assume() on kotlin.test. Tests that fail here should be skipped instead. */
private fun assumeTrue(b: Boolean) {
assertTrue(b)
Expand Down Expand Up @@ -550,15 +576,19 @@ private data class SizeImpl(
) : Size

private data class MarginImpl(
override val margin: app.cash.redwood.ui.Margin,
) : app.cash.redwood.layout.modifier.Margin {
override val margin: Margin,
) : MarginModifier {
constructor(all: Dp = 0.dp) : this(Margin(all))
}

private data class GrowImpl(
override val `value`: Double,
override val value: Double,
) : Grow

private data class ShrinkImpl(
override val `value`: Double,
override val value: Double,
) : Shrink

private data class FlexImpl(
override val value: Double,
) : Flex
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CB408CE42AC64CEF00E1BA00"
BuildableName = "RedwoodLayoutUIViewTests.xctest"
BlueprintName = "RedwoodLayoutUIViewTests"
ReferencedContainer = "container:RedwoodLayoutUIViewTests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ public class Node internal constructor(
public var flexShrink: Float
get() = Yoga.YGNodeStyleGetFlexShrink(native)
set(value) = Yoga.YGNodeStyleSetFlexShrink(native, value)
public var flexBasis: Float
get() = Yoga.YGNodeStyleGetFlexBasisPercent(native)
set(value) = if (value >= 0) {
Yoga.YGNodeStyleSetFlexBasisPercent(native, value)
} else {
Yoga.YGNodeStyleSetFlexBasisAuto(native)
}
public var marginStart: Float
get() = getMargin(YGEdge.YGEdgeStart)
set(value) = setMargin(YGEdge.YGEdgeStart, value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,14 @@ internal object Yoga {
}
}

fun YGNodeStyleGetFlexBasisPercent(node: YGNode): Float {
return if (node.style.flexBasis.isPercent()) {
node.style.flexBasis.convertToYgValue().value
} else {
-1.0f // This is a stand-in for any non-percent value.
}
}

private fun <T : Enum<T>> updateStyleIndexed(
node: YGNode,
edge: T,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ internal class CompactValue {
return undefined || !isAuto() && !isPoint() && !isPercent() && payload_.value.isNaN()
}

private fun isPercent(): Boolean {
fun isPercent(): Boolean {
return payload_.unit == YGUnit.YGUnitPercent
}

private fun isPoint(): Boolean {
fun isPoint(): Boolean {
return payload_.unit == YGUnit.YGUnitPoint
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import app.cash.redwood.layout.api.CrossAxisAlignment
import app.cash.redwood.layout.api.MainAxisAlignment
import app.cash.redwood.layout.compose.Column
import app.cash.redwood.layout.compose.Row
import app.cash.redwood.layout.compose.flex
import app.cash.redwood.lazylayout.compose.ExperimentalRedwoodLazyLayoutApi
import app.cash.redwood.lazylayout.compose.LazyColumn
import app.cash.redwood.lazylayout.compose.items
Expand Down