Skip to content

Commit

Permalink
Animations and change page extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
WojciechOsak committed May 26, 2024
1 parent 1a57b61 commit 2e9ed8a
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<Float> = 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<Float> = 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,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand All @@ -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<LocalDate>,
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<LocalDate>,
)

/**
Expand All @@ -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<LocalDate> = 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<LocalDate> = mutableListOf(),
): MutableState<CalendarConfig> = 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<CalendarConfig>.nextMonth() {
val currentConfig = value
value = value.copy(
monthYear = currentConfig.monthYear.toLocalDate().plus(1, DateTimeUnit.MONTH).toMonthYear()
)
}

fun MutableState<CalendarConfig>.previousMonth() {
val currentConfig = value
value = value.copy(
monthYear = currentConfig.monthYear.toLocalDate().minus(1, DateTimeUnit.MONTH).toMonthYear()
)
}
7 changes: 7 additions & 0 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,10 @@ Button(onClick = {
}
```

CalendarAnimator provides also pager methods like:

```kotlin
animateToNextPage()
animateToPreviousPage()
scrollToPage(page: Int, pageOffsetFraction: Float = 0f)
```

0 comments on commit 2e9ed8a

Please sign in to comment.