-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8db43ec
commit 61132b9
Showing
21 changed files
with
338 additions
and
115 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
root = true | ||
|
||
[*.{kt,kts}] | ||
ktlint_function_naming_ignore_when_annotated_with=Composable |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -106,6 +106,7 @@ kotlin { | |
} | ||
} | ||
|
||
|
||
android { | ||
namespace = "com.wojciechosak.calendar" | ||
compileSdk = 34 | ||
|
86 changes: 86 additions & 0 deletions
86
calendar/src/commonMain/kotlin/io/wojciechosak/calendar/animation/CalendarAnimator.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,86 @@ | ||
package io.wojciechosak.calendar.animation | ||
|
||
import androidx.compose.animation.core.AnimationSpec | ||
import androidx.compose.animation.core.Spring | ||
import androidx.compose.animation.core.spring | ||
import androidx.compose.foundation.ExperimentalFoundationApi | ||
import androidx.compose.foundation.pager.PagerState | ||
import io.wojciechosak.calendar.config.CalendarConstants.INITIAL_PAGE_INDEX | ||
import io.wojciechosak.calendar.utils.copy | ||
import kotlinx.datetime.DateTimeUnit | ||
import kotlinx.datetime.LocalDate | ||
import kotlinx.datetime.daysUntil | ||
import kotlinx.datetime.periodUntil | ||
import kotlinx.datetime.plus | ||
import kotlin.math.floor | ||
|
||
@OptIn(ExperimentalFoundationApi::class) | ||
class CalendarAnimator(private val startDate: LocalDate) { | ||
enum class AnimationMode { | ||
MONTH, | ||
DAY, | ||
WEEK, | ||
} | ||
|
||
private var pagerState: PagerState? = null | ||
|
||
private var mode: AnimationMode = AnimationMode.MONTH | ||
|
||
fun updatePagerState(pagerState: PagerState) { | ||
this.pagerState = pagerState | ||
} | ||
|
||
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 = pagerState?.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, | ||
) | ||
} | ||
} | ||
} |
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
5 changes: 5 additions & 0 deletions
5
calendar/src/commonMain/kotlin/io/wojciechosak/calendar/config/CalendarConstants.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,5 @@ | ||
package io.wojciechosak.calendar.config | ||
|
||
object CalendarConstants { | ||
internal const val INITIAL_PAGE_INDEX = Int.MAX_VALUE / 2 | ||
} |
17 changes: 17 additions & 0 deletions
17
calendar/src/commonMain/kotlin/io/wojciechosak/calendar/config/MonthYear.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,17 @@ | ||
package io.wojciechosak.calendar.config | ||
|
||
import io.wojciechosak.calendar.utils.toMonthYear | ||
import kotlinx.datetime.DateTimeUnit | ||
import kotlinx.datetime.LocalDate | ||
import kotlinx.datetime.Month | ||
import kotlinx.datetime.plus | ||
|
||
data class MonthYear(val month: Month, val year: Int) | ||
|
||
fun MonthYear.toLocalDate() = LocalDate(year, month, 1) | ||
|
||
fun MonthYear.monthOffset(monthOffset: Int) = | ||
this | ||
.toLocalDate() | ||
.plus(monthOffset, DateTimeUnit.MONTH) | ||
.toMonthYear() |
5 changes: 0 additions & 5 deletions
5
calendar/src/commonMain/kotlin/io/wojciechosak/calendar/config/YearMonth.kt
This file was deleted.
Oops, something went wrong.
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
32 changes: 22 additions & 10 deletions
32
calendar/src/commonMain/kotlin/io/wojciechosak/calendar/view/VerticalCalendarView.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 |
---|---|---|
@@ -1,34 +1,46 @@ | ||
package io.wojciechosak.calendar.view | ||
|
||
import androidx.compose.foundation.ExperimentalFoundationApi | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.PaddingValues | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.pager.PageSize | ||
import androidx.compose.foundation.pager.VerticalPager | ||
import androidx.compose.foundation.pager.rememberPagerState | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.unit.dp | ||
import io.wojciechosak.calendar.animation.CalendarAnimator | ||
import io.wojciechosak.calendar.config.CalendarConstants.INITIAL_PAGE_INDEX | ||
import kotlinx.datetime.LocalDate | ||
|
||
@OptIn(ExperimentalFoundationApi::class) | ||
@Composable | ||
fun VerticalCalendarView( | ||
startDate: LocalDate, | ||
calendarAnimator: CalendarAnimator = CalendarAnimator(startDate), | ||
modifier: Modifier = Modifier, | ||
pageSize: PageSize = PageSize.Fill, | ||
contentPadding: PaddingValues = PaddingValues(0.dp), | ||
calendarView: @Composable (monthOffset: Int) -> Unit, | ||
) { | ||
val pagerState = | ||
rememberPagerState( | ||
initialPage = INITIAL_PAGE_INDEX, | ||
pageCount = { Int.MAX_VALUE }, | ||
) | ||
LaunchedEffect(pagerState) { | ||
calendarAnimator.setAnimationMode(CalendarAnimator.AnimationMode.MONTH) | ||
calendarAnimator.updatePagerState(pagerState) | ||
} | ||
VerticalPager( | ||
state = | ||
rememberPagerState( | ||
initialPage = Int.MAX_VALUE / 2, | ||
pageCount = { Int.MAX_VALUE }, | ||
), | ||
state = pagerState, | ||
modifier = modifier.fillMaxWidth(), | ||
pageSize = pageSize, | ||
beyondBoundsPageCount = 0, | ||
contentPadding = contentPadding, | ||
) { | ||
val index = it - Int.MAX_VALUE / 2 | ||
Column { | ||
calendarView(index) | ||
} | ||
val index = it - INITIAL_PAGE_INDEX | ||
calendarView(index) | ||
} | ||
} |
Oops, something went wrong.