Skip to content

dyguests/LinCalendar

Repository files navigation

LinCalendar

A composable Calendar.

default default default

Dependency

  1. Add it in your root build.gradle at the end of repositories:

        dependencyResolutionManagement {
            repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
            repositories {
                mavenCentral()
                maven { url 'https://jitpack.io' }
            }
        }
  2. Add the dependency

        dependencies {
            implementation 'com.github.dyguests:LinCalendar:0.4.0'
        }

Usage

val state = rememberLinCalendarState()

LinCalendar(
    state = state,
)

Properties

fun rememberLinCalendarState(
    initialDate: LocalDate = LocalDate.now(),
    startDate: LocalDate = LocalDate.of(1900, 1, 1),
    endDate: LocalDate = LocalDate.of(2099, 12, 31),
    initialDisplayMode: LinCalendar.DisplayMode = LinCalendar.DisplayMode.MONTHLY,
    option: LinCalendar.Option = LinCalendarDefaults.option(),
): LinCalendarState
enum class DisplayMode {
    MONTHLY,
    WEEKLY, // todo impl
}
data class Option(
    val headerHeight: Dp = 32.dp,
    val rowHeight: Dp = 36.dp,
    val firstDayOfWeek: DayOfWeek = DayOfWeek.MONDAY,
    val weekDisplayMode: WeekDisplayMode = WeekDisplayMode.FIXED_HEIGHT,
    val locale: Locale = Locale.getDefault(),
)

Consider of WeekDisplayMode, the height of Calendar in different months may be different.

Therefore, you cannot set the height of Calendar directly, but use headerHeight and rowHeight.

enum class WeekDisplayMode {
    // Fixed height, leaving the fifth week empty
    FIXED_HEIGHT,

    // Fixed height, equally dividing height by weeks
    EQUAL_HEIGHT, // todo impl

    // Dynamic height, adapting to the number of weeks in the month
    DYNAMIC_HEIGHT // todo impl
}

Custom composable

Each part of LinCalendar is composable, so you can customize each part yourself.

Structure
  • LinCalendar
    • monthsField
      • monthFiled
        • weekHeaderField
          • dayHeaderField
        • weekField
          • dayField
Custom Example

Add a highlighted background to today's day of the calendar.

Step 1

Add LinCalendar

val state = rememberLinCalendarState()

LinCalendar(
    state = state,
)

Step 2

If you look at the source code, you can see that the above code is equivalent to:

LinCalendar(
    state = state,
    monthsField = LinCalendarDefaults.monthsField(
        state = state,
        monthFiled = LinCalendarDefaults.monthField(
            state = state,
        ),
    ),
)

...

equivalent to:

LinCalendar(
    state = state,
    monthsField = LinCalendarDefaults.monthsField(
        state = state,
        monthFiled = LinCalendarDefaults.monthField(
            state = state,
            weekField = LinCalendarDefaults.weekField(
                state = state,
                dayField = LinCalendarDefaults.dayField(
                    state = state,
                )
            ),
        ),
    ),
)

To highlighted background to today's day, You need to custom dayField, change code to this:

val dayField = LinCalendarDefaults.dayField(
    state = state,
)

LinCalendar(
    // ...
    dayField = dayField
    // ...
)

Now we focus on dayField

Step 3

Inline the function LinCalendarDefaults.dayField.(You can also copy the source code of LinCalendarDefaults.dayField)

val dayField: @Composable RowScope.(YearMonth, LocalDate) -> Unit = { yearMonth: YearMonth, localDate: LocalDate ->
    val now = remember { LocalDate.now() }

    Box(
        modifier = Modifier
            .height(state.option.rowHeight)
            .weight(1f)
            .then(Modifier),
        contentAlignment = Alignment.Center,
    ) {
        Text(
            text = localDate.dayOfMonth.toString(),
            style = TextStyle(
                color = if (localDate == now) MaterialTheme.colorScheme.primary
                else MaterialTheme.colorScheme.onSurface,
                fontWeight = if (localDate == now) FontWeight.Bold
                else if (yearMonth.month == localDate.month) FontWeight.Normal
                else FontWeight.Light,
            ),
        )
    }
}

Now you can add a highlighted background to today.

    val dayField: @Composable RowScope.(YearMonth, LocalDate) -> Unit = { yearMonth: YearMonth, localDate: LocalDate ->
    // ...
    Box(
        // ...
    ) {
        if (localDate == now) {
            Box(
                modifier = Modifier
                    .size(32.dp)
                    .background(Color.Red, CircleShape)
            )
        }
        Text(
            // ...
            style = TextStyle(
                color = if (localDate == now) Color.White
                // ...
            ),
        )
    }
}
default

That's it.

Todo List

  • 隐藏无关细节。比如monthFiled中的计算逻辑

References

License

MIT LICENSE