fix(#514): re-encode reminders when an existing event switches all-day

This commit is contained in:
makiolaj committed 2026-11-14 02:39:26 +01:00
1 parent 6a384b03e9
commit f1554fbcf3
3 files changed
+22 -6

No files matched your search

@@ -1024,9 +1024,8 @@ class AndroidCalendarDataSource @Inject constructor(
updateEventRow(eventId, values.toContentValues(), "update event id=$eventId")
}
// Untouched reminder sets are left alone so unrelated edits can't
// disturb provider rows the form never knew about. The diff is on the
// form's semantic minutes; reconcile works in encoded provider minutes.
if (updated.reminders.toSet() != original.reminders.toSet()) {
// disturb provider rows the form never knew about.
if (remindersNeedRewrite(original, updated)) {
reconcileReminders(eventId, encodedReminders(updated, allDayReminderTimeMinutes))
}
// Same untouched-set guard for guests: only reconcile when the form's
@@ -1785,3 +1784,11 @@ class AndroidCalendarDataSource @Inject constructor(
const val MAX_SEARCH_TOKENS = 8
}
}
/**
* Whether an update must rewrite the reminder rows. The diff is on the form's
* semantic minutes, but the provider stores encoded minutes, so switching all-day
* on or off re-encodes an otherwise unchanged set.
*/
internal fun remindersNeedRewrite(original: EventForm, updated: EventForm): Boolean =
updated.reminders.toSet() != original.reminders.toSet() || updated.isAllDay != original.isAllDay
@@ -538,9 +538,10 @@ class EventEditViewModel @Inject constructor(
if (opened != session) return@launch
val current = _form.value ?: return@launch
if (_editTarget.value != null) return@launch
if (default.isEmpty() || default == current.firingReminders()) return@launch
val firing = current.firingReminders()
if (default.isEmpty() || default == firing) return@launch
_importReminderPrompt.value = ImportReminderPrompt(
currentReminderCount = current.firingReminders().size,
currentReminderCount = firing.size,
defaultReminders = default,
)
}
@@ -967,7 +968,7 @@ class EventEditViewModel @Inject constructor(
/**
* Reminders as they fire: an all-day event fires on whole days, so a sub-day lead
* time kept from the timed form reads as its day. The form keeps the raw values,
* so switching all-day off again restores them.
* so switching all-day off again restores any the user did not remove.
*/
internal fun EventForm.firingReminders(): List<Int> =
if (isAllDay) wholeDayLeadTimes(reminders) else reminders
@@ -33,6 +33,14 @@ class EventWriteMapperTest {
timezone = timezone,
)
@Test
fun `reminders are rewritten when they change or the all-day flag flips`() {
val timed = form().copy(reminders = listOf(10))
assertThat(remindersNeedRewrite(timed, timed.copy(title = "Renamed"))).isFalse()
assertThat(remindersNeedRewrite(timed, timed.copy(reminders = listOf(10, 30)))).isTrue()
assertThat(remindersNeedRewrite(timed, timed.copy(isAllDay = true))).isTrue()
}
@Test
fun `timed event resolves wall clock in the given zone`() {
val times = form().toWriteTimes(berlin)