feat(agenda): add calendar-aligned "this week"/"this month" ranges
All checks were successful
Translations / check (pull_request) Successful in 4s
CI / ci (pull_request) Successful in 11m22s

Extend AgendaRange with calendar-aligned windows alongside the rolling
ones: ThisWeek runs through the end of the current week (respecting the
week-start preference — a Monday start means everything before next
Monday), ThisMonth through the last day of the current month. dayCount now
takes the anchor day and week-start; the agenda screen and widget resolve
the week-start preference and pass it through. Rolling options relabelled
("Today", "Next 7 days", "Next 30 days") to read distinctly from the new
calendar-aligned ones.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-27 14:25:59 +02:00
parent add88fbadf
commit 766c2ffcf8
7 changed files with 114 additions and 27 deletions

View File

@@ -1,27 +1,60 @@
package de.jeanlucmakiola.calendula.ui.agenda
import com.google.common.truth.Truth.assertThat
import kotlinx.datetime.DayOfWeek
import kotlinx.datetime.LocalDate
import org.junit.jupiter.api.Test
class AgendaRangeTest {
// A reference anchor: 2026-06-17 is a Wednesday.
private val wednesday = LocalDate(2026, 6, 17)
@Test
fun `fixed ranges have 1, 7, 30 day counts`() {
assertThat(AgendaRange.Day.dayCount()).isEqualTo(1)
assertThat(AgendaRange.Week.dayCount()).isEqualTo(7)
assertThat(AgendaRange.Month.dayCount()).isEqualTo(30)
fun `rolling ranges have fixed 1, 7, 30 day counts regardless of anchor`() {
assertThat(AgendaRange.Day.dayCount(wednesday, DayOfWeek.MONDAY)).isEqualTo(1)
assertThat(AgendaRange.Week.dayCount(wednesday, DayOfWeek.MONDAY)).isEqualTo(7)
assertThat(AgendaRange.Month.dayCount(wednesday, DayOfWeek.MONDAY)).isEqualTo(30)
}
@Test
fun `this week runs through the day before the week repeats`() {
// Mon-start week: Wed → Wed,Thu,Fri,Sat,Sun = 5 days (everything before next Monday).
assertThat(AgendaRange.ThisWeek.dayCount(wednesday, DayOfWeek.MONDAY)).isEqualTo(5)
// On the first day of the week the whole 7 days remain.
val monday = LocalDate(2026, 6, 15)
assertThat(AgendaRange.ThisWeek.dayCount(monday, DayOfWeek.MONDAY)).isEqualTo(7)
// A Sunday-start week shifts the boundary: Wed → 4 days left (through Saturday).
assertThat(AgendaRange.ThisWeek.dayCount(wednesday, DayOfWeek.SUNDAY)).isEqualTo(4)
}
@Test
fun `this month runs through the last day of the month`() {
// June has 30 days: the 17th leaves 14 days (17..30 inclusive).
assertThat(AgendaRange.ThisMonth.dayCount(wednesday, DayOfWeek.MONDAY)).isEqualTo(14)
// February 2026 (non-leap) has 28 days.
assertThat(AgendaRange.ThisMonth.dayCount(LocalDate(2026, 2, 20), DayOfWeek.MONDAY))
.isEqualTo(9)
}
@Test
fun `custom day count is clamped to bounds`() {
assertThat(AgendaRange.Custom(45).dayCount()).isEqualTo(45)
assertThat(AgendaRange.Custom(0).dayCount()).isEqualTo(AgendaRange.MIN_CUSTOM_DAYS)
assertThat(AgendaRange.Custom(9_999).dayCount()).isEqualTo(AgendaRange.MAX_CUSTOM_DAYS)
assertThat(AgendaRange.Custom(45).dayCount(wednesday, DayOfWeek.MONDAY)).isEqualTo(45)
assertThat(AgendaRange.Custom(0).dayCount(wednesday, DayOfWeek.MONDAY))
.isEqualTo(AgendaRange.MIN_CUSTOM_DAYS)
assertThat(AgendaRange.Custom(9_999).dayCount(wednesday, DayOfWeek.MONDAY))
.isEqualTo(AgendaRange.MAX_CUSTOM_DAYS)
}
@Test
fun `fixed ranges round-trip through storage`() {
listOf(AgendaRange.Day, AgendaRange.Week, AgendaRange.Month).forEach { range ->
listOf(
AgendaRange.Day,
AgendaRange.Week,
AgendaRange.Month,
AgendaRange.ThisWeek,
AgendaRange.ThisMonth,
).forEach { range ->
assertThat(parseAgendaRange(range.storageValue(), default = AgendaRange.Day))
.isEqualTo(range)
}