Merge recurring occurrence save fix (#338)
This commit is contained in:
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
- **Multi-day events stay above shorter events.** Month and Week bars, Split day lists, and Agenda now place multi-day events before one-day all-day events, then timed events; declined events remain last ([#291]).
|
||||
- **Editing one occurrence of a coloured Google series saves again.** Saving with "Only this event" kept you on the edit screen without saving anything ([#338]).
|
||||
|
||||
## [2.21.0] — 2026-09-23
|
||||
|
||||
@@ -1789,3 +1790,4 @@ automatically, with zero telemetry and no internet permission.
|
||||
[#321]: https://codeberg.org/jlmakiola/calendula/issues/321
|
||||
[#329]: https://codeberg.org/jlmakiola/calendula/issues/329
|
||||
[#285]: https://codeberg.org/jlmakiola/calendula/issues/285
|
||||
[#338]: https://codeberg.org/jlmakiola/calendula/issues/338
|
||||
|
||||
@@ -1261,6 +1261,13 @@ class AndroidCalendarDataSource @Inject constructor(
|
||||
values.toContentValues(),
|
||||
) ?: throw WriteFailedException("modify occurrence event id=$eventId begin=$beginMillis")
|
||||
val exceptionId = ContentUris.parseId(uri)
|
||||
form.colorKey?.let { key ->
|
||||
resolver.update(
|
||||
ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, exceptionId),
|
||||
ContentValues().apply { put(CalendarContract.Events.EVENT_COLOR_KEY, key) },
|
||||
null, null,
|
||||
)
|
||||
}
|
||||
// Whether the provider copied the parent's reminder rows is its
|
||||
// business — reconciling against the actual rows handles both ways.
|
||||
reconcileReminders(exceptionId, encodedReminders(form, allDayReminderTimeMinutes))
|
||||
|
||||
@@ -247,6 +247,10 @@ internal fun buildEventUpdateValues(
|
||||
* DTSTART + DURATION itself, clearing the inherited RRULE in the process. This
|
||||
* matches how AOSP Calendar/Etar write exceptions; sending DTEND is what made
|
||||
* "only this event" fail on-device (Codeberg #16).
|
||||
*
|
||||
* A palette key is left out: the provider crashes on an exception insert that
|
||||
* carries `EVENT_COLOR_KEY` (Codeberg #338), so the caller sets it with a plain
|
||||
* update once the row exists.
|
||||
*/
|
||||
internal fun buildOccurrenceExceptionValues(
|
||||
form: EventForm,
|
||||
@@ -264,7 +268,7 @@ internal fun buildOccurrenceExceptionValues(
|
||||
put(CalendarContract.Events.ACCESS_LEVEL, form.accessLevel.toProviderValue())
|
||||
put(CalendarContract.Events.EVENT_LOCATION, form.location.trim().ifEmpty { null })
|
||||
put(CalendarContract.Events.DESCRIPTION, form.description.trim().ifEmpty { null })
|
||||
putAll(eventColorColumns(form.colorKey, form.color))
|
||||
if (form.colorKey == null) putAll(eventColorColumns(null, form.color))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+15
-2
@@ -1075,16 +1075,29 @@ class EventWriteMapperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `occurrence exception carries the palette key`() {
|
||||
fun `occurrence exception leaves the palette key out`() {
|
||||
// The provider crashes on an exception insert carrying a colour key
|
||||
// (Codeberg #338); the data source sets it with an update afterwards.
|
||||
val values = buildOccurrenceExceptionValues(
|
||||
form = form().copy(colorKey = "2", color = 0xFFE67C00.toInt()),
|
||||
originalInstanceMillis = 0L,
|
||||
zone = berlin,
|
||||
)
|
||||
assertThat(values).containsEntry(CalendarContract.Events.EVENT_COLOR_KEY, "2")
|
||||
assertThat(values).doesNotContainKey(CalendarContract.Events.EVENT_COLOR_KEY)
|
||||
assertThat(values).doesNotContainKey(CalendarContract.Events.EVENT_COLOR)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `occurrence exception with a custom colour writes it directly`() {
|
||||
val values = buildOccurrenceExceptionValues(
|
||||
form = form().copy(color = 0xFFE67C00.toInt()),
|
||||
originalInstanceMillis = 0L,
|
||||
zone = berlin,
|
||||
)
|
||||
assertThat(values).containsEntry(CalendarContract.Events.EVENT_COLOR, 0xFFE67C00.toInt())
|
||||
assertThat(values).containsEntry(CalendarContract.Events.EVENT_COLOR_KEY, null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `occurrence exception with no colour clears both columns`() {
|
||||
val values = buildOccurrenceExceptionValues(
|
||||
|
||||
Reference in New Issue
Block a user