Make SubtitleLineViewModel.StartTime a plain setter; add StartTimeKeepDuration#11664
Conversation
…pDuration
The StartTime setter had a hidden side effect: assigning it also moved
EndTime to preserve duration ("drag the whole line"). That made the
natural-looking `line.StartTime = x` the dangerous path - programmatic
code almost always wants the end to stay fixed, hence ~45 SetStartTimeOnly
calls, while forgetting it silently shifted timing.
Invert the default:
- StartTime setter is now plain: moves the start, keeps the end fixed,
recomputes duration (identical to SetStartTimeOnly, which is kept as an
alias so existing callers are unchanged).
- New StartTimeKeepDuration property provides the drag-the-line behavior.
- The start-time grid editor binds to StartTimeKeepDuration when no
separate end-time editor is shown (preserving that UX), and to
StartTimeOnly otherwise.
Converted the five call sites that relied on the old drag behavior to
StartTimeKeepDuration (waveform Alt-drag, insert-at-video-position,
transcribe-split, ripple-delete trailing shift, and single-point sync).
Converting single-point sync also fixes a bug where it shifted only the
start time, leaving end times in place (shrinking/inverting durations).
Add tests for the new StartTime / StartTimeKeepDuration / SetStartTimeOnly
semantics and for single-point sync shifting the whole line.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code review found six sites that shift a line keeping its duration using the compound form `StartTime += ...` (or `+ adjustment`), which the original caller audit's `.StartTime = ` grep missed. After the StartTime-setter inversion these would have moved only the start and corrupted durations: - Adjust (all / selected / selected-and-forward) - the "Show earlier/later" and "Adjust all times" sync tool - WaveformSetStartAndOffsetTheRest / WaveformSetEndAndOffsetTheRest - AudioVisualizerSetStartAndOffsetTheRest Convert them to StartTimeKeepDuration so the whole line shifts as before. Also simplify StartTimeKeepDuration to delegate to SetTimes, so start/end are applied atomically (no transient start > end) and the shift is computed from the live EndTime - StartTime span rather than a possibly-stale Duration field. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Self-review follow-upRan a multi-angle review of this branch. It caught one significant miss in the original caller audit, now fixed in bd30cfe: The audit grepped for
All converted to Also simplified Other review findings reviewed and not changed (not regressions from this PR):
Full UI suite: 354/354 green. |
StartTimeKeepDuration must stay a property because the start-time editor binds to it TwoWay, but assigning a side-effecting property from code is the footgun this change set out to remove. Mirror the existing StartTimeOnly/SetStartTimeOnly convention: keep a thin bindable property and add an internal SetStartTimeKeepDuration(TimeSpan) method that the ~11 programmatic callers use, so the "move the whole line" side effect reads as an explicit action. The property delegates to the method. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Background
SubtitleLineViewModel.StartTime's setter had a hidden side effect: assigning it also movedEndTimeto preserve the duration ("drag the whole line"). This made the most natural-looking statement —line.StartTime = x— the dangerous one:SetStartTimeOnly(...)calls to opt out of the drag.SetStartTimeOnlyand writingStartTime = xsilently shifted the end too, corrupting timing.This is the design follow-up to #11661 (which routed
AdjustthroughSetTimes). It inverts the default so the safe behavior is the obvious one.Change
StartTimesetter is now plain: it moves the start, keeps the end fixed, and recomputes the duration — identical to the existingSetStartTimeOnly, which is kept as an alias so the ~45 existing callers are unchanged.StartTimeKeepDurationproperty provides the old drag-the-line (preserve-duration) behavior, explicitly.InitListViewAndEditBox): the start-time editor binds toStartTimeKeepDurationwhen no separate end-time editor is shown (preserving that UX), and toStartTimeOnlywhen one is.Caller audit
I audited every direct
SubtitleLineViewModel.StartTime = …assignment insrc/ui(excludingParagraphand other types). Only five relied on the drag and were converted toStartTimeKeepDuration:AudioVisualizer.cs— waveform Alt-drag (move whole line)MainViewModel.cs— insert subtitle at video positionMainViewModel.cs— transcribe split into new linesMainViewModel.cs— ripple-delete trailing-line shiftPointSyncer.cs— single-point syncAll other direct assignments either set
EndTimeimmediately after or wanted keep-end semantics (one, snap-start-to-shot-change, is actually fixed by the new plain setter).Bonus fix
Converting single-point sync (
AdjustViaShowEarlierLater) toStartTimeKeepDurationalso fixes a real bug: it previously shifted only the start time of every line, leaving end times in place, which shrank/inverted durations. It now shifts the whole line by the offset.Tests
SubtitleLineViewModelTimeTests—StartTime(plain, keep-end),SetStartTimeOnly(keep-end), andStartTimeKeepDuration(positive/negative shift, duration preserved).PointSyncerTests— single-point sync shifts both start and end, preserving durations.Full UI suite: 354/354 passing.
🤖 Generated with Claude Code