Merge relative all-day reminder dates (#308)
This commit is contained in:
@@ -88,6 +88,7 @@ class ReminderNotifier @Inject constructor(
|
|||||||
is24Hour = is24Hour,
|
is24Hour = is24Hour,
|
||||||
today = Instant.now().atZone(zone).toLocalDate(),
|
today = Instant.now().atZone(zone).toLocalDate(),
|
||||||
firstDayOfWeek = firstDayOfWeek,
|
firstDayOfWeek = firstDayOfWeek,
|
||||||
|
todayLabel = context.getString(R.string.reminder_day_today),
|
||||||
tomorrowLabel = context.getString(R.string.reminder_day_tomorrow),
|
tomorrowLabel = context.getString(R.string.reminder_day_tomorrow),
|
||||||
yesterdayLabel = context.getString(R.string.reminder_day_yesterday),
|
yesterdayLabel = context.getString(R.string.reminder_day_yesterday),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ import java.util.Locale
|
|||||||
* alone would be ambiguous)
|
* alone would be ambiguous)
|
||||||
* - timed, crossing days: "11 Jun, 23:30 – 12 Jun, 00:30" (medium date + short time,
|
* - timed, crossing days: "11 Jun, 23:30 – 12 Jun, 00:30" (medium date + short time,
|
||||||
* already unambiguous)
|
* already unambiguous)
|
||||||
* - all-day, one day: "11 Jun 2026"
|
* - all-day, one day: "Tomorrow" / "Thu" / "11 Jun 2026" (same relative rules,
|
||||||
* - all-day, multi-day: "11 Jun 2026 – 12 Jun 2026"
|
* plus [todayLabel] — no time range to lean on)
|
||||||
|
* - all-day, multi-day: "Tomorrow – 12 Jun 2026" (relative start, explicit end)
|
||||||
*
|
*
|
||||||
* All-day instances already carry an explicit date, so they never gain a
|
* All-day instances store UTC midnights with an exclusive end, so they are read
|
||||||
* relative prefix. They store UTC midnights with an exclusive end, so they are
|
* in UTC and the end day is the last *covered* day (issue #308).
|
||||||
* read in UTC and the end day is the last *covered* day.
|
|
||||||
*/
|
*/
|
||||||
fun reminderTimeText(
|
fun reminderTimeText(
|
||||||
beginMillis: Long,
|
beginMillis: Long,
|
||||||
@@ -43,6 +43,7 @@ fun reminderTimeText(
|
|||||||
is24Hour: Boolean,
|
is24Hour: Boolean,
|
||||||
today: LocalDate,
|
today: LocalDate,
|
||||||
firstDayOfWeek: DayOfWeek,
|
firstDayOfWeek: DayOfWeek,
|
||||||
|
todayLabel: String,
|
||||||
tomorrowLabel: String,
|
tomorrowLabel: String,
|
||||||
yesterdayLabel: String,
|
yesterdayLabel: String,
|
||||||
): String {
|
): String {
|
||||||
@@ -53,11 +54,16 @@ fun reminderTimeText(
|
|||||||
val lastDay = Instant.ofEpochMilli(endMillis).atZone(ZoneOffset.UTC).toLocalDate()
|
val lastDay = Instant.ofEpochMilli(endMillis).atZone(ZoneOffset.UTC).toLocalDate()
|
||||||
.minusDays(1)
|
.minusDays(1)
|
||||||
.coerceAtLeast(firstDay)
|
.coerceAtLeast(firstDay)
|
||||||
return if (lastDay == firstDay) {
|
val start = relativeDayPrefix(
|
||||||
dateFormat.format(firstDay)
|
day = firstDay,
|
||||||
} else {
|
today = today,
|
||||||
dateFormat.format(firstDay) + RANGE + dateFormat.format(lastDay)
|
firstDayOfWeek = firstDayOfWeek,
|
||||||
}
|
locale = locale,
|
||||||
|
dateFormat = dateFormat,
|
||||||
|
tomorrowLabel = tomorrowLabel,
|
||||||
|
yesterdayLabel = yesterdayLabel,
|
||||||
|
) ?: todayLabel
|
||||||
|
return if (lastDay == firstDay) start else start + RANGE + dateFormat.format(lastDay)
|
||||||
}
|
}
|
||||||
|
|
||||||
val timeFormat = timeOfDayFormatter(is24Hour, locale)
|
val timeFormat = timeOfDayFormatter(is24Hour, locale)
|
||||||
|
|||||||
@@ -353,6 +353,7 @@
|
|||||||
<string name="reminder_action_snooze">Snooze</string>
|
<string name="reminder_action_snooze">Snooze</string>
|
||||||
<string name="reminder_action_dismiss">Dismiss</string>
|
<string name="reminder_action_dismiss">Dismiss</string>
|
||||||
<!-- Day context prefix in a reminder for an event on another day (v2.15.0) -->
|
<!-- Day context prefix in a reminder for an event on another day (v2.15.0) -->
|
||||||
|
<string name="reminder_day_today">Today</string>
|
||||||
<string name="reminder_day_tomorrow">Tomorrow</string>
|
<string name="reminder_day_tomorrow">Tomorrow</string>
|
||||||
<string name="reminder_day_yesterday">Yesterday</string>
|
<string name="reminder_day_yesterday">Yesterday</string>
|
||||||
|
|
||||||
|
|||||||
+47
-10
@@ -38,6 +38,7 @@ class ReminderTimeTextTest {
|
|||||||
is24Hour = is24Hour,
|
is24Hour = is24Hour,
|
||||||
today = today ?: java.time.Instant.ofEpochMilli(beginMillis).atZone(zone).toLocalDate(),
|
today = today ?: java.time.Instant.ofEpochMilli(beginMillis).atZone(zone).toLocalDate(),
|
||||||
firstDayOfWeek = firstDayOfWeek,
|
firstDayOfWeek = firstDayOfWeek,
|
||||||
|
todayLabel = "Today",
|
||||||
tomorrowLabel = "Tomorrow",
|
tomorrowLabel = "Tomorrow",
|
||||||
yesterdayLabel = "Yesterday",
|
yesterdayLabel = "Yesterday",
|
||||||
)
|
)
|
||||||
@@ -130,38 +131,74 @@ class ReminderTimeTextTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `all-day single day shows one date, read in UTC`() {
|
fun `all-day single day today reads as today, read in UTC`() {
|
||||||
val text = text(
|
val text = text(
|
||||||
beginMillis = utcMidnight(LocalDate.of(2026, 6, 11)),
|
beginMillis = utcMidnight(LocalDate.of(2026, 6, 11)),
|
||||||
endMillis = utcMidnight(LocalDate.of(2026, 6, 12)),
|
endMillis = utcMidnight(LocalDate.of(2026, 6, 12)),
|
||||||
isAllDay = true,
|
isAllDay = true,
|
||||||
// Zone must not matter for all-day events: UTC midnight is
|
// Zone must not matter for all-day events: UTC midnight is
|
||||||
// 02:00 in Berlin — naive local reading would shift the day.
|
// the previous evening in Los Angeles — naive local reading would shift the day.
|
||||||
|
zone = ZoneId.of("America/Los_Angeles"),
|
||||||
today = LocalDate.of(2026, 6, 11),
|
today = LocalDate.of(2026, 6, 11),
|
||||||
)
|
)
|
||||||
assertThat(text).isEqualTo("11.06.2026")
|
assertThat(text).isEqualTo("Today")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `all-day event tomorrow still shows the exact date, no relative prefix`() {
|
fun `all-day event tomorrow reads as tomorrow`() {
|
||||||
val text = text(
|
val text = text(
|
||||||
beginMillis = utcMidnight(LocalDate.of(2026, 6, 12)),
|
beginMillis = utcMidnight(LocalDate.of(2026, 6, 12)),
|
||||||
endMillis = utcMidnight(LocalDate.of(2026, 6, 13)),
|
endMillis = utcMidnight(LocalDate.of(2026, 6, 13)),
|
||||||
isAllDay = true,
|
isAllDay = true,
|
||||||
today = LocalDate.of(2026, 6, 11),
|
today = LocalDate.of(2026, 6, 11),
|
||||||
)
|
)
|
||||||
assertThat(text).isEqualTo("12.06.2026")
|
assertThat(text).isEqualTo("Tomorrow")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `all-day multi-day shows the last covered day, not the exclusive end`() {
|
fun `all-day event later this week reads as the short weekday`() {
|
||||||
|
// 2026-06-11 is a Thursday; Saturday the 13th shares its week.
|
||||||
val text = text(
|
val text = text(
|
||||||
beginMillis = utcMidnight(LocalDate.of(2026, 6, 11)),
|
beginMillis = utcMidnight(LocalDate.of(2026, 6, 13)),
|
||||||
endMillis = utcMidnight(LocalDate.of(2026, 6, 13)),
|
endMillis = utcMidnight(LocalDate.of(2026, 6, 14)),
|
||||||
|
isAllDay = true,
|
||||||
|
locale = Locale.US,
|
||||||
|
today = LocalDate.of(2026, 6, 11),
|
||||||
|
)
|
||||||
|
assertThat(text).isEqualTo("Sat")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `all-day event next week falls back to the exact date`() {
|
||||||
|
val text = text(
|
||||||
|
beginMillis = utcMidnight(LocalDate.of(2026, 6, 16)),
|
||||||
|
endMillis = utcMidnight(LocalDate.of(2026, 6, 17)),
|
||||||
isAllDay = true,
|
isAllDay = true,
|
||||||
today = LocalDate.of(2026, 6, 11),
|
today = LocalDate.of(2026, 6, 11),
|
||||||
)
|
)
|
||||||
assertThat(text).isEqualTo("11.06.2026 – 12.06.2026")
|
assertThat(text).isEqualTo("16.06.2026")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `all-day multi-day reads relative start and the last covered day`() {
|
||||||
|
val text = text(
|
||||||
|
beginMillis = utcMidnight(LocalDate.of(2026, 6, 12)),
|
||||||
|
endMillis = utcMidnight(LocalDate.of(2026, 6, 14)),
|
||||||
|
isAllDay = true,
|
||||||
|
today = LocalDate.of(2026, 6, 11),
|
||||||
|
)
|
||||||
|
assertThat(text).isEqualTo("Tomorrow – 13.06.2026")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `all-day multi-day further out keeps both dates`() {
|
||||||
|
val text = text(
|
||||||
|
beginMillis = utcMidnight(LocalDate.of(2026, 7, 1)),
|
||||||
|
endMillis = utcMidnight(LocalDate.of(2026, 7, 3)),
|
||||||
|
isAllDay = true,
|
||||||
|
today = LocalDate.of(2026, 6, 11),
|
||||||
|
)
|
||||||
|
assertThat(text).isEqualTo("01.07.2026 – 02.07.2026")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -173,6 +210,6 @@ class ReminderTimeTextTest {
|
|||||||
isAllDay = true,
|
isAllDay = true,
|
||||||
today = LocalDate.of(2026, 6, 11),
|
today = LocalDate.of(2026, 6, 11),
|
||||||
)
|
)
|
||||||
assertThat(text).isEqualTo("11.06.2026")
|
assertThat(text).isEqualTo("Today")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user