feat(agenda): anchor today with an empty-day card (#35)

Add an "Always show today" setting (Settings → Agenda, on by default) that
keeps today as the first entry in both the Agenda screen and its home-screen
widget even once nothing is left today. Under today's normal header a small
"No more events today" card appears — the coffee-cup empty-state motif in the
app, a rounded surface in the widget — so the first rows you see are clearly
today's rather than a future day's.

The anchor is a pure, JVM-tested helper (anchorTodayIfMissing) applied after
past-event filtering; in-app it only kicks in when the window starts on today,
never on a jumped-to date. The widget reads the pref reactively via per-instance
Glance state, mirroring the range/past-event settings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 18:39:27 +02:00
parent 1b731a4ab0
commit b9329f6fb6
12 changed files with 290 additions and 30 deletions

View File

@@ -0,0 +1,39 @@
package de.jeanlucmakiola.calendula.ui.agenda
import com.google.common.truth.Truth.assertThat
import kotlinx.datetime.LocalDate
import org.junit.jupiter.api.Test
/** Covers the agenda widget's "always show today" anchor logic (#35). */
class AnchorTodayTest {
private val today = LocalDate(2026, 6, 17)
private val tomorrow = LocalDate(2026, 6, 18)
@Test
fun `disabled leaves the days untouched even when today is absent`() {
val days = listOf(AgendaDay(tomorrow, emptyList()))
assertThat(anchorTodayIfMissing(days, today, enabled = false)).isEqualTo(days)
}
@Test
fun `enabled prepends an empty today when it is missing`() {
val days = listOf(AgendaDay(tomorrow, emptyList()))
val result = anchorTodayIfMissing(days, today, enabled = true)
assertThat(result).hasSize(2)
assertThat(result.first()).isEqualTo(AgendaDay(today, emptyList()))
assertThat(result[1]).isEqualTo(days.first())
}
@Test
fun `enabled anchors today into an otherwise empty list`() {
val result = anchorTodayIfMissing(emptyList(), today, enabled = true)
assertThat(result).containsExactly(AgendaDay(today, emptyList()))
}
@Test
fun `enabled is a no-op when today already has its own day`() {
val days = listOf(AgendaDay(today, emptyList()), AgendaDay(tomorrow, emptyList()))
assertThat(anchorTodayIfMissing(days, today, enabled = true)).isEqualTo(days)
}
}