Skip to content

Commit

Permalink
Add month changes throttling (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
boguszpawlowski authored Mar 18, 2023
1 parent 2962892 commit d7cd040
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 11 deletions.
2 changes: 1 addition & 1 deletion library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ plugins {
android {
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = freeCompilerArgs + "-Xexplicit-api=strict"
freeCompilerArgs = freeCompilerArgs + "-Xexplicit-api=strict" + "-Xcontext-receivers"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.snapshotFlow
import io.github.boguszpawlowski.composecalendar.header.MonthState
import io.github.boguszpawlowski.composecalendar.util.throttleOnOffset
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
Expand All @@ -21,7 +22,7 @@ internal class MonthListState(
private val listState: LazyListState,
) {

private val currentlyVisibleMonth by derivedStateOf {
private val currentFirstVisibleMonth by derivedStateOf {
getMonthForPage(listState.firstVisibleItemIndex)
}

Expand All @@ -30,16 +31,20 @@ internal class MonthListState(
moveToMonth(month)
}.launchIn(coroutineScope)

snapshotFlow { currentlyVisibleMonth }.onEach { newMonth ->
monthState.currentMonth = newMonth
}.launchIn(coroutineScope)
with(listState) {
snapshotFlow { currentFirstVisibleMonth }
.throttleOnOffset()
.onEach { newMonth ->
monthState.currentMonth = newMonth
}.launchIn(coroutineScope)
}
}

fun getMonthForPage(index: Int): YearMonth =
initialMonth.plusMonths((index - StartIndex).toLong())

private fun moveToMonth(month: YearMonth) {
if (month == currentlyVisibleMonth) return
if (month == currentFirstVisibleMonth) return
initialMonth.minus(month).let { offset ->
coroutineScope.launch {
listState.animateScrollToItem((StartIndex - offset).toInt())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.github.boguszpawlowski.composecalendar.util

import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.snapshotFlow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map

context(LazyListState) internal fun <T> Flow<T>.throttleOnOffset() =
combine(
snapshotFlow { firstVisibleItemScrollOffset }
) { newMonth, offset ->
newMonth to (offset <= MinimalOffsetForEmit)
}.filter { (_, shouldUpdate) ->
shouldUpdate
}.map { (newValue, _) -> newValue }

private const val MinimalOffsetForEmit = 10
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.snapshotFlow
import io.github.boguszpawlowski.composecalendar.header.WeekState
import io.github.boguszpawlowski.composecalendar.month.StartIndex
import io.github.boguszpawlowski.composecalendar.util.throttleOnOffset
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
Expand All @@ -21,7 +22,7 @@ internal class WeekListState(
private val listState: LazyListState,
) {

private val currentlyVisibleMonth by derivedStateOf {
private val currentlyFirstVisibleMonth by derivedStateOf {
getWeekForPage(listState.firstVisibleItemIndex)
}

Expand All @@ -30,16 +31,20 @@ internal class WeekListState(
moveToWeek(week)
}.launchIn(coroutineScope)

snapshotFlow { currentlyVisibleMonth }.onEach { newMonth ->
weekState.currentWeek = newMonth
}.launchIn(coroutineScope)
with(listState) {
snapshotFlow { currentlyFirstVisibleMonth }
.throttleOnOffset()
.onEach { newMonth ->
weekState.currentWeek = newMonth
}.launchIn(coroutineScope)
}
}

fun getWeekForPage(index: Int): Week =
initialWeek.plusWeeks((index - StartIndex).toLong())

private fun moveToWeek(week: Week) {
if (week == currentlyVisibleMonth) return
if (week == currentlyFirstVisibleMonth) return
initialWeek.minus(week).let { offset ->
coroutineScope.launch {
listState.animateScrollToItem((StartIndex - offset).toInt())
Expand Down

0 comments on commit d7cd040

Please sign in to comment.