{"id":13822055,"url":"https://github.com/boguszpawlowski/ComposeCalendar","last_synced_at":"2025-05-16T15:32:23.986Z","repository":{"id":40380442,"uuid":"355182891","full_name":"boguszpawlowski/ComposeCalendar","owner":"boguszpawlowski","description":"A Jetpack Compose library for handling calendar component rendering.","archived":false,"fork":false,"pushed_at":"2024-05-15T13:20:57.000Z","size":1066,"stargazers_count":324,"open_issues_count":4,"forks_count":40,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-08-04T08:07:34.405Z","etag":null,"topics":["android","calendar","calendar-component","calendar-view","compose","kotlin-android"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/boguszpawlowski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-06T12:37:13.000Z","updated_at":"2024-08-04T08:07:39.620Z","dependencies_parsed_at":"2023-09-27T22:19:46.038Z","dependency_job_id":"4a59349b-95c5-4bf1-93b5-2027a05f2c4e","html_url":"https://github.com/boguszpawlowski/ComposeCalendar","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":"boguszpawlowski/AndroidTemplate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boguszpawlowski%2FComposeCalendar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boguszpawlowski%2FComposeCalendar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boguszpawlowski%2FComposeCalendar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boguszpawlowski%2FComposeCalendar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boguszpawlowski","download_url":"https://codeload.github.com/boguszpawlowski/ComposeCalendar/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225436454,"owners_count":17474149,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","calendar","calendar-component","calendar-view","compose","kotlin-android"],"created_at":"2024-08-04T08:01:40.465Z","updated_at":"2024-11-19T22:31:58.105Z","avatar_url":"https://github.com/boguszpawlowski.png","language":"Kotlin","funding_links":[],"categories":["Kotlin","Libraries"],"sub_categories":["UI"],"readme":"\u003cimg src=\"https://user-images.githubusercontent.com/36514058/154865567-3deef00d-f43e-4286-aa81-2924b81c650d.svg\" width=\"500\"/\u003e\n\nCompose Calendar is a composable handling all complexity of rendering calendar component and date selection.\nDue to flexibility provided by slot API's, you can decide how the calendar will look like, the library will handle proper calendar elements arrangement and it's state.\n\n![Github Actions](https://github.com/boguszpawlowski/composecalendar/actions/workflows/publish-snapshot.yml/badge.svg?branch=main)\n[\u003cimg src=\"https://img.shields.io/maven-central/v/io.github.boguszpawlowski.composecalendar/composecalendar.svg?label=release%20version\"/\u003e](https://search.maven.org/search?q=g:io.github.boguszpawlowski.composecalendar)\n[\u003cimg src=\"https://img.shields.io/nexus/s/https/s01.oss.sonatype.org/io.github.boguszpawlowski.composecalendar/composecalendar.svg?label=snapshot%20version\"/\u003e](https://s01.oss.sonatype.org/content/repositories/snapshots/io/github/boguszpawlowski/composecalendar/)\n[\u003cimg src=\"https://androidweekly.net/issues/issue-501/badge\"/\u003e](https://androidweekly.net/issues/issue-501/)\n## Setup\nLibrary is available on Maven Central repository.\n```kotlin\n  // module-level build.gradle\n  dependecies {\n    implementation \"io.github.boguszpawlowski.composecalendar:composecalendar:\u003clatest-version\u003e\"\n    \n    // separate artifact with utilities for working with kotlinx-datetime\n    implementation \"io.github.boguszpawlowski.composecalendar:kotlinx-datetime:\u003clatest-version\u003e\"\n  }\n```\nSnapshots are available on [Sonatype’s snapshots repository](https://s01.oss.sonatype.org/content/repositories/snapshots/io/github/boguszpawlowski/composecalendar/).\n\n### 1.3.0 Changes\nFrom version 1.3.0 library no longer uses `coreLibraryDesugaring` itself. If you are using it in project supporting min SDK \u003c 26, you need to add it to prevent runtime crashes. \n```kotlin\n  // app-level build.gradle\n  android {\n    compileOptions {\n        coreLibraryDesugaringEnabled true\n    }\n    kotlinOptions {\n        jvmTarget = \"1.8\"\n    }\n  }\n  dependencies {\n    coreLibraryDesugaring \"com.android.tools:desugar_jdk_libs:2.0.4\"\n  }\n```\n\n## Supported features\n- Selection (single, multiple or a range of days)\n- Chose day as first day of week\n- Showing/hiding adjacent months\n- Month and week headers\n- Customizable month container\n- Fully customizable day content\n- Horizontal swipe for changing a current month\n- Month / Week mode\n- Min / Max Month (or Week) \n\n## Basic Usage\n\n### Static calendar\nTo show the basic version of the calendar, without any kind of selection mechanism, you can simply use the `StaticCalendar` composable without passing any parameters:\n```kotlin\n\n  @Composable\n  fun MainScreen() {\n    StaticCalendar()\n  }\n\n```\nThis chunk will render the calendar with default components for each day, and also month and week headers.\nSee the `StaticCalendarSample` file for a full example. For showing a week calendar, you can similarly use `StaticWeekCalendar`:\n```kotlin\n\n  @Composable\n  fun MainScreen() {\n    StaticWeekCalendar()\n  }\n\n```\n\n\u003cimg src=\"https://github.com/boguszpawlowski/ComposeCalendar/blob/main/blob/screenshot_1.jpg\" width=\"260\"\u003e\n\n\u003e :exclamation: By default, at first the calendar will show current month. If you want to start with some different date, you have to pass an `initialMonth` parameter to the initial state of the calendar. See [Initial State section](#initial-state)\n\n### Selectable calendar\nCalendar with a mechanism for selection. The default implementation uses `DynamicSelectionState` (see [Dynamic Selection section](#dynamic-selection-state)) which allows to change `SelectionMode` in the runtime.\n```kotlin\n\n  @Composable\n  fun MainScreen() {\n    SelectableCalendar()\n  }\n\n```\nBy the default, after changing the selection mode, selection is cleared.\nSee the `SelectableCalendarSample` file for a full example. For showing a week calendar, you can similarly use `SelectableWeekCalendar`:\n```kotlin\n\n  @Composable\n  fun MainScreen() {\n    SelectableWeekCalendar()\n  }\n\n```\nSee the `WeekCalendarSample` file for a full example.\n\nhttps://user-images.githubusercontent.com/36514058/126049987-685a7b81-1596-48a4-95a1-c342f6c796bf.mp4\n\n\u003e :exclamation: If you want to define your own selection behavior, please check out the [Custom Selection section](#custom-selection) and/or `CustomSelectionSample`.\n\n### Calendar with custom components\nFor the customization you should pass your own composable functions as day content, moth header etc.:\n```kotlin\n\n  @Composable\n  fun MyDay(dayState: DayState) {\n    Text(dayState.date.dayOfMonth.toString())\n  }\n\n  @Composable\n  fun MainScreen() {\n     StaticCalendar(\n        dayContent = { dayState -\u003e MyDay(dayState) }\n     )\n  }\n\n```\nThe same you can do for every customizable element:\n- Day content - responsible for single day content\n- Month header - responsible for showing the current month (and by default for changing the current month)\n- Week header - responsible for showing the names of week days.\n- Month container - wrapping the month content, it defaults to a plain `Box`, but can be any layout.\n\nThe `Calendar` composable accepts a `Modifier` for simple customization of the overall appearance.\nSee the `CustomComponentsSample` for a full example.\n\n### Custom selection\nAs the selection state is represented by an interface, you can provide your own implementation, to suit your\nuse-case. E.g:\n```kotlin\n  class MonthSelectionState(\n    initialSelection: YearMonth? = null,\n  ) : SelectionState {\n    private var selection by mutableStateOf(initialSelection)\n  \n    override fun isDateSelected(date: LocalDate): Boolean =\n      date.yearMonth == selection\n  \n    override fun onDateSelected(date: LocalDate) {\n      selection = if (date.yearMonth == selection) null else date.yearMonth\n    }\n  }\n```\nTo use the defined selection state, you have to pass it into a generic version of `Calendar` composable.\nThis chunk is an implementation that will select all days in a clicked day's month. For a full example\nplease check out `CustomSelectionSample` file.\n\n### Calendar properties customization\nApart from rendering your own components inside the calendar, you can modify it by passing different properties.:\n- `showAdjacentMonths` - whenever to render days from adjacent months. Defaults to `true`.\n- `firstDayOfWeek` - you can pass the `DayOfWeek` which you want you week to start with. It defaults to the first day of week of the `Locale.default()`.\n- `horizontalScrollEnabled` - a Boolean flag which enables month to be changed by a horizontal swipe. Defaults to `true`.\n- `minMonth` - a `YearMonth` object representing the minimum month that can be shown in the calendar. By default there is no minimum month.\n- `maxMonth` - a `YearMonth` object representing the maximum month that can be shown in the calendar. By default there is no maximum month.\n\n\u003e :exclamation: You cannot set `minMonth` to be lower than `maxMonth` and vice versa. If you do so, the calendar state won't change.\n\nApart from this, `Calendar` you can pass a `Modifier` object like in any other composable.\n\n## State\nCalendar composable holds its state as an `CalendarState` object, which consists of 2 properties.\n- `MonthState` - current value of the presented month.\n- `SelectionState` - current value of the selection.\n\nBoth properties are represented by interfaces, so the default implementation can be overwritten if needed.\nThe calendar state is leveraging Compose saving mechanism, so that the state will survive any configuration change, or the process death.\n\n### Initial state\nInitial state for the static calendar is provided by the `rememberCalendarState()` function. If you need to change the initial conditions, you can pass the params to it:\n\n```kotlin\n\n  @Composable\n  fun MainScreen() {\n    StaticCalendar(\n      calendarState = rememberCalendarState(\n        initialMonth = YearMonth.now().plusYears(1),\n      )\n    )\n  }\n\n```\nIn case of the selectable calendar, the state has additional parameters, used to calculate the initial selection:\n\n```kotlin\n\n  @Composable\n  fun MainScreen() {\n    SelectableCalendar(\n      calendarState = rememberSelectableCalendarState(\n        initialMonth = YearMonth.now().plusYears(1),\n        initialSelection = listOf(LocalDate.parse(\"20-01-2020\")),\n        initialSelectionMode = SelectionMode.Period,\n      )\n    )\n  }\n\n```\n\n### State hoisting\nIn case you need to react to the state changes, or change the state from the outside of the composable,\nyou need to hoist the state out of the `Calendar` composable:\n\n```kotlin\n\n  @Composable\n  fun MainScreen() {\n    val calendarState = rememberCalendarState()\n    StaticCalendar(calendarState = calendarState)\n   \n    // now you can manipulate the state from scope of this composable\n    calendarState.monthState.currentMonth = YearMonth.of(2020, 5)\n  }\n\n```\n\n### Dynamic Selection State\nBy default, the `SelectableCalendar` is using a `DynamicSelectionState` implementation of `SelectionState`. The selection is kept as a list of `LocalDate` objects. For a purpose of flexibility, `DynamicSelectionState` allows for 4 different selection modes, each one varying how the selection is changing after interacting with the calendar. Furthermore, selection mode can be changed in the runtime, for some specific use-cases.\nSelection modes are represented by `SelectionMode` enum, with following values:\n- `None` - no selection allowed - selection will always be an empty list.\n- `Single` - only single day is selectable - selection will contain one or zero days selected.\n- `Multiple` - a list of dates can be selected.\n- `Period` - selectable period - implemented by `start` and `end` dates. - selection will contain all dates between start and the end date.\nThis implementation of SelectionState also allows for handling side-effects and vetoing the state change via `confirmSelectionChange` callback.\n\n## Week Calendar\nApart from the default calendar, there is also a week calendar, which shows a single week at a time. It can be used in the same way as the default calendar, and has the same customization options.\n\n## KotlinX DateTime\nAs the core of the library is built on `java.time` library, on Android SDK \u003c 26 it requires to use [core libary desugaring](https://developer.android.com/studio/write/java8-support) to access it's API.\nAs a result it's features may be unavailable to some project built around different date-time libraries (e.g. kotlinx-datetime). Although the project wont be migrating from `java.time`, as it's the best suited for it, there is a separate `kotlinx-datetime` artifact for those who need to use the library from a codebase based on it. It doesn't consist of a separate version of `ComposeCalendar` features, but offers a small bunch of utilities, that will enable you to create your own wrapper, as briefly presented in `KotlinDateTimeSample`. If the provided functionality, doesn't match your use-case, please submit an issue.\n\n## License\n\n    Copyright 2024 Bogusz Pawłowski\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboguszpawlowski%2FComposeCalendar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboguszpawlowski%2FComposeCalendar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboguszpawlowski%2FComposeCalendar/lists"}