From 596f76bbaabdc6fbbb17b911b865356e6c54bb01 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Fri, 25 Sep 2026 20:56:16 +0200 Subject: [PATCH] Open split day list from Pages month style (#111) --- CHANGELOG.md | 3 ++ .../calendula/ui/month/MonthScreen.kt | 46 +++++++++++++------ app/src/main/res/values/strings.xml | 2 +- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0408cf5..6edaba5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- **Pages can open the split agenda.** Swipe up from a full month to reveal the compact grid and month agenda; tap a day to filter it, then swipe down to return. The transition gives haptic feedback ([#111]). + ### Changed - **Split view opens with the month's agenda.** It starts at today in the current month; tapping a day filters the list, and the filter chip restores the full month. Swiping the list moves by day when filtered and by month otherwise ([#142]). diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/month/MonthScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/month/MonthScreen.kt index d2e52e6..b28207a 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/month/MonthScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/month/MonthScreen.kt @@ -135,6 +135,8 @@ import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics @@ -332,6 +334,9 @@ fun MonthScreen( } val isOnCurrentMonth = titleMonth == YearMonth(today.year, today.month) + var splitExpanded by rememberSaveable(viewStyle) { + mutableStateOf(viewStyle == MonthViewStyle.Paged) + } // Continuous names the month on the block's own sticky header, so the bar // carries the year instead of repeating it two lines further down. Dense has @@ -433,7 +438,8 @@ fun MonthScreen( // today when its month is shown, else the 1st. onCreateEvent( when { - viewStyle == MonthViewStyle.Split -> selectedDate + (viewStyle == MonthViewStyle.Split || + (viewStyle == MonthViewStyle.Paged && !splitExpanded)) -> selectedDate ?: if (isOnCurrentMonth) today else LocalDate(titleMonth.year, titleMonth.month, 1) isOnCurrentMonth -> today else -> LocalDate(titleMonth.year, titleMonth.month, 1) @@ -471,10 +477,13 @@ fun MonthScreen( onOpenDay = onOpenDay, onEventClick = onEventClick, ) - } else if (viewStyle == MonthViewStyle.Split) { + } else if (viewStyle == MonthViewStyle.Split || viewStyle == MonthViewStyle.Paged) { SplitMonthContent( state = state, selected = selectedDate, + initiallyExpanded = viewStyle == MonthViewStyle.Paged, + expanded = splitExpanded, + onExpandedChange = { splitExpanded = it }, pagerState = pagerState, weekStart = weekStart, monthState = viewModel::month, @@ -1303,6 +1312,9 @@ private val MONTH_EXPAND_THRESHOLD = 48.dp private fun SplitMonthContent( state: MonthUiState, selected: LocalDate?, + initiallyExpanded: Boolean, + expanded: Boolean, + onExpandedChange: (Boolean) -> Unit, pagerState: PagerState, weekStart: DayOfWeek, monthState: (YearMonth, DayOfWeek) -> StateFlow, @@ -1318,15 +1330,23 @@ private fun SplitMonthContent( ) { val fadeSpec = rememberCalendarFadeSpec() val reduceMotion = rememberReduceMotion() - var expanded by rememberSaveable { mutableStateOf(false) } - // Back collapses before it does anything else. Expanding replaces the whole - // screen, so it is a place you can be, and every other place in the app can - // be backed out of. Declared deeper than CalendarHost's view-stack handler, - // which is what makes it win while it is enabled. - BackHandler(enabled = expanded) { expanded = false } + val haptics = LocalHapticFeedback.current + BackHandler(enabled = expanded != initiallyExpanded) { + onExpandedChange(initiallyExpanded) + } val expandDrag = rememberSplitExpandDrag( - onExpand = { expanded = true }, - onCollapse = { expanded = false }, + onExpand = { + if (!expanded) { + onExpandedChange(true) + haptics.performHapticFeedback(HapticFeedbackType.SegmentTick) + } + }, + onCollapse = { + if (expanded) { + onExpandedChange(false) + haptics.performHapticFeedback(HapticFeedbackType.SegmentTick) + } + }, ) when (state) { @@ -1369,13 +1389,13 @@ private fun SplitMonthContent( // the day you picked. onPickDay = { onSelectDay(it) - expanded = false + onExpandedChange(false) }, // A tapped chip is asking for that event, not for its // day, so it opens the detail from here too rather // than collapsing (#187). onEventClick = onEventClick, - onCollapse = { expanded = false }, + onCollapse = { onExpandedChange(false) }, ) } else { SplitMonthCollapsed( @@ -1391,7 +1411,7 @@ private fun SplitMonthContent( onOpenDay = onOpenDay, onEventClick = onEventClick, onCreateEvent = onCreateEvent, - onExpand = { expanded = true }, + onExpand = { onExpandedChange(true) }, ) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4099239..63e0484 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -551,7 +551,7 @@ Month view Month view style Pages - One month fills the screen. Swipe left or right to change month. + One month fills the screen. Swipe left or right to change month, or swipe up to show the month agenda. Scrolling months Each month sits under its own heading, with a little space setting it apart from the next. Seamless weeks