Merge split day list in Pages month view (#111)

This commit is contained in:
Jean-Luc Makiola
2026-09-30 13:16:27 +02:00
3 changed files with 37 additions and 14 deletions
+3
View File
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [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 ### 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]). - **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]).
@@ -135,6 +135,8 @@ import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity 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.res.stringResource
import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
@@ -332,6 +334,9 @@ fun MonthScreen(
} }
val isOnCurrentMonth = titleMonth == YearMonth(today.year, today.month) 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 // 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 // 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. // today when its month is shown, else the 1st.
onCreateEvent( onCreateEvent(
when { when {
viewStyle == MonthViewStyle.Split -> selectedDate (viewStyle == MonthViewStyle.Split ||
(viewStyle == MonthViewStyle.Paged && !splitExpanded)) -> selectedDate
?: if (isOnCurrentMonth) today else LocalDate(titleMonth.year, titleMonth.month, 1) ?: if (isOnCurrentMonth) today else LocalDate(titleMonth.year, titleMonth.month, 1)
isOnCurrentMonth -> today isOnCurrentMonth -> today
else -> LocalDate(titleMonth.year, titleMonth.month, 1) else -> LocalDate(titleMonth.year, titleMonth.month, 1)
@@ -471,10 +477,13 @@ fun MonthScreen(
onOpenDay = onOpenDay, onOpenDay = onOpenDay,
onEventClick = onEventClick, onEventClick = onEventClick,
) )
} else if (viewStyle == MonthViewStyle.Split) { } else if (viewStyle == MonthViewStyle.Split || viewStyle == MonthViewStyle.Paged) {
SplitMonthContent( SplitMonthContent(
state = state, state = state,
selected = selectedDate, selected = selectedDate,
initiallyExpanded = viewStyle == MonthViewStyle.Paged,
expanded = splitExpanded,
onExpandedChange = { splitExpanded = it },
pagerState = pagerState, pagerState = pagerState,
weekStart = weekStart, weekStart = weekStart,
monthState = viewModel::month, monthState = viewModel::month,
@@ -1303,6 +1312,9 @@ private val MONTH_EXPAND_THRESHOLD = 48.dp
private fun SplitMonthContent( private fun SplitMonthContent(
state: MonthUiState, state: MonthUiState,
selected: LocalDate?, selected: LocalDate?,
initiallyExpanded: Boolean,
expanded: Boolean,
onExpandedChange: (Boolean) -> Unit,
pagerState: PagerState, pagerState: PagerState,
weekStart: DayOfWeek, weekStart: DayOfWeek,
monthState: (YearMonth, DayOfWeek) -> StateFlow<MonthUiState>, monthState: (YearMonth, DayOfWeek) -> StateFlow<MonthUiState>,
@@ -1318,15 +1330,23 @@ private fun SplitMonthContent(
) { ) {
val fadeSpec = rememberCalendarFadeSpec() val fadeSpec = rememberCalendarFadeSpec()
val reduceMotion = rememberReduceMotion() val reduceMotion = rememberReduceMotion()
var expanded by rememberSaveable { mutableStateOf(false) } val haptics = LocalHapticFeedback.current
// Back collapses before it does anything else. Expanding replaces the whole BackHandler(enabled = expanded != initiallyExpanded) {
// screen, so it is a place you can be, and every other place in the app can onExpandedChange(initiallyExpanded)
// 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 expandDrag = rememberSplitExpandDrag( val expandDrag = rememberSplitExpandDrag(
onExpand = { expanded = true }, onExpand = {
onCollapse = { expanded = false }, if (!expanded) {
onExpandedChange(true)
haptics.performHapticFeedback(HapticFeedbackType.SegmentTick)
}
},
onCollapse = {
if (expanded) {
onExpandedChange(false)
haptics.performHapticFeedback(HapticFeedbackType.SegmentTick)
}
},
) )
when (state) { when (state) {
@@ -1369,13 +1389,13 @@ private fun SplitMonthContent(
// the day you picked. // the day you picked.
onPickDay = { onPickDay = {
onSelectDay(it) onSelectDay(it)
expanded = false onExpandedChange(false)
}, },
// A tapped chip is asking for that event, not for its // A tapped chip is asking for that event, not for its
// day, so it opens the detail from here too rather // day, so it opens the detail from here too rather
// than collapsing (#187). // than collapsing (#187).
onEventClick = onEventClick, onEventClick = onEventClick,
onCollapse = { expanded = false }, onCollapse = { onExpandedChange(false) },
) )
} else { } else {
SplitMonthCollapsed( SplitMonthCollapsed(
@@ -1391,7 +1411,7 @@ private fun SplitMonthContent(
onOpenDay = onOpenDay, onOpenDay = onOpenDay,
onEventClick = onEventClick, onEventClick = onEventClick,
onCreateEvent = onCreateEvent, onCreateEvent = onCreateEvent,
onExpand = { expanded = true }, onExpand = { onExpandedChange(true) },
) )
} }
} }
+1 -1
View File
@@ -551,7 +551,7 @@
<string name="settings_month_header">Month view</string> <string name="settings_month_header">Month view</string>
<string name="settings_month_view_style">Month view style</string> <string name="settings_month_view_style">Month view style</string>
<string name="month_style_paged">Pages</string> <string name="month_style_paged">Pages</string>
<string name="month_style_paged_summary">One month fills the screen. Swipe left or right to change month.</string> <string name="month_style_paged_summary">One month fills the screen. Swipe left or right to change month, or swipe up to show the month agenda.</string>
<string name="month_style_continuous">Scrolling months</string> <string name="month_style_continuous">Scrolling months</string>
<string name="month_style_continuous_summary">Each month sits under its own heading, with a little space setting it apart from the next.</string> <string name="month_style_continuous_summary">Each month sits under its own heading, with a little space setting it apart from the next.</string>
<string name="month_style_dense">Seamless weeks</string> <string name="month_style_dense">Seamless weeks</string>