From 2ac5379223bf39e6b948d4cca382af935b2232af Mon Sep 17 00:00:00 2001 From: Mori-Atsushi Date: Fri, 24 Nov 2023 23:29:48 +0900 Subject: [PATCH 1/4] Refactor ComponentPadding --- .../component/padding/ComponentPaddingTest.kt | 128 ++++++++++++++++++ .../component/padding/ComponentPadding.kt | 108 +++++++++------ 2 files changed, 192 insertions(+), 44 deletions(-) create mode 100644 compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt diff --git a/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt b/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt new file mode 100644 index 0000000..139ec63 --- /dev/null +++ b/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt @@ -0,0 +1,128 @@ +package com.moriatsushi.compose.stylesheet.component.padding + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi +import com.moriatsushi.compose.stylesheet.token.Token +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertEquals + +@OptIn(StyleSheetComponentApi::class) +@RunWith(AndroidJUnit4::class) +class ComponentPaddingTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun testAsPaddingValues() { + val componentPadding = ComponentPadding( + start = Token(10.dp), + top = Token(20.dp), + end = Token(30.dp), + bottom = Token(40.dp), + ) + composeTestRule.setContent { + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + assertEquals( + PaddingValues.Absolute( + left = 10.dp, + top = 20.dp, + right = 30.dp, + bottom = 40.dp, + ), + componentPadding.asPaddingValues(), + ) + } + + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { + assertEquals( + PaddingValues.Absolute( + left = 30.dp, + top = 20.dp, + right = 10.dp, + bottom = 40.dp, + ), + componentPadding.asPaddingValues(), + ) + } + } + } + + @Test + fun testAsPaddingValues_absolute() { + val componentPadding = ComponentPadding.absolute( + left = Token(10.dp), + top = Token(20.dp), + right = Token(30.dp), + bottom = Token(40.dp), + ) + composeTestRule.setContent { + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + assertEquals( + PaddingValues.Absolute( + left = 10.dp, + top = 20.dp, + right = 30.dp, + bottom = 40.dp, + ), + componentPadding.asPaddingValues(), + ) + } + + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { + assertEquals( + PaddingValues.Absolute( + left = 10.dp, + top = 20.dp, + right = 30.dp, + bottom = 40.dp, + ), + componentPadding.asPaddingValues(), + ) + } + } + } + + @Test + fun testAsPaddingValues_paddingValues() { + val paddingValues = PaddingValues( + start = 10.dp, + top = 20.dp, + end = 30.dp, + bottom = 40.dp, + ) + val componentPadding = ComponentPadding(paddingValues) + composeTestRule.setContent { + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + assertEquals( + PaddingValues.Absolute( + left = 10.dp, + top = 20.dp, + right = 30.dp, + bottom = 40.dp, + ), + componentPadding.asPaddingValues(), + ) + } + + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { + assertEquals( + PaddingValues.Absolute( + left = 30.dp, + top = 20.dp, + right = 10.dp, + bottom = 40.dp, + ), + componentPadding.asPaddingValues(), + ) + } + } + } +} diff --git a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt index 8a91f6a..f42152d 100644 --- a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt +++ b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt @@ -5,17 +5,18 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi import com.moriatsushi.compose.stylesheet.token.Token import com.moriatsushi.compose.stylesheet.token.value -import kotlin.jvm.JvmInline @Immutable sealed interface ComponentPadding { - @Composable @StyleSheetComponentApi + @Composable fun asPaddingValues(): PaddingValues companion object { @@ -24,66 +25,81 @@ sealed interface ComponentPadding { top: Token = Token(0.dp), right: Token = Token(0.dp), bottom: Token = Token(0.dp), - ): ComponentPadding = AbstractComponentPadding( - left = left, - top = top, - right = right, - bottom = bottom, + ): ComponentPadding = ComponentPadding( + PaddingSide.Left to left, + PaddingSide.Top to top, + PaddingSide.Right to right, + PaddingSide.Bottom to bottom, ) } } -internal fun ComponentPadding(values: PaddingValues): ComponentPadding = - PaddingValuesComponentPadding(values) +internal fun ComponentPadding(paddingValues: PaddingValues): ComponentPadding = + ComponentPaddingImpl(paddingValues = paddingValues) internal fun ComponentPadding( start: Token = Token(0.dp), top: Token = Token(0.dp), end: Token = Token(0.dp), bottom: Token = Token(0.dp), -): ComponentPadding = ComponentPaddingImpl( - start = start, - top = top, - end = end, - bottom = bottom, +): ComponentPadding = ComponentPadding( + PaddingSide.Start to start, + PaddingSide.Top to top, + PaddingSide.End to end, + PaddingSide.Bottom to bottom, ) -@JvmInline -private value class PaddingValuesComponentPadding( - private val paddingValues: PaddingValues, +private fun ComponentPadding(vararg values: Pair>): ComponentPadding = + ComponentPaddingImpl(values = values.toList()) + +private data class ComponentPaddingImpl( + private val values: List>> = emptyList(), + private val paddingValues: PaddingValues? = null, ) : ComponentPadding { @Composable - override fun asPaddingValues(): PaddingValues = paddingValues + override fun asPaddingValues(): PaddingValues { + val layoutDirection = LocalLayoutDirection.current + + val left = values.firstOrNull { it.first.isLeft(layoutDirection) }?.second?.value + ?: paddingValues?.calculateLeftPadding(layoutDirection) + ?: 0.dp + + val top = values.firstOrNull { it.first == PaddingSide.Top }?.second?.value + ?: paddingValues?.calculateTopPadding() + ?: 0.dp + + val right = values.firstOrNull { it.first.isRight(layoutDirection) }?.second?.value + ?: paddingValues?.calculateRightPadding(layoutDirection) + ?: 0.dp + + val bottom = values.firstOrNull { it.first == PaddingSide.Bottom }?.second?.value + ?: paddingValues?.calculateBottomPadding() + ?: 0.dp + + return PaddingValues.Absolute(left = left, top = top, right = right, bottom = bottom) + } } -private data class AbstractComponentPadding( - val left: Token, - val top: Token, - val right: Token, - val bottom: Token, -) : ComponentPadding { - @Composable - override fun asPaddingValues(): PaddingValues = PaddingValues.Absolute( - left = left.value, - top = top.value, - right = right.value, - bottom = bottom.value, - ) +private fun PaddingSide.isLeft(layoutDirection: LayoutDirection): Boolean { + if (this == PaddingSide.Left) { + return true + } + return if (layoutDirection == LayoutDirection.Ltr) { + this == PaddingSide.Start + } else { + this == PaddingSide.End + } } -private data class ComponentPaddingImpl( - val start: Token, - val top: Token, - val end: Token, - val bottom: Token, -) : ComponentPadding { - @Composable - override fun asPaddingValues(): PaddingValues = PaddingValues( - start = start.value, - top = top.value, - end = end.value, - bottom = bottom.value, - ) +private fun PaddingSide.isRight(layoutDirection: LayoutDirection): Boolean { + if (this == PaddingSide.Right) { + return true + } + return if (layoutDirection == LayoutDirection.Ltr) { + this == PaddingSide.End + } else { + this == PaddingSide.Start + } } @Composable @@ -91,3 +107,7 @@ private data class ComponentPaddingImpl( fun Modifier.componentPadding(padding: ComponentPadding?): Modifier = this.then( if (padding != null) Modifier.padding(padding.asPaddingValues()) else Modifier, ) + +private enum class PaddingSide { + Left, Top, Right, Bottom, Start, End, +} From 6f0bf9610813a8db33f680babfab49a0014b5aa5 Mon Sep 17 00:00:00 2001 From: Mori-Atsushi Date: Fri, 24 Nov 2023 23:50:31 +0900 Subject: [PATCH 2/4] Add padding parameters --- .../component/ComponentPaddingTest.kt | 22 +++++- .../component/padding/ComponentPaddingTest.kt | 44 ++++++++++- .../component/ComponentStyleBuilder.kt | 12 +-- .../component/padding/ComponentPadding.kt | 77 +++++++++++-------- .../component/padding/PaddingSetter.kt | 26 +++++++ .../theme/appbar/TopAppBarStyleSheet.kt | 2 +- .../theme/button/ButtonStyleSheet.kt | 2 +- 7 files changed, 144 insertions(+), 41 deletions(-) diff --git a/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentPaddingTest.kt b/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentPaddingTest.kt index 792f083..c3b2636 100644 --- a/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentPaddingTest.kt +++ b/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentPaddingTest.kt @@ -76,10 +76,28 @@ class ComponentPaddingTest { .assertHeightIsEqualTo(50.dp) } + @Test + fun testPadding_vertical() { + val style = DummyComponentStyle { + padding.vertical += 10.dp + } + + composeTestRule.setContent { + DummyComponent( + modifier = Modifier.testTag("dummyComponent"), + style = style, + ) + } + + composeTestRule.onNodeWithTag("dummyComponent") + .assertWidthIsEqualTo(10.dp) + .assertHeightIsEqualTo(30.dp) + } + @Test fun testPadding_horizontal() { val style = DummyComponentStyle { - padding += padding(horizontal = 10.dp) + padding.horizontal += 10.dp } composeTestRule.setContent { @@ -97,7 +115,7 @@ class ComponentPaddingTest { @Test fun testPadding_top() { val style = DummyComponentStyle { - padding += padding(top = 10.dp) + padding.top += 10.dp } composeTestRule.setContent { diff --git a/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt b/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt index 139ec63..cac649e 100644 --- a/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt +++ b/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt @@ -9,10 +9,10 @@ import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi import com.moriatsushi.compose.stylesheet.token.Token +import kotlin.test.assertEquals import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import kotlin.test.assertEquals @OptIn(StyleSheetComponentApi::class) @RunWith(AndroidJUnit4::class) @@ -57,7 +57,7 @@ class ComponentPaddingTest { @Test fun testAsPaddingValues_absolute() { - val componentPadding = ComponentPadding.absolute( + val componentPadding = ComponentPadding( left = Token(10.dp), top = Token(20.dp), right = Token(30.dp), @@ -125,4 +125,44 @@ class ComponentPaddingTest { } } } + + @Test + fun testAsPaddingValues_copied() { + val paddingValues = PaddingValues( + start = 10.dp, + top = 20.dp, + end = 30.dp, + bottom = 40.dp, + ) + val componentPadding = ComponentPadding(paddingValues) + .copy(left = Token(50.dp)) + .copy(bottom = Token(60.dp)) + .copy(start = Token(70.dp)) + + composeTestRule.setContent { + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + assertEquals( + PaddingValues.Absolute( + left = 70.dp, + top = 20.dp, + right = 30.dp, + bottom = 60.dp, + ), + componentPadding.asPaddingValues(), + ) + } + + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { + assertEquals( + PaddingValues.Absolute( + left = 50.dp, + top = 20.dp, + right = 70.dp, + bottom = 60.dp, + ), + componentPadding.asPaddingValues(), + ) + } + } + } } diff --git a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentStyleBuilder.kt b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentStyleBuilder.kt index c1dc9eb..e9aba1d 100644 --- a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentStyleBuilder.kt +++ b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentStyleBuilder.kt @@ -155,12 +155,14 @@ abstract class ComponentStyleBuilder : StyleBuilder { * Example: * ``` * padding += 10.dp - * padding += sizeToken // Token - * padding += padding(horizontal = 10.dp, vertical = 20.dp) - * padding += padding(horizontal = horizontalToken, vertical = verticalToken) + * padding += dpToken * padding += padding(start = 10.dp, top = 20.dp, end = 30.dp, bottom = 40.dp) * padding += absolutePadding(left = 10.dp, top = 20.dp, right = 30.dp, bottom = 40.dp) * padding += PaddingValues(10.dp) + * padding.top += 10.dp + * padding.top += dpToken + * padding.vertical += 10.dp + * padding.horizontal += 10.dp * ``` */ val padding: PaddingSetter = PaddingSetter() @@ -248,7 +250,7 @@ abstract class ComponentStyleBuilder : StyleBuilder { top: Token = Token(0.dp), right: Token = Token(0.dp), bottom: Token = Token(0.dp), - ): ComponentPadding = ComponentPadding.absolute( + ): ComponentPadding = ComponentPadding( left = left, top = top, right = right, @@ -260,7 +262,7 @@ abstract class ComponentStyleBuilder : StyleBuilder { top: Dp = 0.dp, right: Dp = 0.dp, bottom: Dp = 0.dp, - ): ComponentPadding = ComponentPadding.absolute( + ): ComponentPadding = ComponentPadding( left = Token(left), top = Token(top), right = Token(right), diff --git a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt index f42152d..4ee9269 100644 --- a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt +++ b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt @@ -14,48 +14,45 @@ import com.moriatsushi.compose.stylesheet.token.Token import com.moriatsushi.compose.stylesheet.token.value @Immutable -sealed interface ComponentPadding { - @StyleSheetComponentApi +sealed class ComponentPadding { @Composable - fun asPaddingValues(): PaddingValues - - companion object { - internal fun absolute( - left: Token = Token(0.dp), - top: Token = Token(0.dp), - right: Token = Token(0.dp), - bottom: Token = Token(0.dp), - ): ComponentPadding = ComponentPadding( - PaddingSide.Left to left, - PaddingSide.Top to top, - PaddingSide.Right to right, - PaddingSide.Bottom to bottom, - ) - } + internal abstract fun asPaddingValues(): PaddingValues + + internal abstract fun copy( + start: Token? = null, + top: Token? = null, + end: Token? = null, + bottom: Token? = null, + right: Token? = null, + left: Token? = null, + ): ComponentPadding } internal fun ComponentPadding(paddingValues: PaddingValues): ComponentPadding = ComponentPaddingImpl(paddingValues = paddingValues) internal fun ComponentPadding( - start: Token = Token(0.dp), - top: Token = Token(0.dp), - end: Token = Token(0.dp), - bottom: Token = Token(0.dp), -): ComponentPadding = ComponentPadding( - PaddingSide.Start to start, - PaddingSide.Top to top, - PaddingSide.End to end, - PaddingSide.Bottom to bottom, + start: Token? = null, + top: Token? = null, + end: Token? = null, + bottom: Token? = null, + right: Token? = null, + left: Token? = null, +): ComponentPadding = ComponentPaddingImpl( + listOfNotNull( + start?.let { PaddingSide.Start to it }, + top?.let { PaddingSide.Top to it }, + end?.let { PaddingSide.End to it }, + bottom?.let { PaddingSide.Bottom to it }, + right?.let { PaddingSide.Right to it }, + left?.let { PaddingSide.Left to it }, + ), ) -private fun ComponentPadding(vararg values: Pair>): ComponentPadding = - ComponentPaddingImpl(values = values.toList()) - private data class ComponentPaddingImpl( private val values: List>> = emptyList(), private val paddingValues: PaddingValues? = null, -) : ComponentPadding { +) : ComponentPadding() { @Composable override fun asPaddingValues(): PaddingValues { val layoutDirection = LocalLayoutDirection.current @@ -78,6 +75,26 @@ private data class ComponentPaddingImpl( return PaddingValues.Absolute(left = left, top = top, right = right, bottom = bottom) } + + override fun copy( + start: Token?, + top: Token?, + end: Token?, + bottom: Token?, + right: Token?, + left: Token?, + ): ComponentPadding { + val newList = listOfNotNull( + start?.let { PaddingSide.Start to it }, + top?.let { PaddingSide.Top to it }, + end?.let { PaddingSide.End to it }, + bottom?.let { PaddingSide.Bottom to it }, + right?.let { PaddingSide.Right to it }, + left?.let { PaddingSide.Left to it }, + ) + val newSides = newList.map { it.first }.toSet() + return copy(values = newList + values.filterNot { newSides.contains(it.first) }) + } } private fun PaddingSide.isLeft(layoutDirection: LayoutDirection): Boolean { diff --git a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt index af50a28..4355368 100644 --- a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt +++ b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt @@ -3,10 +3,36 @@ package com.moriatsushi.compose.stylesheet.component.padding import androidx.compose.foundation.layout.PaddingValues import androidx.compose.ui.unit.Dp import com.moriatsushi.compose.stylesheet.token.Token +import com.moriatsushi.compose.stylesheet.token.TokenSetterCallback class PaddingSetter internal constructor() { internal var value: ComponentPadding? = null + val start: TokenSetterCallback = TokenSetterCallback { + value = value?.copy(start = it) ?: ComponentPadding(start = it) + } + val top: TokenSetterCallback = TokenSetterCallback { + value = value?.copy(top = it) ?: ComponentPadding(top = it) + } + val end: TokenSetterCallback = TokenSetterCallback { + value = value?.copy(end = it) ?: ComponentPadding(end = it) + } + val bottom: TokenSetterCallback = TokenSetterCallback { + value = value?.copy(bottom = it) ?: ComponentPadding(bottom = it) + } + val right: TokenSetterCallback = TokenSetterCallback { + value = value?.copy(right = it) ?: ComponentPadding(right = it) + } + val left: TokenSetterCallback = TokenSetterCallback { + value = value?.copy(left = it) ?: ComponentPadding(left = it) + } + val vertical: TokenSetterCallback = TokenSetterCallback { + value = value?.copy(top = it, bottom = it) ?: ComponentPadding(top = it, bottom = it) + } + val horizontal: TokenSetterCallback = TokenSetterCallback { + value = value?.copy(start = it, end = it) ?: ComponentPadding(start = it, end = it) + } + operator fun plusAssign(padding: ComponentPadding?) { if (padding != null) { value = padding diff --git a/compose-stylesheet-theme/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/theme/appbar/TopAppBarStyleSheet.kt b/compose-stylesheet-theme/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/theme/appbar/TopAppBarStyleSheet.kt index a7626cd..a45bddc 100644 --- a/compose-stylesheet-theme/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/theme/appbar/TopAppBarStyleSheet.kt +++ b/compose-stylesheet-theme/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/theme/appbar/TopAppBarStyleSheet.kt @@ -10,7 +10,7 @@ val topAppBarStyleSheet = StyleSheet { topAppBar { width += fill minHeight += 64.dp - padding += padding(vertical = 2.dp) + padding.vertical += 2.dp background += Colors.semantic.background layout { diff --git a/compose-stylesheet-theme/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/theme/button/ButtonStyleSheet.kt b/compose-stylesheet-theme/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/theme/button/ButtonStyleSheet.kt index c883827..0a600a6 100644 --- a/compose-stylesheet-theme/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/theme/button/ButtonStyleSheet.kt +++ b/compose-stylesheet-theme/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/theme/button/ButtonStyleSheet.kt @@ -12,7 +12,7 @@ internal val buttonStyleSheet = StyleSheet { background += Colors.semantic.inverseSurface shape += RoundedCornerShape(50) minSize += 40.dp - padding += padding(vertical = 2.dp) + padding.vertical += 2.dp layout { spaceBetweenContentAndContainer += 24.dp From dce3a7cd3e438c02954b2885ca6889967c3484a0 Mon Sep 17 00:00:00 2001 From: Mori-Atsushi Date: Sat, 25 Nov 2023 00:13:38 +0900 Subject: [PATCH 3/4] Add a merge function for ComponentPadding --- .../component/padding/ComponentPaddingTest.kt | 52 ++++++++++++++++++- .../component/padding/ComponentPadding.kt | 19 +++++-- .../component/padding/PaddingSetter.kt | 2 +- 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt b/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt index cac649e..150ef33 100644 --- a/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt +++ b/compose-stylesheet-core/src/androidUnitTest/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPaddingTest.kt @@ -7,14 +7,12 @@ import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.moriatsushi.compose.stylesheet.component.StyleSheetComponentApi import com.moriatsushi.compose.stylesheet.token.Token import kotlin.test.assertEquals import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -@OptIn(StyleSheetComponentApi::class) @RunWith(AndroidJUnit4::class) class ComponentPaddingTest { @get:Rule @@ -165,4 +163,54 @@ class ComponentPaddingTest { } } } + + @Test + fun testAsPaddingValues_merged() { + val paddingValues = PaddingValues( + start = 10.dp, + top = 20.dp, + end = 30.dp, + bottom = 40.dp, + ) + val padding1 = ComponentPadding( + PaddingValues( + start = 10.dp, + top = 20.dp, + end = 30.dp, + bottom = 40.dp, + ), + ) + val padding2 = ComponentPadding( + start = Token(50.dp), + top = Token(60.dp), + ) + val merged1 = padding1.merge(padding2) + val merged2 = padding2.merge(padding1) + + composeTestRule.setContent { + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + assertEquals( + PaddingValues.Absolute( + left = 50.dp, + top = 60.dp, + right = 30.dp, + bottom = 40.dp, + ), + merged1.asPaddingValues(), + ) + } + + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + assertEquals( + PaddingValues.Absolute( + left = 10.dp, + top = 20.dp, + right = 30.dp, + bottom = 40.dp, + ), + merged2.asPaddingValues(), + ) + } + } + } } diff --git a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt index 4ee9269..67290df 100644 --- a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt +++ b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt @@ -15,6 +15,9 @@ import com.moriatsushi.compose.stylesheet.token.value @Immutable sealed class ComponentPadding { + internal abstract val values: List>> + internal abstract val paddingValues: PaddingValues? + @Composable internal abstract fun asPaddingValues(): PaddingValues @@ -26,6 +29,16 @@ sealed class ComponentPadding { right: Token? = null, left: Token? = null, ): ComponentPadding + + internal fun merge(other: ComponentPadding): ComponentPadding = + if (other.paddingValues != null) { + other + } else { + ComponentPaddingImpl( + values = other.values + values, + paddingValues = paddingValues, + ) + } } internal fun ComponentPadding(paddingValues: PaddingValues): ComponentPadding = @@ -50,8 +63,8 @@ internal fun ComponentPadding( ) private data class ComponentPaddingImpl( - private val values: List>> = emptyList(), - private val paddingValues: PaddingValues? = null, + override val values: List>> = emptyList(), + override val paddingValues: PaddingValues? = null, ) : ComponentPadding() { @Composable override fun asPaddingValues(): PaddingValues { @@ -125,6 +138,6 @@ fun Modifier.componentPadding(padding: ComponentPadding?): Modifier = this.then( if (padding != null) Modifier.padding(padding.asPaddingValues()) else Modifier, ) -private enum class PaddingSide { +internal enum class PaddingSide { Left, Top, Right, Bottom, Start, End, } diff --git a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt index 4355368..f7fdf3d 100644 --- a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt +++ b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt @@ -35,7 +35,7 @@ class PaddingSetter internal constructor() { operator fun plusAssign(padding: ComponentPadding?) { if (padding != null) { - value = padding + value = value?.merge(padding) ?: padding } } From 41c09355af6131a07d07d187a89ea1778db27b7a Mon Sep 17 00:00:00 2001 From: Mori-Atsushi Date: Sat, 25 Nov 2023 00:16:34 +0900 Subject: [PATCH 4/4] Add a default value for ComponentPadding --- .../component/ComponentCommonStyle.kt | 2 +- .../component/padding/ComponentPadding.kt | 26 ++++++++++++++----- .../component/padding/PaddingSetter.kt | 24 ++++++++--------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentCommonStyle.kt b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentCommonStyle.kt index abad28b..823b460 100644 --- a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentCommonStyle.kt +++ b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/ComponentCommonStyle.kt @@ -29,7 +29,7 @@ import com.moriatsushi.compose.stylesheet.token.value @StyleSheetComponentApi data class ComponentCommonStyle internal constructor( internal val size: ComponentSize = ComponentSize.Default, - val padding: ComponentPadding? = null, + val padding: ComponentPadding = ComponentPadding.Default, internal val background: Token? = null, internal val shape: Token? = null, internal val border: BorderStyle? = null, diff --git a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt index 67290df..2d509d4 100644 --- a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt +++ b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/ComponentPadding.kt @@ -34,15 +34,19 @@ sealed class ComponentPadding { if (other.paddingValues != null) { other } else { - ComponentPaddingImpl( + ComponentPadding( values = other.values + values, paddingValues = paddingValues, ) } + + companion object { + internal val Default: ComponentPadding = ComponentPadding(emptyList()) + } } internal fun ComponentPadding(paddingValues: PaddingValues): ComponentPadding = - ComponentPaddingImpl(paddingValues = paddingValues) + ComponentPadding(emptyList(), paddingValues = paddingValues) internal fun ComponentPadding( start: Token? = null, @@ -51,7 +55,7 @@ internal fun ComponentPadding( bottom: Token? = null, right: Token? = null, left: Token? = null, -): ComponentPadding = ComponentPaddingImpl( +): ComponentPadding = ComponentPadding( listOfNotNull( start?.let { PaddingSide.Start to it }, top?.let { PaddingSide.Top to it }, @@ -62,9 +66,17 @@ internal fun ComponentPadding( ), ) +private fun ComponentPadding( + values: List>> = emptyList(), + paddingValues: PaddingValues? = null, +): ComponentPadding = ComponentPaddingImpl( + values = values.distinctBy { it.first }, + paddingValues = paddingValues, +) + private data class ComponentPaddingImpl( - override val values: List>> = emptyList(), - override val paddingValues: PaddingValues? = null, + override val values: List>>, + override val paddingValues: PaddingValues?, ) : ComponentPadding() { @Composable override fun asPaddingValues(): PaddingValues { @@ -105,8 +117,8 @@ private data class ComponentPaddingImpl( right?.let { PaddingSide.Right to it }, left?.let { PaddingSide.Left to it }, ) - val newSides = newList.map { it.first }.toSet() - return copy(values = newList + values.filterNot { newSides.contains(it.first) }) + + return copy(values = (newList + values).distinctBy { it.first }) } } diff --git a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt index f7fdf3d..9b83ca7 100644 --- a/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt +++ b/compose-stylesheet-core/src/commonMain/kotlin/com/moriatsushi/compose/stylesheet/component/padding/PaddingSetter.kt @@ -6,37 +6,35 @@ import com.moriatsushi.compose.stylesheet.token.Token import com.moriatsushi.compose.stylesheet.token.TokenSetterCallback class PaddingSetter internal constructor() { - internal var value: ComponentPadding? = null + internal var value: ComponentPadding = ComponentPadding.Default val start: TokenSetterCallback = TokenSetterCallback { - value = value?.copy(start = it) ?: ComponentPadding(start = it) + value = value.copy(start = it) } val top: TokenSetterCallback = TokenSetterCallback { - value = value?.copy(top = it) ?: ComponentPadding(top = it) + value = value.copy(top = it) } val end: TokenSetterCallback = TokenSetterCallback { - value = value?.copy(end = it) ?: ComponentPadding(end = it) + value = value.copy(end = it) } val bottom: TokenSetterCallback = TokenSetterCallback { - value = value?.copy(bottom = it) ?: ComponentPadding(bottom = it) + value = value.copy(bottom = it) } val right: TokenSetterCallback = TokenSetterCallback { - value = value?.copy(right = it) ?: ComponentPadding(right = it) + value = value.copy(right = it) } val left: TokenSetterCallback = TokenSetterCallback { - value = value?.copy(left = it) ?: ComponentPadding(left = it) + value = value.copy(left = it) } val vertical: TokenSetterCallback = TokenSetterCallback { - value = value?.copy(top = it, bottom = it) ?: ComponentPadding(top = it, bottom = it) + value = value.copy(top = it, bottom = it) } val horizontal: TokenSetterCallback = TokenSetterCallback { - value = value?.copy(start = it, end = it) ?: ComponentPadding(start = it, end = it) + value = value.copy(start = it, end = it) } - operator fun plusAssign(padding: ComponentPadding?) { - if (padding != null) { - value = value?.merge(padding) ?: padding - } + operator fun plusAssign(padding: ComponentPadding) { + value = value.merge(padding) } operator fun plusAssign(all: Token) {