feat(write): event creation — form screen, FAB, last-used calendar (v1.2)
Second slice of milestone 2 (write support): - EventForm domain model + problems() validation (end-before-start, no-calendar; blank titles and instant events stay legal) - Full-screen EventEditScreen: title, all-day switch, M3 date/time pickers (moving the start preserves the duration), calendar picker limited to writable calendars, location, description. Save validates, requests the WRITE upgrade contextually, and closes on success - Calendar preselection: explicit pick > last-used (CalendarPrefs) > first writable calendar - insertEvent in the data source; EventWriteMapper (JVM-tested) normalises all-day events to UTC midnights with exclusive DTEND, timed events to the device zone - CalendarFabColumn shared by month/week/day: persistent "+" FAB anchored on the visible day, jump-to-today pill stacked above it - Tests: EventForm validation, write-time mapping (incl. DST-safe epoch check), repository createEvent delegation/error propagation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberCalendarSlideSpec
|
||||
import de.jeanlucmakiola.calendula.ui.day.DayScreen
|
||||
import de.jeanlucmakiola.calendula.ui.detail.EventDetailScreen
|
||||
import de.jeanlucmakiola.calendula.ui.edit.EventEditScreen
|
||||
import de.jeanlucmakiola.calendula.ui.month.MonthScreen
|
||||
import de.jeanlucmakiola.calendula.ui.settings.SettingsScreen
|
||||
import de.jeanlucmakiola.calendula.ui.week.WeekScreen
|
||||
@@ -66,6 +67,15 @@ fun CalendarHost(modifier: Modifier = Modifier) {
|
||||
var showSettings by rememberSaveable { mutableStateOf(false) }
|
||||
val onOpenSettings = { showSettings = true }
|
||||
|
||||
// Event form (v1.2 create) — same held-key pattern as the detail screen:
|
||||
// [heldCreateIso] keeps the prefill date alive through the slide-out.
|
||||
var createDateIso by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
var heldCreateIso by remember { mutableStateOf<String?>(null) }
|
||||
val onCreateEvent: (LocalDate) -> Unit = { date ->
|
||||
heldCreateIso = date.toString()
|
||||
createDateIso = date.toString()
|
||||
}
|
||||
|
||||
val slideSpec = rememberCalendarSlideSpec()
|
||||
|
||||
Box(modifier = modifier.fillMaxSize()) {
|
||||
@@ -75,12 +85,14 @@ fun CalendarHost(modifier: Modifier = Modifier) {
|
||||
onSelectView = onSelectView,
|
||||
onEventClick = onEventClick,
|
||||
onOpenSettings = onOpenSettings,
|
||||
onCreateEvent = onCreateEvent,
|
||||
)
|
||||
CalendarView.Day -> DayScreen(
|
||||
selectedView = view,
|
||||
onSelectView = onSelectView,
|
||||
onEventClick = onEventClick,
|
||||
onOpenSettings = onOpenSettings,
|
||||
onCreateEvent = onCreateEvent,
|
||||
initialDateIso = pendingDayIso,
|
||||
)
|
||||
CalendarView.Month -> MonthScreen(
|
||||
@@ -88,6 +100,7 @@ fun CalendarHost(modifier: Modifier = Modifier) {
|
||||
onSelectView = onSelectView,
|
||||
onOpenDay = onOpenDay,
|
||||
onOpenSettings = onOpenSettings,
|
||||
onCreateEvent = onCreateEvent,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -108,6 +121,20 @@ fun CalendarHost(modifier: Modifier = Modifier) {
|
||||
}
|
||||
}
|
||||
|
||||
// Event form (v1.2) — full-screen destination, slides over the calendar.
|
||||
AnimatedVisibility(
|
||||
visible = createDateIso != null,
|
||||
enter = slideInHorizontally(slideSpec) { it } + fadeIn(),
|
||||
exit = slideOutHorizontally(slideSpec) { it } + fadeOut(),
|
||||
) {
|
||||
(createDateIso ?: heldCreateIso)?.let { iso ->
|
||||
EventEditScreen(
|
||||
initialDateIso = iso,
|
||||
onClose = { createDateIso = null },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Settings (M4) — full-screen destination, slides over the calendar.
|
||||
AnimatedVisibility(
|
||||
visible = showSettings,
|
||||
|
||||
Reference in New Issue
Block a user