feat(agenda): spell out multi-day time line instead of arrows

The "→" arrow convention read as unclear. Spell each day out instead:
the first day names the start ("Starts 14:00"), the last day the end
("Ends 10:00"), and whole days in between read as "All day". All-day
multi-day events stay "All day" on every day. Single-day rows unchanged.

Adds agenda_span_starts / agenda_span_ends (owes Weblate backfill).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-19 11:42:15 +02:00
parent 3feafe38f2
commit b5c2930609
2 changed files with 13 additions and 16 deletions

View File

@@ -562,11 +562,10 @@ private fun agendaDayLabel(date: LocalDate, today: LocalDate): String {
/** /**
* Time line under the title: "09:00 10:00 · Location", "All day", etc. * Time line under the title: "09:00 10:00 · Location", "All day", etc.
* *
* A multi-day event shows only the part relevant to [day], with a "→" marking * A multi-day event shows only the part relevant to [day], spelled out so each
* that it carries past this day's boundary: its first day shows the start * day reads on its own: its first day names the start ("Starts 14:00"), its last
* ("14:00 →"), its last day the end (" 10:00"), and any whole day in between * day the end ("Ends 10:00"), and any whole day in between reads as "All day".
* reads as an all-day span arriving from and continuing into its neighbours * An all-day multi-day event is simply "All day" on every day it covers.
* ("→ All day →").
*/ */
@Composable @Composable
private fun agendaTimeSummary(event: EventInstance, day: LocalDate): String { private fun agendaTimeSummary(event: EventInstance, day: LocalDate): String {
@@ -575,18 +574,13 @@ private fun agendaTimeSummary(event: EventInstance, day: LocalDate): String {
val locale = currentLocale() val locale = currentLocale()
val time = if (event.spansMultipleDays(zone)) { val time = if (event.spansMultipleDays(zone)) {
val continuesBefore = day > event.spanFirstDay(zone) val isFirstDay = day <= event.spanFirstDay(zone)
val continuesAfter = day < event.spanLastDay(zone) val isLastDay = day >= event.spanLastDay(zone)
val core = when { when {
event.isAllDay -> allDayLabel event.isAllDay -> allDayLabel
!continuesBefore -> formatTime(event.start, is24Hour, locale) // the first day isFirstDay -> stringResource(R.string.agenda_span_starts, formatTime(event.start, is24Hour, locale))
!continuesAfter -> formatTime(event.end, is24Hour, locale) // the last day isLastDay -> stringResource(R.string.agenda_span_ends, formatTime(event.end, is24Hour, locale))
else -> allDayLabel // a full middle day else -> allDayLabel // a full middle day
}
buildString {
if (continuesBefore) append("")
append(core)
if (continuesAfter) append("")
} }
} else if (event.isAllDay) { } else if (event.isAllDay) {
allDayLabel allDayLabel

View File

@@ -257,6 +257,9 @@
<string name="agenda_header_tomorrow">Tomorrow</string> <string name="agenda_header_tomorrow">Tomorrow</string>
<string name="agenda_empty_title">You\'re all caught up</string> <string name="agenda_empty_title">You\'re all caught up</string>
<string name="agenda_no_more_today">No more events today</string> <string name="agenda_no_more_today">No more events today</string>
<!-- Time line for a multi-day event, on its first / last day (%1$s is a time, e.g. "14:00"). -->
<string name="agenda_span_starts">Starts %1$s</string>
<string name="agenda_span_ends">Ends %1$s</string>
<!-- Event search --> <!-- Event search -->
<string name="search_action">Search</string> <string name="search_action">Search</string>