release: v2.13.1 — recurring-event open fix, 24h time picker, INSERT intent #60

Merged
makiolaj merged 6 commits from release/v2.13.1 into main 2026-07-06 15:36:43 +00:00
2 changed files with 13 additions and 9 deletions
Showing only changes of commit 76846420a2 - Show all commits

View File

@@ -37,16 +37,15 @@ internal fun ColumnReader.toEventDetailCore(
// Recurring events store DURATION instead of DTEND, so the series row's
// DTEND is null. Keep the event (end == begin); callers that opened a
// specific occurrence supply the real per-occurrence times from
// CalendarContract.Instances. Only a present-but-backwards DTEND is malformed.
// CalendarContract.Instances. A present-but-backwards DTEND is malformed,
// but dropping the row would make the event un-openable — the same trap as
// the pre-1970 DTSTART bug above (issue #34): it would surface as the
// generic error screen with no way to open the event and fix it. Clamp to a
// zero-length event instead (matching SearchMapper's coerceAtLeast).
val end = if (isNull(EventDetailProjection.IDX_DTEND)) {
begin
} else {
val rawEnd = getLong(EventDetailProjection.IDX_DTEND)
if (rawEnd < begin) {
Log.w(TAG, "Dropping event with dtend=$rawEnd < dtstart=$begin")
return null
}
rawEnd
getLong(EventDetailProjection.IDX_DTEND).coerceAtLeast(begin)
}
// Kept raw (no untitled fallback): the detail screen substitutes its own

View File

@@ -120,9 +120,14 @@ class EventDetailMapperTest {
}
@Test
fun `dtend before dtstart drops detail`() {
fun `dtend before dtstart is clamped to a zero-length event, not dropped`() {
// A backwards DTEND is malformed, but dropping it would make the event
// un-openable (the "Something went wrong" trap, same as issue #34); keep
// it as a zero-length event so the user can still open and fix it.
val detail = detailReader(dtstart = 2000L, dtend = 1000L).toDetail()
assertThat(detail).isNull()
assertThat(detail).isNotNull()
assertThat(detail!!.instance.start.toEpochMilliseconds()).isEqualTo(2000L)
assertThat(detail.instance.end.toEpochMilliseconds()).isEqualTo(2000L)
}
@Test