From 00b34e31fb2009d6a6a2aae2feff95820a5da920 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Fri, 31 Jul 2026 20:56:13 +0200 Subject: [PATCH] Open the date picker by tapping the top-bar title (#57) (#124) Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/124 --- CHANGELOG.md | 5 ++ .../ui/common/CalendarTitleButton.kt | 81 +++++++++++++++++++ .../calendula/ui/day/DayScreen.kt | 10 ++- .../calendula/ui/month/MonthScreen.kt | 12 ++- .../calendula/ui/week/WeekScreen.kt | 10 ++- 5 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarTitleButton.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index a30994c..59d4562 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 duplicate — keeps that length. All-day events are unaffected ([#54]). ### Changed +- The date in the top bar is now the way to jump: tapping the month, week or day + title opens the same date picker the sidebar's **Jump to date** offers, seeded + on whatever the bar is naming. A drop-down caret marks it as tappable. The + sidebar entry stays where it is ([#57]). - A reminder in the status bar is now Calendula's own mark — the calendar with the bloom — instead of the generic calendar glyph it shared with the system's date surfaces and every other calendar app. The status bar draws that icon as @@ -1272,3 +1276,4 @@ automatically, with zero telemetry and no internet permission. [#103]: https://codeberg.org/jlmakiola/calendula/issues/103 [#69]: https://codeberg.org/jlmakiola/calendula/issues/69 [#54]: https://codeberg.org/jlmakiola/calendula/issues/54 +[#57]: https://codeberg.org/jlmakiola/calendula/issues/57 diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarTitleButton.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarTitleButton.kt new file mode 100644 index 0000000..4857aa0 --- /dev/null +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarTitleButton.kt @@ -0,0 +1,81 @@ +package de.jeanlucmakiola.calendula.ui.common + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.dp +import de.jeanlucmakiola.calendula.R +import kotlinx.datetime.LocalDate + +/** + * Top-bar title that doubles as the jump-to-date entry point: the formatted + * [title] with a drop-down caret, opening the same [CalendarDatePickerDialog] the + * drawer uses and reporting the chosen day through [onJumpToDate]. + * + * [currentDate] seeds the picker with whatever the bar is currently naming (the + * visible day, week start or month anchor). + * + * The row keeps its own 8.dp inset rather than shifting back onto the app bar's + * start alignment: M3 places the title flush against the navigation icon's + * trailing edge, and the title is hit-tested on top of it, so a negative offset + * would swallow taps meant for the menu button. + */ +@Composable +fun CalendarTitleButton( + title: String, + currentDate: LocalDate, + onJumpToDate: (LocalDate) -> Unit, + modifier: Modifier = Modifier, +) { + var showDatePicker by rememberSaveable { mutableStateOf(false) } + + Row( + modifier = modifier + .heightIn(min = 48.dp) + .clip(MaterialTheme.shapes.large) + .clickable( + onClickLabel = stringResource(R.string.drawer_jump_to_date), + role = Role.Button, + ) { showDatePicker = true } + .padding(horizontal = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = title, + style = MaterialTheme.typography.titleLarge, + modifier = Modifier.weight(1f, fill = false), + ) + Icon( + imageVector = Icons.Default.ArrowDropDown, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + + if (showDatePicker) { + CalendarDatePickerDialog( + initial = currentDate, + onConfirm = { + showDatePicker = false + onJumpToDate(it) + }, + onDismiss = { showDatePicker = false }, + ) + } +} diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/day/DayScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/day/DayScreen.kt index 842486e..320997d 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/day/DayScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/day/DayScreen.kt @@ -68,6 +68,7 @@ import de.jeanlucmakiola.calendula.R import de.jeanlucmakiola.calendula.domain.EventInstance import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer +import de.jeanlucmakiola.calendula.ui.common.CalendarTitleButton import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn import de.jeanlucmakiola.calendula.ui.common.TodayAction import de.jeanlucmakiola.calendula.ui.common.CalendarFailure @@ -221,6 +222,7 @@ fun DayScreen( onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) }, onOpenDrawer = { scope.launch { drawerState.open() } }, onOpenSearch = onOpenSearch, + onJumpToDate = jumpToDate, showTodayButton = todayInToolbar, onToday = jumpToToday, scrollBehavior = scrollBehavior, @@ -364,6 +366,7 @@ private fun DayTopBar( onCycleView: () -> Unit, onOpenDrawer: () -> Unit, onOpenSearch: () -> Unit, + onJumpToDate: (LocalDate) -> Unit, showTodayButton: Boolean, onToday: () -> Unit, scrollBehavior: androidx.compose.material3.TopAppBarScrollBehavior, @@ -371,9 +374,10 @@ private fun DayTopBar( val locale = currentLocale() TopAppBar( title = { - Text( - text = formatDayTitle(date, locale, currentYear), - style = MaterialTheme.typography.titleLarge, + CalendarTitleButton( + title = formatDayTitle(date, locale, currentYear), + currentDate = date, + onJumpToDate = onJumpToDate, ) }, navigationIcon = { 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 c6ca86c..fc7202e 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 @@ -101,6 +101,7 @@ import de.jeanlucmakiola.calendula.ui.agenda.AgendaEmptyDayRow import de.jeanlucmakiola.calendula.ui.agenda.AgendaEventRow import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer +import de.jeanlucmakiola.calendula.ui.common.CalendarTitleButton import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn import de.jeanlucmakiola.calendula.ui.common.TodayAction import de.jeanlucmakiola.calendula.ui.common.CalendarFailure @@ -350,10 +351,12 @@ fun MonthScreen( topBar = { MonthTopBar( title = topBarTitle, + titleDate = LocalDate(titleMonth.year, titleMonth.month, 1), selectedView = selectedView, onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) }, onOpenDrawer = { scope.launch { drawerState.open() } }, onOpenSearch = onOpenSearch, + onJumpToDate = jumpToDate, showTodayButton = todayInToolbar, onToday = jumpToToday, scrollBehavior = scrollBehavior, @@ -509,19 +512,22 @@ private fun ContinuousMonthContent( @Composable private fun MonthTopBar( title: String, + titleDate: LocalDate, selectedView: CalendarView, onCycleView: () -> Unit, onOpenDrawer: () -> Unit, onOpenSearch: () -> Unit, + onJumpToDate: (LocalDate) -> Unit, showTodayButton: Boolean, onToday: () -> Unit, scrollBehavior: androidx.compose.material3.TopAppBarScrollBehavior, ) { TopAppBar( title = { - Text( - text = title, - style = MaterialTheme.typography.titleLarge, + CalendarTitleButton( + title = title, + currentDate = titleDate, + onJumpToDate = onJumpToDate, ) }, navigationIcon = { diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/week/WeekScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/week/WeekScreen.kt index ea5243c..2121582 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/week/WeekScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/week/WeekScreen.kt @@ -77,6 +77,7 @@ import de.jeanlucmakiola.calendula.domain.EventInstance import de.jeanlucmakiola.calendula.domain.hasEnded import de.jeanlucmakiola.calendula.ui.common.formatCalendarTitle import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer +import de.jeanlucmakiola.calendula.ui.common.CalendarTitleButton import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn import de.jeanlucmakiola.calendula.ui.common.TodayAction import de.jeanlucmakiola.calendula.ui.common.CalendarFailure @@ -242,6 +243,7 @@ fun WeekScreen( onCycleView = { onSelectView(selectedView.next(quickSwitchViews)) }, onOpenDrawer = { scope.launch { drawerState.open() } }, onOpenSearch = onOpenSearch, + onJumpToDate = jumpToDate, showTodayButton = todayInToolbar, onToday = jumpToToday, scrollBehavior = scrollBehavior, @@ -397,6 +399,7 @@ private fun WeekTopBar( onCycleView: () -> Unit, onOpenDrawer: () -> Unit, onOpenSearch: () -> Unit, + onJumpToDate: (LocalDate) -> Unit, showTodayButton: Boolean, onToday: () -> Unit, scrollBehavior: androidx.compose.material3.TopAppBarScrollBehavior, @@ -404,9 +407,10 @@ private fun WeekTopBar( val locale = currentLocale() TopAppBar( title = { - Text( - text = formatWeekTitle(weekStart, locale, currentYear), - style = MaterialTheme.typography.titleLarge, + CalendarTitleButton( + title = formatWeekTitle(weekStart, locale, currentYear), + currentDate = weekStart, + onJumpToDate = onJumpToDate, ) }, navigationIcon = {