Move CommunalLayoutLib to AOSP
For more about the library, see go/hm-24-layout.
Bug: 303317477
Fix: 303317477
Test: atest CommunalLayoutLibTests
Change-Id: I01e3813a6081a22208f64b2dbaec8dda66e58a93
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index e40fcb2..1a33b6e3 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -60,6 +60,7 @@
// except for SystemUI-core.
// Copied from compose/features/Android.bp.
static_libs: [
+ "CommunalLayoutLib",
"PlatformComposeCore",
"androidx.compose.runtime_runtime",
diff --git a/packages/SystemUI/communal/layout/Android.bp b/packages/SystemUI/communal/layout/Android.bp
new file mode 100644
index 0000000..88dad66
--- /dev/null
+++ b/packages/SystemUI/communal/layout/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+ name: "CommunalLayoutLib",
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.arch.core_core-runtime",
+ "androidx.compose.animation_animation-graphics",
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.material3_material3",
+ "jsr330",
+ "kotlinx-coroutines-android",
+ "kotlinx-coroutines-core",
+ ],
+ manifest: "AndroidManifest.xml",
+ kotlincflags: ["-Xjvm-default=all"],
+}
diff --git a/packages/SystemUI/communal/layout/AndroidManifest.xml b/packages/SystemUI/communal/layout/AndroidManifest.xml
new file mode 100644
index 0000000..141be07
--- /dev/null
+++ b/packages/SystemUI/communal/layout/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest package="com.android.systemui.communal.layout" />
diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/CommunalLayoutEngine.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/CommunalLayoutEngine.kt
new file mode 100644
index 0000000..df87d19d
--- /dev/null
+++ b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/CommunalLayoutEngine.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.layout
+
+import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard
+
+/** Computes the arrangement of cards. */
+class CommunalLayoutEngine {
+ companion object {
+ /**
+ * Determines the size that each card should be rendered in, and distributes the cards into
+ * columns.
+ *
+ * Returns a nested list where the outer list contains columns, and the inner list contains
+ * cards in each column.
+ *
+ * Currently treats the first supported size as the size to be rendered in, ignoring other
+ * supported sizes.
+ */
+ fun distributeCardsIntoColumns(
+ cards: List<CommunalGridLayoutCard>,
+ ): List<List<CommunalGridLayoutCardInfo>> {
+ val result = ArrayList<ArrayList<CommunalGridLayoutCardInfo>>()
+
+ var capacityOfLastColumn = 0
+ for (card in cards) {
+ val cardSize = card.supportedSizes.first()
+ if (capacityOfLastColumn >= cardSize.value) {
+ // Card fits in last column
+ capacityOfLastColumn -= cardSize.value
+ } else {
+ // Create a new column
+ result.add(arrayListOf())
+ capacityOfLastColumn = CommunalGridLayoutCard.Size.FULL.value - cardSize.value
+ }
+
+ result.last().add(CommunalGridLayoutCardInfo(card, cardSize))
+ }
+
+ return result
+ }
+ }
+
+ /**
+ * A data class that wraps around a [CommunalGridLayoutCard] and also contains the size that the
+ * card should be rendered in.
+ */
+ data class CommunalGridLayoutCardInfo(
+ val card: CommunalGridLayoutCard,
+ val size: CommunalGridLayoutCard.Size,
+ )
+}
diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/CommunalGridLayout.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/CommunalGridLayout.kt
new file mode 100644
index 0000000..4ed78b3
--- /dev/null
+++ b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/CommunalGridLayout.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.layout.ui.compose
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.android.systemui.communal.layout.CommunalLayoutEngine
+import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard
+import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutConfig
+
+/**
+ * An arrangement of cards with a horizontal scroll, where each card is displayed in the right size
+ * and follows a specific order based on its priority, ensuring a seamless layout without any gaps.
+ */
+@Composable
+fun CommunalGridLayout(
+ modifier: Modifier,
+ layoutConfig: CommunalGridLayoutConfig,
+ communalCards: List<CommunalGridLayoutCard>,
+) {
+ val columns = CommunalLayoutEngine.distributeCardsIntoColumns(communalCards)
+ LazyRow(
+ modifier = modifier.height(layoutConfig.gridHeight),
+ horizontalArrangement = Arrangement.spacedBy(layoutConfig.gridGutter),
+ ) {
+ for (column in columns) {
+ item {
+ Column(
+ modifier = Modifier.width(layoutConfig.cardWidth),
+ verticalArrangement = Arrangement.spacedBy(layoutConfig.gridGutter),
+ ) {
+ for (cardInfo in column) {
+ Row(
+ modifier = Modifier.height(layoutConfig.cardHeight(cardInfo.size)),
+ ) {
+ cardInfo.card.Content(Modifier.fillMaxSize())
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutCard.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutCard.kt
new file mode 100644
index 0000000..ac8aa67
--- /dev/null
+++ b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutCard.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.layout.ui.compose.config
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+
+/** A card that hosts content to be rendered in the communal grid layout. */
+abstract class CommunalGridLayoutCard {
+ /**
+ * Content to be hosted by the card.
+ *
+ * To host non-Compose views, see
+ * https://developer.android.com/jetpack/compose/migrate/interoperability-apis/views-in-compose.
+ */
+ @Composable abstract fun Content(modifier: Modifier)
+
+ /**
+ * Sizes supported by the card.
+ *
+ * If multiple sizes are available, they should be ranked in order of preference, from most to
+ * least preferred.
+ */
+ abstract val supportedSizes: List<Size>
+
+ /**
+ * Priority of the content hosted by the card.
+ *
+ * The value of priority is relative to other cards. Cards with a higher priority are generally
+ * ordered first.
+ */
+ open val priority: Int = 0
+
+ /**
+ * Size of the card.
+ *
+ * @param value A numeric value that represents the size. Must be less than or equal to
+ * [Size.FULL].
+ */
+ enum class Size(val value: Int) {
+ /** The card takes up full height of the grid layout. */
+ FULL(value = 6),
+
+ /** The card takes up half of the vertical space of the grid layout. */
+ HALF(value = 3),
+
+ /** The card takes up a third of the vertical space of the grid layout. */
+ THIRD(value = 2),
+ }
+}
diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfig.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfig.kt
new file mode 100644
index 0000000..143df83
--- /dev/null
+++ b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfig.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.layout.ui.compose.config
+
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.times
+
+/**
+ * Configurations of the communal grid layout.
+ *
+ * The communal grid layout follows Material Design's responsive layout grid (see
+ * https://m2.material.io/design/layout/responsive-layout-grid.html), in which the layout is divided
+ * up by columns and gutters, and each card occupies one or multiple columns.
+ */
+data class CommunalGridLayoutConfig(
+ /**
+ * Size in dp of each grid column.
+ *
+ * Every card occupies one or more grid columns, which means that the width of each card is
+ * influenced by the size of the grid columns.
+ */
+ val gridColumnSize: Dp,
+
+ /**
+ * Size in dp of each grid gutter.
+ *
+ * A gutter is the space between columns that helps separate content. This is, therefore, also
+ * the size of the gaps between cards, both horizontally and vertically.
+ */
+ val gridGutter: Dp,
+
+ /**
+ * Height in dp of the grid layout.
+ *
+ * Cards with a full size take up the entire height of the grid layout.
+ */
+ val gridHeight: Dp,
+
+ /**
+ * Number of grid columns that each card occupies.
+ *
+ * It's important to note that all the cards take up the same number of grid columns, or in
+ * simpler terms, they all have the same width.
+ */
+ val gridColumnsPerCard: Int,
+) {
+ /**
+ * Width in dp of each card.
+ *
+ * It's important to note that all the cards take up the same number of grid columns, or in
+ * simpler terms, they all have the same width.
+ */
+ val cardWidth = gridColumnSize * gridColumnsPerCard + gridGutter * (gridColumnsPerCard - 1)
+
+ /** Returns the height of a card in dp, based on its size. */
+ fun cardHeight(cardSize: CommunalGridLayoutCard.Size): Dp {
+ return when (cardSize) {
+ CommunalGridLayoutCard.Size.FULL -> cardHeightBy(denominator = 1)
+ CommunalGridLayoutCard.Size.HALF -> cardHeightBy(denominator = 2)
+ CommunalGridLayoutCard.Size.THIRD -> cardHeightBy(denominator = 3)
+ }
+ }
+
+ /** Returns the height of a card in dp when the layout is evenly divided by [denominator]. */
+ private fun cardHeightBy(denominator: Int): Dp {
+ return (gridHeight - (denominator - 1) * gridGutter) / denominator
+ }
+}
diff --git a/packages/SystemUI/communal/layout/tests/Android.bp b/packages/SystemUI/communal/layout/tests/Android.bp
new file mode 100644
index 0000000..a60b1de
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/Android.bp
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_test {
+ name: "CommunalLayoutLibTests",
+ srcs: [
+ "**/*.kt",
+ ],
+ static_libs: [
+ "CommunalLayoutLib",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "frameworks-base-testutils",
+ "junit",
+ "kotlinx_coroutines_test",
+ "mockito-target-extended-minus-junit4",
+ "platform-test-annotations",
+ "testables",
+ "truth-prebuilt",
+ ],
+ libs: [
+ "android.test.mock",
+ "android.test.base",
+ "android.test.runner",
+ ],
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+ manifest: "AndroidManifest.xml",
+}
diff --git a/packages/SystemUI/communal/layout/tests/AndroidManifest.xml b/packages/SystemUI/communal/layout/tests/AndroidManifest.xml
new file mode 100644
index 0000000..b19007c
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.communal.layout.tests">
+
+ <application android:debuggable="true" android:largeHeap="true">
+ <uses-library android:name="android.test.mock" />
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.testing.TestableInstrumentation"
+ android:targetPackage="com.android.systemui.communal.layout.tests"
+ android:label="Tests for CommunalLayoutLib">
+ </instrumentation>
+
+</manifest>
diff --git a/packages/SystemUI/communal/layout/tests/AndroidTest.xml b/packages/SystemUI/communal/layout/tests/AndroidTest.xml
new file mode 100644
index 0000000..1352b23
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration description="Runs tests for CommunalLayoutLib">
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="CommunalLayoutLibTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="framework-base-presubmit" />
+ <option name="test-tag" value="CommunalLayoutLibTests" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.systemui.communal.layout.tests" />
+ <option name="runner" value="android.testing.TestableInstrumentation" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+
+</configuration>
diff --git a/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/CommunalLayoutEngineTest.kt b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/CommunalLayoutEngineTest.kt
new file mode 100644
index 0000000..fdf65f5
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/CommunalLayoutEngineTest.kt
@@ -0,0 +1,99 @@
+package com.android.systemui.communal.layout
+
+import androidx.compose.material3.Card
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalLayoutEngineTest {
+ @Test
+ fun distribution_fullLayout() {
+ val cards =
+ listOf(
+ generateCard(CommunalGridLayoutCard.Size.FULL),
+ generateCard(CommunalGridLayoutCard.Size.HALF),
+ generateCard(CommunalGridLayoutCard.Size.HALF),
+ generateCard(CommunalGridLayoutCard.Size.THIRD),
+ generateCard(CommunalGridLayoutCard.Size.THIRD),
+ generateCard(CommunalGridLayoutCard.Size.THIRD),
+ )
+ val expected =
+ listOf(
+ listOf(
+ CommunalGridLayoutCard.Size.FULL,
+ ),
+ listOf(
+ CommunalGridLayoutCard.Size.HALF,
+ CommunalGridLayoutCard.Size.HALF,
+ ),
+ listOf(
+ CommunalGridLayoutCard.Size.THIRD,
+ CommunalGridLayoutCard.Size.THIRD,
+ CommunalGridLayoutCard.Size.THIRD,
+ ),
+ )
+
+ assertDistribution(cards, expected)
+ }
+
+ @Test
+ fun distribution_layoutWithGaps() {
+ val cards =
+ listOf(
+ generateCard(CommunalGridLayoutCard.Size.HALF),
+ generateCard(CommunalGridLayoutCard.Size.THIRD),
+ generateCard(CommunalGridLayoutCard.Size.HALF),
+ generateCard(CommunalGridLayoutCard.Size.FULL),
+ generateCard(CommunalGridLayoutCard.Size.THIRD),
+ )
+ val expected =
+ listOf(
+ listOf(
+ CommunalGridLayoutCard.Size.HALF,
+ CommunalGridLayoutCard.Size.THIRD,
+ ),
+ listOf(
+ CommunalGridLayoutCard.Size.HALF,
+ ),
+ listOf(
+ CommunalGridLayoutCard.Size.FULL,
+ ),
+ listOf(
+ CommunalGridLayoutCard.Size.THIRD,
+ ),
+ )
+
+ assertDistribution(cards, expected)
+ }
+
+ private fun assertDistribution(
+ cards: List<CommunalGridLayoutCard>,
+ expected: List<List<CommunalGridLayoutCard.Size>>,
+ ) {
+ val result = CommunalLayoutEngine.distributeCardsIntoColumns(cards)
+
+ for (c in expected.indices) {
+ for (r in expected[c].indices) {
+ assertThat(result[c][r].size).isEqualTo(expected[c][r])
+ }
+ }
+ }
+
+ private fun generateCard(size: CommunalGridLayoutCard.Size): CommunalGridLayoutCard {
+ return object : CommunalGridLayoutCard() {
+ override val supportedSizes = listOf(size)
+
+ @Composable
+ override fun Content(modifier: Modifier) {
+ Card(modifier = modifier, content = {})
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfigTest.kt b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfigTest.kt
new file mode 100644
index 0000000..946eeec
--- /dev/null
+++ b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfigTest.kt
@@ -0,0 +1,63 @@
+package com.android.systemui.communal.layout.ui.compose.config
+
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CommunalGridLayoutConfigTest {
+ @Test
+ fun cardWidth() {
+ Truth.assertThat(
+ CommunalGridLayoutConfig(
+ gridColumnSize = 5.dp,
+ gridGutter = 3.dp,
+ gridHeight = 17.dp,
+ gridColumnsPerCard = 1,
+ )
+ .cardWidth
+ )
+ .isEqualTo(5.dp)
+
+ Truth.assertThat(
+ CommunalGridLayoutConfig(
+ gridColumnSize = 5.dp,
+ gridGutter = 3.dp,
+ gridHeight = 17.dp,
+ gridColumnsPerCard = 2,
+ )
+ .cardWidth
+ )
+ .isEqualTo(13.dp)
+
+ Truth.assertThat(
+ CommunalGridLayoutConfig(
+ gridColumnSize = 5.dp,
+ gridGutter = 3.dp,
+ gridHeight = 17.dp,
+ gridColumnsPerCard = 3,
+ )
+ .cardWidth
+ )
+ .isEqualTo(21.dp)
+ }
+
+ @Test
+ fun cardHeight() {
+ val config =
+ CommunalGridLayoutConfig(
+ gridColumnSize = 5.dp,
+ gridGutter = 2.dp,
+ gridHeight = 10.dp,
+ gridColumnsPerCard = 3,
+ )
+
+ Truth.assertThat(config.cardHeight(CommunalGridLayoutCard.Size.FULL)).isEqualTo(10.dp)
+ Truth.assertThat(config.cardHeight(CommunalGridLayoutCard.Size.HALF)).isEqualTo(4.dp)
+ Truth.assertThat(config.cardHeight(CommunalGridLayoutCard.Size.THIRD)).isEqualTo(2.dp)
+ }
+}