Skip to content

Commit

Permalink
Make CrossAxisAlignment modifier available for items within LazyList
Browse files Browse the repository at this point in the history
  • Loading branch information
veyndan committed Jun 28, 2023
1 parent b68e628 commit ef8332c
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 33 deletions.
1 change: 1 addition & 0 deletions redwood-lazylayout-compose/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ kotlin {
sourceSets {
commonMain {
dependencies {
api projects.redwoodLayoutModifiers
api projects.redwoodLazylayoutWidget
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,25 @@ import app.cash.redwood.ui.Margin
@LayoutScopeMarker
public interface LazyListScope {
public fun item(
content: @Composable () -> Unit,
content: @Composable LazyItemScope.() -> Unit,
)

public fun items(
count: Int,
itemContent: @Composable (index: Int) -> Unit,
itemContent: @Composable LazyItemScope.(index: Int) -> Unit,
)
}

public inline fun <T> LazyListScope.items(
items: List<T>,
crossinline itemContent: @Composable (item: T) -> Unit,
crossinline itemContent: @Composable LazyItemScope.(item: T) -> Unit,
): Unit = items(items.size) {
itemContent(items[it])
}

public inline fun <T> LazyListScope.itemsIndexed(
items: List<T>,
crossinline itemContent: @Composable (index: Int, item: T) -> Unit,
crossinline itemContent: @Composable LazyItemScope.(index: Int, item: T) -> Unit,
): Unit = items(
items.size,
) {
Expand All @@ -52,7 +52,7 @@ public inline fun <T> LazyListScope.itemsIndexed(

public inline fun <T> LazyListScope.items(
items: Array<T>,
crossinline itemContent: @Composable (item: T) -> Unit,
crossinline itemContent: @Composable LazyItemScope.(item: T) -> Unit,
): Unit = items(
items.size,
) {
Expand All @@ -61,7 +61,7 @@ public inline fun <T> LazyListScope.items(

public inline fun <T> LazyListScope.itemsIndexed(
items: Array<T>,
crossinline itemContent: @Composable (index: Int, item: T) -> Unit,
crossinline itemContent: @Composable LazyItemScope.(index: Int, item: T) -> Unit,
): Unit = items(
items.size,
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 Square, Inc.
*
* 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 app.cash.redwood.lazylayout.compose

import androidx.compose.runtime.Stable
import app.cash.redwood.LayoutScopeMarker
import app.cash.redwood.Modifier
import app.cash.redwood.layout.api.CrossAxisAlignment

@LayoutScopeMarker
public interface LazyItemScope {
@Stable
public fun Modifier.alignment(alignment: CrossAxisAlignment): Modifier =
then(AlignmentImpl(alignment))
}

internal object LazyItemScopeImpl : LazyItemScope
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal class LazyListIntervalContent(

override fun items(
count: Int,
itemContent: @Composable (index: Int) -> Unit,
itemContent: @Composable LazyItemScope.(index: Int) -> Unit,
) {
intervals.addInterval(
count,
Expand All @@ -43,7 +43,7 @@ internal class LazyListIntervalContent(
)
}

override fun item(content: @Composable () -> Unit) {
override fun item(content: @Composable LazyItemScope.() -> Unit) {
intervals.addInterval(
1,
LazyListInterval(
Expand All @@ -54,5 +54,5 @@ internal class LazyListIntervalContent(
}

internal class LazyListInterval(
val item: @Composable (index: Int) -> Unit,
val item: @Composable LazyItemScope.(index: Int) -> Unit,
) : LazyLayoutIntervalContent.Interval
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ import app.cash.redwood.lazylayout.compose.layout.LazyLayoutItemProvider
// Copied from https://github.com/androidx/androidx/blob/a733905d282ecdba574bc5e35d6b0ebf83c82dcd/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemProvider.kt
// Removed support for content types, header indices, item scope, and pinnable items.

internal interface LazyListItemProvider : LazyLayoutItemProvider
internal interface LazyListItemProvider : LazyLayoutItemProvider {
val itemScope: LazyItemScopeImpl
}

@Composable
internal fun rememberLazyListItemProvider(
Expand All @@ -37,12 +39,14 @@ internal fun rememberLazyListItemProvider(
return remember(latestContent) {
LazyListItemProviderImpl(
latestContent = { latestContent.value },
itemScope = LazyItemScopeImpl,
)
}
}

private class LazyListItemProviderImpl(
private val latestContent: () -> (LazyListScope.() -> Unit),
override val itemScope: LazyItemScopeImpl,
) : LazyListItemProvider {
private val listContent by derivedStateOf(referentialEqualityPolicy()) {
LazyListIntervalContent(latestContent())
Expand All @@ -53,7 +57,7 @@ private class LazyListItemProviderImpl(
@Composable
override fun Item(index: Int) {
listContent.withInterval(index) { localIndex, content ->
content.item(localIndex)
content.item(itemScope, localIndex)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package app.cash.redwood.lazylayout.compose

import app.cash.redwood.layout.api.CrossAxisAlignment
import app.cash.redwood.layout.modifier.Alignment

internal class AlignmentImpl(
override val alignment: CrossAxisAlignment,
) : Alignment {
override fun equals(other: Any?): Boolean = other is Alignment
&& other.alignment == alignment

override fun hashCode(): Int {
var hash = 17
hash = 31 * hash + alignment.hashCode()
return hash
}

override fun toString(): String = """Alignment(alignment=$alignment)"""
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ internal class ComposeUiLazyList :
val content: LazyListScope.() -> Unit = {
items(items.widgets) { item ->
// TODO If CrossAxisAlignment is Stretch, pass Modifier.fillParentMaxWidth() to child widget.
// TODO Apply Modifier.alignment on child widgets.
item.value.invoke()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import app.cash.redwood.Modifier
import app.cash.redwood.layout.api.Constraint
import app.cash.redwood.layout.api.CrossAxisAlignment
import app.cash.redwood.layout.modifier.Alignment
import app.cash.redwood.lazylayout.widget.LazyList
import app.cash.redwood.lazylayout.widget.RefreshableLazyList
import app.cash.redwood.ui.Density
Expand Down Expand Up @@ -253,20 +254,7 @@ internal open class ViewLazyList(context: Context) : LazyList<View> {

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
lastItemHeight = holder.itemView.height
val layoutParams = if (crossAxisAlignment == CrossAxisAlignment.Stretch) {
FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
} else {
FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
}
layoutParams.apply {
gravity = when (crossAxisAlignment) {
CrossAxisAlignment.Start -> Gravity.START
CrossAxisAlignment.Center -> Gravity.CENTER
CrossAxisAlignment.End -> Gravity.END
CrossAxisAlignment.Stretch -> Gravity.START
else -> throw AssertionError()
}
}
val layoutParams = layoutParams(crossAxisAlignment)
when (holder) {
is ViewHolder.Placeholder -> {
if (holder.container.childCount == 0) {
Expand All @@ -286,11 +274,12 @@ internal open class ViewLazyList(context: Context) : LazyList<View> {
}
is ViewHolder.Item -> {
val index = position - items.itemsBefore
val view = items.widgets[index].value
val widget = items.widgets[index]
holder.container.removeAllViews()
(view.parent as? FrameLayout)?.removeAllViews()
view.layoutParams = layoutParams
holder.container.addView(view)
(widget.value.parent as? FrameLayout)?.removeAllViews()
widget.value.layoutParams = layoutParams
holder.container.addView(widget.value)
widget.value.applyModifier(widget.modifier)
}
}
}
Expand Down Expand Up @@ -327,3 +316,30 @@ internal class ViewRefreshableLazyList(
swipeRefreshLayout.setOnRefreshListener(onRefresh)
}
}

private fun layoutParams(crossAxisAlignment: CrossAxisAlignment): FrameLayout.LayoutParams {
val layoutParams = if (crossAxisAlignment == CrossAxisAlignment.Stretch) {
FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
} else {
FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
}
return layoutParams.apply {
gravity = when (crossAxisAlignment) {
CrossAxisAlignment.Start -> Gravity.START
CrossAxisAlignment.Center -> Gravity.CENTER
CrossAxisAlignment.End -> Gravity.END
CrossAxisAlignment.Stretch -> Gravity.START
else -> throw AssertionError()
}
}
}

private fun View.applyModifier(parentModifier: Modifier) {
parentModifier.forEach { childModifier ->
when (childModifier) {
is Alignment -> {
this.layoutParams = layoutParams(childModifier.alignment)
}
}
}
}
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.

0 comments on commit ef8332c

Please sign in to comment.