Skip to content

Commit 9bdec48

Browse files
committed
Make CrossAxisAlignment modifier available for items within LazyList
1 parent 3a6d5d7 commit 9bdec48

File tree

11 files changed

+120
-34
lines changed

11 files changed

+120
-34
lines changed

redwood-lazylayout-compose/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ kotlin {
1313
sourceSets {
1414
commonMain {
1515
dependencies {
16+
api projects.redwoodLayoutModifiers
1617
api projects.redwoodLazylayoutWidget
1718
}
1819
}

redwood-lazylayout-compose/src/commonMain/kotlin/app/cash/redwood/lazylayout/compose/LazyDsl.kt

+6-6
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,25 @@ import app.cash.redwood.ui.Margin
2525
@LayoutScopeMarker
2626
public interface LazyListScope {
2727
public fun item(
28-
content: @Composable () -> Unit,
28+
content: @Composable LazyItemScope.() -> Unit,
2929
)
3030

3131
public fun items(
3232
count: Int,
33-
itemContent: @Composable (index: Int) -> Unit,
33+
itemContent: @Composable LazyItemScope.(index: Int) -> Unit,
3434
)
3535
}
3636

3737
public inline fun <T> LazyListScope.items(
3838
items: List<T>,
39-
crossinline itemContent: @Composable (item: T) -> Unit,
39+
crossinline itemContent: @Composable LazyItemScope.(item: T) -> Unit,
4040
): Unit = items(items.size) {
4141
itemContent(items[it])
4242
}
4343

4444
public inline fun <T> LazyListScope.itemsIndexed(
4545
items: List<T>,
46-
crossinline itemContent: @Composable (index: Int, item: T) -> Unit,
46+
crossinline itemContent: @Composable LazyItemScope.(index: Int, item: T) -> Unit,
4747
): Unit = items(
4848
items.size,
4949
) {
@@ -52,7 +52,7 @@ public inline fun <T> LazyListScope.itemsIndexed(
5252

5353
public inline fun <T> LazyListScope.items(
5454
items: Array<T>,
55-
crossinline itemContent: @Composable (item: T) -> Unit,
55+
crossinline itemContent: @Composable LazyItemScope.(item: T) -> Unit,
5656
): Unit = items(
5757
items.size,
5858
) {
@@ -61,7 +61,7 @@ public inline fun <T> LazyListScope.items(
6161

6262
public inline fun <T> LazyListScope.itemsIndexed(
6363
items: Array<T>,
64-
crossinline itemContent: @Composable (index: Int, item: T) -> Unit,
64+
crossinline itemContent: @Composable LazyItemScope.(index: Int, item: T) -> Unit,
6565
): Unit = items(
6666
items.size,
6767
) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (C) 2023 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package app.cash.redwood.lazylayout.compose
17+
18+
import androidx.compose.runtime.Stable
19+
import app.cash.redwood.LayoutScopeMarker
20+
import app.cash.redwood.Modifier
21+
import app.cash.redwood.layout.api.CrossAxisAlignment
22+
23+
@LayoutScopeMarker
24+
public interface LazyItemScope {
25+
@Stable
26+
public fun Modifier.alignment(alignment: CrossAxisAlignment): Modifier =
27+
then(AlignmentImpl(alignment))
28+
}
29+
30+
internal object LazyItemScopeImpl : LazyItemScope

redwood-lazylayout-compose/src/commonMain/kotlin/app/cash/redwood/lazylayout/compose/LazyListIntervalContent.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ internal class LazyListIntervalContent(
3333

3434
override fun items(
3535
count: Int,
36-
itemContent: @Composable (index: Int) -> Unit,
36+
itemContent: @Composable LazyItemScope.(index: Int) -> Unit,
3737
) {
3838
intervals.addInterval(
3939
count,
@@ -43,7 +43,7 @@ internal class LazyListIntervalContent(
4343
)
4444
}
4545

46-
override fun item(content: @Composable () -> Unit) {
46+
override fun item(content: @Composable LazyItemScope.() -> Unit) {
4747
intervals.addInterval(
4848
1,
4949
LazyListInterval(
@@ -54,5 +54,5 @@ internal class LazyListIntervalContent(
5454
}
5555

5656
internal class LazyListInterval(
57-
val item: @Composable (index: Int) -> Unit,
57+
val item: @Composable LazyItemScope.(index: Int) -> Unit,
5858
) : LazyLayoutIntervalContent.Interval

redwood-lazylayout-compose/src/commonMain/kotlin/app/cash/redwood/lazylayout/compose/LazyListItemProvider.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import app.cash.redwood.lazylayout.compose.layout.LazyLayoutItemProvider
2727
// Copied from https://github.com/androidx/androidx/blob/a733905d282ecdba574bc5e35d6b0ebf83c82dcd/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemProvider.kt
2828
// Removed support for content types, header indices, item scope, and pinnable items.
2929

30-
internal interface LazyListItemProvider : LazyLayoutItemProvider
30+
internal interface LazyListItemProvider : LazyLayoutItemProvider {
31+
val itemScope: LazyItemScopeImpl
32+
}
3133

3234
@Composable
3335
internal fun rememberLazyListItemProvider(
@@ -37,12 +39,14 @@ internal fun rememberLazyListItemProvider(
3739
return remember(latestContent) {
3840
LazyListItemProviderImpl(
3941
latestContent = { latestContent.value },
42+
itemScope = LazyItemScopeImpl,
4043
)
4144
}
4245
}
4346

4447
private class LazyListItemProviderImpl(
4548
private val latestContent: () -> (LazyListScope.() -> Unit),
49+
override val itemScope: LazyItemScopeImpl,
4650
) : LazyListItemProvider {
4751
private val listContent by derivedStateOf(referentialEqualityPolicy()) {
4852
LazyListIntervalContent(latestContent())
@@ -53,7 +57,7 @@ private class LazyListItemProviderImpl(
5357
@Composable
5458
override fun Item(index: Int) {
5559
listContent.withInterval(index) { localIndex, content ->
56-
content.item(localIndex)
60+
content.item(itemScope, localIndex)
5761
}
5862
}
5963
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (C) 2023 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package app.cash.redwood.lazylayout.compose
17+
18+
import app.cash.redwood.layout.api.CrossAxisAlignment
19+
import app.cash.redwood.layout.modifier.Alignment
20+
21+
internal class AlignmentImpl(
22+
override val alignment: CrossAxisAlignment,
23+
) : Alignment {
24+
override fun equals(other: Any?): Boolean = other is Alignment &&
25+
other.alignment == alignment
26+
27+
override fun hashCode(): Int {
28+
var hash = 17
29+
hash = 31 * hash + alignment.hashCode()
30+
return hash
31+
}
32+
33+
override fun toString(): String = """Alignment(alignment=$alignment)"""
34+
}

redwood-lazylayout-composeui/src/commonMain/kotlin/app/cash/redwood/lazylayout/composeui/ComposeUiLazyList.kt

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ internal class ComposeUiLazyList :
114114
val content: LazyListScope.() -> Unit = {
115115
items(items.widgets) { item ->
116116
// TODO If CrossAxisAlignment is Stretch, pass Modifier.fillParentMaxWidth() to child widget.
117+
// TODO Apply Modifier.alignment on child widgets.
117118
item.value.invoke()
118119
}
119120
}

redwood-lazylayout-view/src/main/kotlin/app/cash/redwood/lazylayout/view/ViewLazyList.kt

+34-18
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
3434
import app.cash.redwood.Modifier
3535
import app.cash.redwood.layout.api.Constraint
3636
import app.cash.redwood.layout.api.CrossAxisAlignment
37+
import app.cash.redwood.layout.modifier.Alignment
3738
import app.cash.redwood.lazylayout.widget.LazyList
3839
import app.cash.redwood.lazylayout.widget.RefreshableLazyList
3940
import app.cash.redwood.ui.Density
@@ -253,20 +254,7 @@ internal open class ViewLazyList(context: Context) : LazyList<View> {
253254

254255
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
255256
lastItemHeight = holder.itemView.height
256-
val layoutParams = if (crossAxisAlignment == CrossAxisAlignment.Stretch) {
257-
FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
258-
} else {
259-
FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
260-
}
261-
layoutParams.apply {
262-
gravity = when (crossAxisAlignment) {
263-
CrossAxisAlignment.Start -> Gravity.START
264-
CrossAxisAlignment.Center -> Gravity.CENTER
265-
CrossAxisAlignment.End -> Gravity.END
266-
CrossAxisAlignment.Stretch -> Gravity.START
267-
else -> throw AssertionError()
268-
}
269-
}
257+
val layoutParams = layoutParams(crossAxisAlignment)
270258
when (holder) {
271259
is ViewHolder.Placeholder -> {
272260
if (holder.container.childCount == 0) {
@@ -286,11 +274,12 @@ internal open class ViewLazyList(context: Context) : LazyList<View> {
286274
}
287275
is ViewHolder.Item -> {
288276
val index = position - items.itemsBefore
289-
val view = items.widgets[index].value
277+
val widget = items.widgets[index]
290278
holder.container.removeAllViews()
291-
(view.parent as? FrameLayout)?.removeAllViews()
292-
view.layoutParams = layoutParams
293-
holder.container.addView(view)
279+
(widget.value.parent as? FrameLayout)?.removeAllViews()
280+
widget.value.layoutParams = layoutParams
281+
holder.container.addView(widget.value)
282+
widget.value.applyModifier(widget.modifier)
294283
}
295284
}
296285
}
@@ -327,3 +316,30 @@ internal class ViewRefreshableLazyList(
327316
swipeRefreshLayout.setOnRefreshListener(onRefresh)
328317
}
329318
}
319+
320+
private fun layoutParams(crossAxisAlignment: CrossAxisAlignment): FrameLayout.LayoutParams {
321+
val layoutParams = if (crossAxisAlignment == CrossAxisAlignment.Stretch) {
322+
FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
323+
} else {
324+
FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
325+
}
326+
return layoutParams.apply {
327+
gravity = when (crossAxisAlignment) {
328+
CrossAxisAlignment.Start -> Gravity.START
329+
CrossAxisAlignment.Center -> Gravity.CENTER
330+
CrossAxisAlignment.End -> Gravity.END
331+
CrossAxisAlignment.Stretch -> Gravity.START
332+
else -> throw AssertionError()
333+
}
334+
}
335+
}
336+
337+
private fun View.applyModifier(parentModifier: Modifier) {
338+
parentModifier.forEach { childModifier ->
339+
when (childModifier) {
340+
is Alignment -> {
341+
this.layoutParams = layoutParams(childModifier.alignment)
342+
}
343+
}
344+
}
345+
}

samples/emoji-search/presenter/src/jsMain/kotlin/com/example/redwood/emojisearch/presenter/EmojiSearchTreehouseUi.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ private class LazyColumnProvider : ColumnProvider {
5959
modifier = modifier,
6060
placeholder = placeholder,
6161
) {
62-
items(items, itemContent)
62+
items(items) { itemContent(it) }
6363
}
6464
}
6565
}

0 commit comments

Comments
 (0)