fix(store): three defects the instrumented suite found on first run
- forking an occurrence copied the master's alarm row id and hit the primary key; replaceForTask now clears it - a sub-second DTSTART made lib-recur emit the anchor and its truncated self, doubling a series' first occurrence; floor to the second, which is all RFC 5545 DATE-TIME carries - room-testing needs kotlinx-serialization 1.8+, but consistent resolution pinned androidTest to the app's 1.7.3 Tests: 52 pass on device.
This commit is contained in:
@@ -22,10 +22,14 @@ interface TaskAlarmDao {
|
||||
@Query("DELETE FROM task_alarms WHERE task_id = :taskId")
|
||||
fun deleteForTask(taskId: Long): Int
|
||||
|
||||
/** Set the task's only reminder, or clear it with `null`. */
|
||||
/**
|
||||
* Set the task's only reminder, or clear it with `null`. The row that lands is
|
||||
* always a new one — the id is cleared so an alarm lifted off another task
|
||||
* (forking an occurrence copies the master's) inserts instead of colliding.
|
||||
*/
|
||||
@Transaction
|
||||
fun replaceForTask(taskId: Long, alarm: TaskAlarmEntity?) {
|
||||
deleteForTask(taskId)
|
||||
alarm?.let { insert(it.copy(taskId = taskId)) }
|
||||
alarm?.let { insert(it.copy(id = 0, taskId = taskId)) }
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -9,6 +9,7 @@ import java.time.ZoneId
|
||||
import java.util.TimeZone
|
||||
import kotlin.time.Instant
|
||||
|
||||
private const val MILLIS_PER_SECOND = 1000L
|
||||
private const val MILLIS_PER_DAY = 24L * 60 * 60 * 1000
|
||||
|
||||
/** The rule set of one task series, as stored. All strings are raw iCalendar values. */
|
||||
@@ -117,10 +118,17 @@ object RecurrenceExpander {
|
||||
return TimeZone.getTimeZone(stored ?: floatingZone)
|
||||
}
|
||||
|
||||
/** All-day series are date-anchored: pin the anchor to UTC midnight, as it is stored. */
|
||||
/**
|
||||
* All-day series are date-anchored: pin the anchor to UTC midnight, as it is
|
||||
* stored. A timed one is floored to the second, because RFC 5545 DATE-TIME
|
||||
* has no sub-second field — carrying millis in makes lib-recur emit the raw
|
||||
* anchor *and* its truncated self, doubling the first occurrence, and mints
|
||||
* `RECURRENCE-ID`s no other client could address.
|
||||
*/
|
||||
private fun anchorMillis(spec: RecurrenceSpec): Long {
|
||||
val millis = spec.anchor.toEpochMilliseconds()
|
||||
return if (!spec.isAllDay) millis else Math.floorDiv(millis, MILLIS_PER_DAY) * MILLIS_PER_DAY
|
||||
val unit = if (spec.isAllDay) MILLIS_PER_DAY else MILLIS_PER_SECOND
|
||||
return Math.floorDiv(millis, unit) * unit
|
||||
}
|
||||
|
||||
private fun ruleOf(value: String, zone: TimeZone): RecurrenceRule? = runCatching {
|
||||
|
||||
Reference in New Issue
Block a user