-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LazyListScrollProcessor manages user and programmatic scrolls (#1619)
* wip * LazyListScrollProcessor manages user and programmatic scrolls --------- Co-authored-by: Jesse Wilson <[email protected]>
- Loading branch information
1 parent
01f7fbf
commit 8afc0ba
Showing
7 changed files
with
171 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
...src/commonTest/kotlin/app/cash/redwood/lazylayout/api/ScrollItemIndexSerializationTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* 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.api | ||
|
||
import assertk.assertThat | ||
import assertk.assertions.isEqualTo | ||
import kotlin.test.Test | ||
import kotlinx.serialization.json.Json | ||
|
||
class ScrollItemIndexSerializationTest { | ||
private val json = Json { | ||
ignoreUnknownKeys = true | ||
useArrayPolymorphism = true | ||
} | ||
|
||
@Test | ||
fun encodeAndDecode() { | ||
assertRoundTrip( | ||
ScrollItemIndex(3, 7), | ||
"""{"id":3,"index":7}""", | ||
) | ||
} | ||
|
||
private fun assertRoundTrip(value: ScrollItemIndex, encoded: String) { | ||
assertThat(json.encodeToString(ScrollItemIndex.serializer(), value)).isEqualTo(encoded) | ||
assertThat(json.decodeFromString(ScrollItemIndex.serializer(), encoded)).isEqualTo(value) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
...idget/src/commonMain/kotlin/app/cash/redwood/lazylayout/widget/LazyListScrollProcessor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* 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.widget | ||
|
||
import app.cash.redwood.lazylayout.api.ScrollItemIndex | ||
|
||
public abstract class LazyListScrollProcessor { | ||
/** To notify guest code of user scrolls. */ | ||
private var onViewportChanged: ((Int, Int) -> Unit)? = null | ||
|
||
/** We can't scroll to this index until we have enough data for it to display! */ | ||
private var deferredProgrammaticScrollIndex: Int = -1 | ||
|
||
/** Once we receive a user scroll, we stop forwarding programmatic scrolls. */ | ||
private var userHasScrolled = false | ||
|
||
public fun onViewportChanged(onViewportChanged: (Int, Int) -> Unit) { | ||
this.onViewportChanged = onViewportChanged | ||
} | ||
|
||
public fun scrollItemIndex(scrollItemIndex: ScrollItemIndex) { | ||
// Defer until we have data in onEndChanges(). | ||
deferredProgrammaticScrollIndex = scrollItemIndex.index | ||
} | ||
|
||
public fun onEndChanges() { | ||
// Do nothing: we don't have deferred scrolls. | ||
if (deferredProgrammaticScrollIndex == -1) return | ||
|
||
// Do nothing: we don't do programmatic scrolls if the user has already scrolled manually. | ||
if (userHasScrolled) return | ||
|
||
// Do nothing: we can't scroll to this item because it hasn't loaded yet! | ||
if (contentSize() <= deferredProgrammaticScrollIndex) return | ||
|
||
// Do a programmatic scroll! | ||
programmaticScroll(deferredProgrammaticScrollIndex) | ||
deferredProgrammaticScrollIndex = -1 | ||
} | ||
|
||
/** | ||
* React to a user-initiated scroll. Callers should not call this function for programmatic | ||
* scrolls. | ||
*/ | ||
public fun onUserScroll(firstIndex: Int, lastIndex: Int) { | ||
if (firstIndex > 0) userHasScrolled = true | ||
onViewportChanged?.invoke(firstIndex, lastIndex) | ||
} | ||
|
||
/** Returns the number of items we're scrolling over. */ | ||
public abstract fun contentSize(): Int | ||
|
||
/** Perform a programmatic scroll. */ | ||
public abstract fun programmaticScroll(firstIndex: Int) | ||
} |
Oops, something went wrong.