Bring the drag docs in line with what the code does (#68)

The realignment envelope is described as implemented: whole-day shifts, or
a time-only shift whose anchor keeps its day. Also documents the one-write-
at-a-time gate, and notes the drag as a third recurring-scope prompt.
This commit is contained in:
2026-08-02 20:23:01 +02:00
parent 097b494c4a
commit 63ea07dd0b
3 changed files with 43 additions and 17 deletions

View File

@@ -69,8 +69,10 @@ data class MoveRequest(
/**
* A recurring drop waiting for the user to pick how far it reaches.
* [occurrenceOnly] means the rule names days a single moved occurrence can't
* re-derive (`BYDAY=MO,WE`, `2TH`, …) — see [realignRecurrence].
* [occurrenceOnly] means a wider write would leave the rule and the series
* anchor disagreeing — either the rule names days one moved occurrence can't
* re-derive (`BYDAY=MO,WE`, `2TH`, …), or the shift wouldn't carry the anchor
* across the same midnights the occurrence crossed.
*/
data class MoveScopePrompt(val occurrenceOnly: Boolean)
@@ -297,8 +299,9 @@ class RescheduleViewModel @Inject constructor(
val isRecurring = original.rrule != null && !detail.isException
val movedDay = shifted.start.date != original.start.date
// The series anchor moves by the same *wall-clock* shift as the dragged
// occurrence, so only a whole-day shift moves it by a predictable number
// of days; anything else can cross an extra midnight at the anchor.
// occurrence, so only a whole-day shift carries it across the same number
// of midnights whatever time of day it sits at. A same-date drag has its
// own, narrower check — see anchorKeepsItsDay.
val wholeDayShift = original.isAllDay || shifted.start.time == original.start.time
val realigned = if (isRecurring && movedDay) {
if (wholeDayShift) {
@@ -326,7 +329,8 @@ class RescheduleViewModel @Inject constructor(
else -> anchorKeepsItsDay(detail, original, shifted, zone)
},
// Where the series row's own DTSTART lands, given the anchor moves by
// the same shift — only meaningful under wholeDayShift.
// the same shift. Only read under canRealign, which is what
// guarantees the anchor really does travel this many days.
newAnchorDate = anchorDate(detail, original, zone)
.plus(shifted.start.date.toEpochDays() - original.start.date.toEpochDays(), DateTimeUnit.DAY),
)

View File

@@ -69,7 +69,7 @@
<!-- Drag an event to another time or day (#68) -->
<string name="event_move_action">Move…</string>
<string name="event_move_recurring_title">Move recurring event</string>
<string name="event_move_occurrence_only">This series picks its days in a way that can\'t be recalculated from one moved event, so only this event can move.</string>
<string name="event_move_occurrence_only">Moving the whole series would change which days it falls on, so only this event can move.</string>
<!-- %1$s is the new date and time, e.g. "Fri, 7 Aug, 09:00". -->
<string name="event_move_done">Moved to %1$s</string>
<string name="event_move_undo">Undo</string>