From d7cd0406e503394beca70485d49e9f8e4dbb2b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogusz=20Paw=C5=82owski?= Date: Sat, 18 Mar 2023 20:36:48 +0100 Subject: [PATCH] Add month changes throttling (#95) --- library/build.gradle.kts | 2 +- .../composecalendar/month/MonthListState.kt | 15 ++++++++++----- .../util/ListStateExtensions.kt | 19 +++++++++++++++++++ .../composecalendar/week/WeekListState.kt | 15 ++++++++++----- 4 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 library/src/main/java/io/github/boguszpawlowski/composecalendar/util/ListStateExtensions.kt diff --git a/library/build.gradle.kts b/library/build.gradle.kts index aff0c2f..70dcc37 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -11,7 +11,7 @@ plugins { android { tasks.withType { kotlinOptions { - freeCompilerArgs = freeCompilerArgs + "-Xexplicit-api=strict" + freeCompilerArgs = freeCompilerArgs + "-Xexplicit-api=strict" + "-Xcontext-receivers" } } } diff --git a/library/src/main/java/io/github/boguszpawlowski/composecalendar/month/MonthListState.kt b/library/src/main/java/io/github/boguszpawlowski/composecalendar/month/MonthListState.kt index a3809f4..16c781f 100644 --- a/library/src/main/java/io/github/boguszpawlowski/composecalendar/month/MonthListState.kt +++ b/library/src/main/java/io/github/boguszpawlowski/composecalendar/month/MonthListState.kt @@ -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 @@ -21,7 +22,7 @@ internal class MonthListState( private val listState: LazyListState, ) { - private val currentlyVisibleMonth by derivedStateOf { + private val currentFirstVisibleMonth by derivedStateOf { getMonthForPage(listState.firstVisibleItemIndex) } @@ -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()) diff --git a/library/src/main/java/io/github/boguszpawlowski/composecalendar/util/ListStateExtensions.kt b/library/src/main/java/io/github/boguszpawlowski/composecalendar/util/ListStateExtensions.kt new file mode 100644 index 0000000..07c576d --- /dev/null +++ b/library/src/main/java/io/github/boguszpawlowski/composecalendar/util/ListStateExtensions.kt @@ -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 Flow.throttleOnOffset() = + combine( + snapshotFlow { firstVisibleItemScrollOffset } + ) { newMonth, offset -> + newMonth to (offset <= MinimalOffsetForEmit) + }.filter { (_, shouldUpdate) -> + shouldUpdate + }.map { (newValue, _) -> newValue } + +private const val MinimalOffsetForEmit = 10 diff --git a/library/src/main/java/io/github/boguszpawlowski/composecalendar/week/WeekListState.kt b/library/src/main/java/io/github/boguszpawlowski/composecalendar/week/WeekListState.kt index c6d75c4..be8b38c 100644 --- a/library/src/main/java/io/github/boguszpawlowski/composecalendar/week/WeekListState.kt +++ b/library/src/main/java/io/github/boguszpawlowski/composecalendar/week/WeekListState.kt @@ -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 @@ -21,7 +22,7 @@ internal class WeekListState( private val listState: LazyListState, ) { - private val currentlyVisibleMonth by derivedStateOf { + private val currentlyFirstVisibleMonth by derivedStateOf { getWeekForPage(listState.firstVisibleItemIndex) } @@ -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())