From 9633a6a1e40303845c1fcd5a64dc637d26f7f988 Mon Sep 17 00:00:00 2001 From: Wojciech Osak Date: Sun, 26 May 2024 22:57:15 +0200 Subject: [PATCH] Animations and change page extensions --- .../calendar/animation/CalendarAnimator.kt | 132 ++++++++++-------- .../calendar/config/CalendarConfig.kt | 79 ++++++----- 2 files changed, 119 insertions(+), 92 deletions(-) diff --git a/calendar/src/commonMain/kotlin/io/wojciechosak/calendar/animation/CalendarAnimator.kt b/calendar/src/commonMain/kotlin/io/wojciechosak/calendar/animation/CalendarAnimator.kt index 447c1b5..0154f9b 100644 --- a/calendar/src/commonMain/kotlin/io/wojciechosak/calendar/animation/CalendarAnimator.kt +++ b/calendar/src/commonMain/kotlin/io/wojciechosak/calendar/animation/CalendarAnimator.kt @@ -21,71 +21,83 @@ import kotlin.math.floor */ @OptIn(ExperimentalFoundationApi::class) class CalendarAnimator(private val startDate: LocalDate) { - enum class AnimationMode { - MONTH, - DAY, - WEEK, - } + enum class AnimationMode { + MONTH, + DAY, + WEEK, + } - private var pagerState: PagerState? = null + private var pagerState: PagerState? = null - private var mode: AnimationMode = AnimationMode.MONTH + private var mode: AnimationMode = AnimationMode.MONTH - internal fun updatePagerState(pagerState: PagerState) { - this.pagerState = pagerState - } + internal fun updatePagerState(pagerState: PagerState) { + this.pagerState = pagerState + } - internal fun setAnimationMode(mode: AnimationMode) { - this.mode = mode - } + internal fun setAnimationMode(mode: AnimationMode) { + this.mode = mode + } - suspend fun animateTo( - target: LocalDate, - pageOffsetFraction: Float = 0f, - animationSpec: AnimationSpec = spring(stiffness = Spring.StiffnessMediumLow), - ) { - val initialPage = INITIAL_PAGE_INDEX - val currentDate = - when (mode) { - AnimationMode.MONTH -> - startDate.plus( - (pagerState?.targetPage ?: 0) - initialPage, - DateTimeUnit.MONTH, - ) + suspend fun animateToNextPage() { + pagerState?.animateScrollToPage(pagerState!!.currentPage + 1) + } - AnimationMode.DAY -> - startDate.plus( - (pagerState?.targetPage ?: 0) - initialPage, - DateTimeUnit.DAY, - ) + suspend fun animateToPreviousPage() { + pagerState?.animateScrollToPage(pagerState!!.currentPage - 1) + } - AnimationMode.WEEK -> - startDate.plus( - (pagerState?.targetPage ?: 0) - initialPage, - DateTimeUnit.WEEK, - ) - } - val targetDate = - target.run { - if (mode == AnimationMode.MONTH) { - copy(day = currentDate.dayOfMonth) - } else { - this - } - } - val diff = currentDate.periodUntil(targetDate) - val offset = - when (mode) { - AnimationMode.MONTH -> diff.months + diff.years * 12 - AnimationMode.DAY -> currentDate.daysUntil(targetDate) - AnimationMode.WEEK -> floor(currentDate.daysUntil(targetDate) / 7f).toInt() - } - if (initialPage + offset > 0) { - pagerState?.animateScrollToPage( - page = (pagerState?.settledPage ?: initialPage) + offset, - pageOffsetFraction = pageOffsetFraction, - animationSpec = animationSpec, - ) - } - } + suspend fun scrollToPage(page: Int, pageOffsetFraction: Float = 0f) { + pagerState?.scrollToPage(page, pageOffsetFraction = pageOffsetFraction) + } + + suspend fun animateTo( + target: LocalDate, + pageOffsetFraction: Float = 0f, + animationSpec: AnimationSpec = spring(stiffness = Spring.StiffnessMediumLow), + ) { + val initialPage = INITIAL_PAGE_INDEX + val currentDate = + when (mode) { + AnimationMode.MONTH -> + startDate.plus( + (pagerState?.targetPage ?: 0) - initialPage, + DateTimeUnit.MONTH, + ) + + AnimationMode.DAY -> + startDate.plus( + (pagerState?.targetPage ?: 0) - initialPage, + DateTimeUnit.DAY, + ) + + AnimationMode.WEEK -> + startDate.plus( + (pagerState?.targetPage ?: 0) - initialPage, + DateTimeUnit.WEEK, + ) + } + val targetDate = + target.run { + if (mode == AnimationMode.MONTH) { + copy(day = currentDate.dayOfMonth) + } else { + this + } + } + val diff = currentDate.periodUntil(targetDate) + val offset = + when (mode) { + AnimationMode.MONTH -> diff.months + diff.years * 12 + AnimationMode.DAY -> currentDate.daysUntil(targetDate) + AnimationMode.WEEK -> floor(currentDate.daysUntil(targetDate) / 7f).toInt() + } + if (initialPage + offset > 0) { + pagerState?.animateScrollToPage( + page = (pagerState?.settledPage ?: initialPage) + offset, + pageOffsetFraction = pageOffsetFraction, + animationSpec = animationSpec, + ) + } + } } diff --git a/calendar/src/commonMain/kotlin/io/wojciechosak/calendar/config/CalendarConfig.kt b/calendar/src/commonMain/kotlin/io/wojciechosak/calendar/config/CalendarConfig.kt index 5ab669d..467291a 100644 --- a/calendar/src/commonMain/kotlin/io/wojciechosak/calendar/config/CalendarConfig.kt +++ b/calendar/src/commonMain/kotlin/io/wojciechosak/calendar/config/CalendarConfig.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.remember import io.wojciechosak.calendar.utils.toMonthYear import kotlinx.datetime.DateTimeUnit import kotlinx.datetime.LocalDate +import kotlinx.datetime.minus import kotlinx.datetime.plus /** @@ -25,15 +26,15 @@ import kotlinx.datetime.plus */ @Stable data class CalendarConfig( - val minDate: LocalDate, - val maxDate: LocalDate, - val monthYear: MonthYear, - val dayOfWeekOffset: Int, - val showNextMonthDays: Boolean, - val showPreviousMonthDays: Boolean, - val showHeader: Boolean, - val showWeekdays: Boolean, - val selectedDates: List, + val minDate: LocalDate, + val maxDate: LocalDate, + val monthYear: MonthYear, + val dayOfWeekOffset: Int, + val showNextMonthDays: Boolean, + val showPreviousMonthDays: Boolean, + val showHeader: Boolean, + val showWeekdays: Boolean, + val selectedDates: List, ) /** @@ -53,28 +54,42 @@ data class CalendarConfig( */ @Composable fun rememberCalendarState( - startDate: LocalDate, - minDate: LocalDate = LocalDate(1971, 1, 1), - maxDate: LocalDate = startDate.plus(15, DateTimeUnit.YEAR), - monthOffset: Int, - dayOfWeekOffset: Int = 0, - showNextMonthDays: Boolean = true, - showPreviousMonthDays: Boolean = true, - showHeader: Boolean = true, - showWeekdays: Boolean = true, - selectedDates: MutableList = mutableListOf(), + startDate: LocalDate, + minDate: LocalDate = LocalDate(1971, 1, 1), + maxDate: LocalDate = startDate.plus(15, DateTimeUnit.YEAR), + monthOffset: Int, + dayOfWeekOffset: Int = 0, + showNextMonthDays: Boolean = true, + showPreviousMonthDays: Boolean = true, + showHeader: Boolean = true, + showWeekdays: Boolean = true, + selectedDates: MutableList = mutableListOf(), ): MutableState = remember { - mutableStateOf( - CalendarConfig( - minDate = minDate, - maxDate = maxDate, - monthYear = startDate.plus(monthOffset, DateTimeUnit.MONTH).toMonthYear(), - dayOfWeekOffset = dayOfWeekOffset, - showNextMonthDays = showNextMonthDays, - showPreviousMonthDays = showPreviousMonthDays, - showHeader = showHeader, - showWeekdays = showWeekdays, - selectedDates = selectedDates, - ), - ) + mutableStateOf( + CalendarConfig( + minDate = minDate, + maxDate = maxDate, + monthYear = startDate.plus(monthOffset, DateTimeUnit.MONTH).toMonthYear(), + dayOfWeekOffset = dayOfWeekOffset, + showNextMonthDays = showNextMonthDays, + showPreviousMonthDays = showPreviousMonthDays, + showHeader = showHeader, + showWeekdays = showWeekdays, + selectedDates = selectedDates, + ), + ) } + +fun MutableState.nextMonth() { + val currentConfig = value + value = value.copy( + monthYear = currentConfig.monthYear.toLocalDate().plus(1, DateTimeUnit.MONTH).toMonthYear() + ) +} + +fun MutableState.previousMonth() { + val currentConfig = value + value = value.copy( + monthYear = currentConfig.monthYear.toLocalDate().minus(1, DateTimeUnit.MONTH).toMonthYear() + ) +} \ No newline at end of file