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