kizitonwose / Calendar

A highly customizable calendar view and compose library for Android and Kotlin Multiplatform.
MIT License
4.67k stars 506 forks source link

Add more info in DayPosition #589

Open KovshefulCoder opened 1 week ago

KovshefulCoder commented 1 week ago

Feature

Add more info in DayPosition to be able to use it in UI

I can propose smth like this: 1) Add something like index or offset in DayPosition to know position of this date in list of dates of the same DayPosition type. 2) Based on this offset calculate if this DayPosition is last of such DayPositions

Use case

Be able to customize UI based on position of day, especially for in and out days. In my case for the last outDay(in phto there is only one outDay, 1day of next month) I want to show arrow indicating how to scroll this calendar image After a little thought, I also came up with a fading for outDays and vice versa for inDays, based on the position and number of such days

Tech (MVP)

New DayPosition

public sealed class DayPosition(open val index: Int, open val isLast: Boolean) {
    data class InDate(override val index: Int, override val isLast: Boolean) :
        DayPosition(index, isLast)

    data class MonthDate(override val index: Int, override val isLast: Boolean) :
        DayPosition(index, isLast)

    data class OutDate(override val index: Int, override val isLast: Boolean) :
        DayPosition(index, isLast)
} 

How it is calculated in MonthData

internal data class MonthData(
    private val month: YearMonth,
    private val inDays: Int,
    private val outDays: Int,
) {
    // …
    private val inPlusMonthDays = inDays + month.lengthOfMonth()
    // …    
    private fun getDay(dayOffset: Int): CalendarDay2 {
        val date = firstDay.plusDays(dayOffset)
        val position = when (date.yearMonth) {
            month -> DayPosition.MonthDate(
                index = dayOffset - inDays,
                isLast = (dayOffset - inDays) == month.lengthOfMonth() - 1
            )
            previousMonth -> DayPosition.InDate(
                index = dayOffset,
                isLast = dayOffset == inDays - 1
            )
            nextMonth -> DayPosition.OutDate(
                index = dayOffset - inPlusMonthDays,
                isLast = (dayOffset - inPlusMonthDays) == outDays - 1
            )
            else -> throw IllegalArgumentException("Invalid date: $date in month: $month")
        }
        return CalendarDay(date, position)
    }
}
kizitonwose commented 1 week ago

You can already figure this out from the CalendarDay provided in the binder.

    val daysOfWeek = daysOfWeek(firstDayOfWeek = firstDayOfWeekFromLocale())

    if (day.position == DayPosition.InDate && day.date.dayOfWeek == daysOfWeek.first()) {
        // This is the first in date in the row
    }

    if (day.position == DayPosition.OutDate && day.date.dayOfWeek == daysOfWeek.last()) {
        // This is the last out date in the row
    }