1 /*
<lambda>null2 * Copyright 2021 The Android Open Source Project
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
17 package androidx.compose.foundation.lazy.grid
18
19 import androidx.collection.IntList
20 import androidx.compose.foundation.ExperimentalFoundationApi
21 import androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider
22 import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
23 import androidx.compose.foundation.lazy.layout.LazyLayoutPinnableItem
24 import androidx.compose.foundation.lazy.layout.NearestRangeKeyIndexMap
25 import androidx.compose.runtime.Composable
26 import androidx.compose.runtime.derivedStateOf
27 import androidx.compose.runtime.referentialEqualityPolicy
28 import androidx.compose.runtime.remember
29 import androidx.compose.runtime.rememberUpdatedState
30
31 @Suppress("PrimitiveInCollection")
32 @OptIn(ExperimentalFoundationApi::class)
33 internal interface LazyGridItemProvider : LazyLayoutItemProvider {
34 val keyIndexMap: LazyLayoutKeyIndexMap
35 val spanLayoutProvider: LazyGridSpanLayoutProvider
36 val headerIndexes: IntList
37 }
38
39 @Composable
rememberLazyGridItemProviderLambdanull40 internal fun rememberLazyGridItemProviderLambda(
41 state: LazyGridState,
42 content: LazyGridScope.() -> Unit,
43 ): () -> LazyGridItemProvider {
44 val latestContent = rememberUpdatedState(content)
45 return remember(state) {
46 val intervalContentState =
47 derivedStateOf(referentialEqualityPolicy()) {
48 LazyGridIntervalContent(latestContent.value)
49 }
50 val itemProviderState =
51 derivedStateOf(referentialEqualityPolicy()) {
52 val intervalContent = intervalContentState.value
53 val map = NearestRangeKeyIndexMap(state.nearestRange, intervalContent)
54 LazyGridItemProviderImpl(
55 state = state,
56 intervalContent = intervalContent,
57 keyIndexMap = map
58 )
59 }
60 itemProviderState::value
61 }
62 }
63
64 private class LazyGridItemProviderImpl(
65 private val state: LazyGridState,
66 private val intervalContent: LazyGridIntervalContent,
67 override val keyIndexMap: LazyLayoutKeyIndexMap,
68 ) : LazyGridItemProvider {
69
70 override val itemCount: Int
71 get() = intervalContent.itemCount
72
getKeynull73 override fun getKey(index: Int): Any =
74 keyIndexMap.getKey(index) ?: intervalContent.getKey(index)
75
76 override fun getContentType(index: Int): Any? = intervalContent.getContentType(index)
77
78 override val headerIndexes: IntList
79 get() = intervalContent.headerIndexes
80
81 @Composable
82 override fun Item(index: Int, key: Any) {
83 LazyLayoutPinnableItem(key, index, state.pinnedItems) {
84 intervalContent.withInterval(index) { localIndex, content ->
85 content.item(LazyGridItemScopeImpl, localIndex)
86 }
87 }
88 }
89
90 override val spanLayoutProvider: LazyGridSpanLayoutProvider
91 get() = intervalContent.spanLayoutProvider
92
getIndexnull93 override fun getIndex(key: Any): Int = keyIndexMap.getIndex(key)
94
95 override fun equals(other: Any?): Boolean {
96 if (this === other) return true
97 if (other !is LazyGridItemProviderImpl) return false
98
99 // the identity of this class is represented by intervalContent object.
100 // having equals() allows us to skip items recomposition when intervalContent didn't change
101 return intervalContent == other.intervalContent
102 }
103
hashCodenull104 override fun hashCode(): Int {
105 return intervalContent.hashCode()
106 }
107 }
108