Appearance
Android / Kotlin
Native Kotlin Core and Jetpack Compose UI, Android 6.0 (API 23) or later. Initial version: 0.1.0-alpha01, local distribution only. The source includes Calendar, resource Timeline, Tasks, Resources and Availability Picker. See the component integration guide. The local alpha has native emulator interaction checks, matching-fixture iOS/Android visual review and an independent Maven consumer build. Public hosting and store distribution are separate.
Install the package
Build packageDistribution from packages/chronosketch-kotlin/ and extract the ZIP. Add its repository directory to your Gradle settings:
kotlin
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("/path/to/extracted/repository") }
}
}Use the Kotlin Android and Compose compiler plugins (2.2.21 in the verified project), enable Compose, compileSdk 36 and Java 17 compatibility. Android consumers must enable core library desugaring for date arithmetic on API 23–25:
kotlin
android {
compileSdk = 36
defaultConfig { minSdk = 23 }
buildFeatures { compose = true }
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
implementation("com.xsigns.chronosketch:chronosketch-ui:0.1.0-alpha01")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
}UI transitively exposes Core and Compose Material 3 dependencies. For a headless JVM integration, depend only on com.xsigns.chronosketch:chronosketch-core:0.1.0-alpha01. A raw AAR alone does not carry resolved transitive dependencies; use the Maven repository with its POM and Gradle module metadata.
Display a calendar
kotlin
import androidx.compose.runtime.remember
import com.xsigns.chronosketch.core.calendar.domain.CalendarEvent
import com.xsigns.chronosketch.core.calendar.domain.CalendarEventInterval
import com.xsigns.chronosketch.core.calendar.domain.CalendarEvents
import com.xsigns.chronosketch.core.datetime.CivilDate
import com.xsigns.chronosketch.ui.calendar.CalendarModel
import com.xsigns.chronosketch.ui.calendar.CalendarView
// Inside your MaterialTheme and consumer-owned scrolling container:
val date = CivilDate(2026, 11, 3)
val model = remember {
CalendarModel(date, CalendarEvents(listOf(
CalendarEvent("workshop", "Workshop", CalendarEventInterval.AllDay(date, date.addingDays(2)))
)))
}
CalendarView(model, today = date, onEventSelected = { event ->
// Open your own native dialog or navigate to the event.
})Ownership and semantics
- Keep one
CalendarModelper component and call it on the UI thread. - The consumer owns confirmed events, persistence and today's date. Update events with
model.setEvents(CalendarEvents(newEvents)); navigation is preserved. CivilDaterepresents Gregorian years 1..9999;LocalDateTimeis floating local time, not an instant. Parsing rejects malformed or impossible dates.- All-day and timed intervals have exclusive ends. Duplicate/blank IDs and empty or reversed intervals are rejected before replacing confirmed state.
- Month uses 42 dates and rejects boundary months whose entire grid exceeds the supported years. Month navigation clamps to the destination's last day.
selectandnavigatevalidate before changing state. Programmatic changes and month arrows do not emitonDateSelected; date and Today taps do.setLanguage(CalendarLanguage.English)changes labels and week start (Sunday). German defaults to Monday. Selection and confirmed events remain unchanged.- Compose inherits MaterialTheme. The consumer owns scrolling, host navigation, saved-state restoration and native event dialogs.
Views and editing
Use model.setView(CalendarViewKind.Week) (or Month, Day, Agenda). navigatePeriod(steps) follows the selected view; navigate(months) remains explicit month navigation. Week and Day clip overnight events while selection returns the original event. Week all-day events use connected lanes. Month keeps the intentional compact iOS date grid and selected-day event list. Large text uses chronological event lists instead of crowded timed columns.
Pass onEventCreateRequested to CalendarView to enable the native Create button. The request contains an interval only; the consumer supplies identity/title and confirms with setEvents. CalendarEventEditRequest and CalendarEventMoveRequest construct validated proposals without mutating data. Edits preserve identity, title, interval kind and protection. All-day form end dates in the demo are inclusive; stored intervals remain exclusive.
Configure CalendarAvailability(constraints, preventEventOverlap) in the model or call setAvailability. checkInteraction evaluates action-specific blocks, protection buffers and optional event overlap against current confirmed events. Editing excludes the original event and its associated constraints. Consumers must recheck current data before accepting a proposal; stale edit rejection and native Android date/time pickers are demonstrated by the demo.
The demo restores confirmed events, view, selected date, language and unfinished form drafts through Activity saved state. This is not persistent storage or a public serialization format.
Supply CalendarEditHandlers(onMoveRequested = { ... }, onResizeRequested = { ... }) as CalendarView's editing argument to enable long-press movement and final-segment end resizing in Day/Week. Week all-day bars support movement with the move handler. Missing handlers disable the corresponding gesture. Timed deltas use relative 15-minute steps, preserving off-grid minutes and overnight duration. A bottom indicator identifies eligible resize segments; ordinary event activation opens the consumer form as the non-drag alternative. Releasing outside the visible grid, cancellation, stale source events and unavailable destinations emit no request. Gesture proposals do not replace confirmed data. The demo accepts valid proposals through its own current-data checks.
setAvailability(policy, validator = { request -> rejectionReasonOrNull }) can add synchronous consumer validation after built-in checks. Reject with a nonblank reason. Day/Week render clipped constraint and protection bands; full intervals remain authoritative for validation.
The optional views constructor argument and setViews select an ordered, nonempty set of enabled views. Duplicates are removed; removing the current view selects the first enabled view. setView rejects disabled views atomically.
CalendarPresentation.scrollPositions configures Day and Week independently with CurrentTime (default), Midnight, FirstEvent, or Time(minute). Initial positioning runs when the displayed date/view changes, preserving manual scrolling on event updates. showWeekNumbers enables ISO week labels.
CalendarPresentation.actions supplies CalendarEventAction(id, title, enabled, perform) values. Native action menus and accessibility actions recheck the current event and action availability before dispatch. Timed/all-day long presses without movement open actions; moving after the hold retains editing behavior. The optional eventContent composable replaces event text while the component retains gestures and semantics. Use CalendarDefaultEventContent(event, subtitle) inside your content column to retain the standard text. Custom content must remain noninteractive.
scrollToTime(minute) explicitly scrolls the current Day/Week view (0–1439) and returns false in Month/Agenda. setEventsVisible(false) hides event rendering without changing confirmed events or availability validation.
Use CompositionLocalProvider(LocalCalendarPresentation provides CalendarPresentation(...)) for per-event tint/decorative content and constraint captions (Hatched, Label, Details). The presentation also reaches a Resources component's composed calendar. Decorations must remain noninteractive; the package owns event activation and gestures.
Timeline, Tasks, Resources and Availability Picker APIs are described in component integration. Runtime, visual and interaction acceptance is tracked separately from source implementation; TalkBack and physical haptics cannot be inferred from compilation or simulator screenshots.