Summary
Repair curve, spring, phase, and keyframe driver transitions so interrupted
animations hold the visible value, removing a configuration reaches the new
target, phase delays use the correct transition index, and completion
listeners fire exactly once. Treat this as one lifecycle-contract change —
fixing only one symptom risks leaving another old/new driver combination
inconsistent.
Why this matters
Several behaviors can render something other than the requested target:
CurveAnimationDriver builds its delay with ConstantTween(_initialSpec).
When an in-progress transition is interrupted, the next delay snaps back to
the driver's first target instead of holding the currently visible
interpolated spec.
StyleAnimationBuilder replaces a driver with config ?? oldConfig on type
change. That fallback is valid for implicit curve/spring drivers (they
implement didUpdateSpec) but phase/keyframe drivers do not retarget there.
- Removing a looping phase/keyframe config can therefore create a new driver
from the old config and keep the old sequence running instead of displaying
the new unanimated target.
- Phase tween construction checks
configs[currentIndex].delay but weights the
inserted delay with configs[nextIndex].delay, so placement and duration
disagree.
_setUpAnimation adds anonymous phase status listeners on every update and
never removes them, so completion callbacks accumulate.
PhaseAnimationConfig.onEnd exists but the driver reads the last curve
config's callback instead.
Source anchors
packages/mix/lib/src/animation/style_animation_builder.dart
packages/mix/lib/src/animation/style_animation_driver.dart
packages/mix/lib/src/animation/animation_config.dart
Required behavior
- Interrupted implicit animations begin from the currently displayed
StyleSpec; a configured delay holds that value for its full duration with no
backward jump.
- Reuse an outgoing config for a null target only when the driver supports
retargeting (curve, spring). Removing phase/keyframe config must stop/dispose
the old driver and expose the supplied target on the same update.
- The full old→new driver matrix (null, curve, spring, phase, keyframe) must
dispose old listeners/tickers and reach the correct target.
- Each phase transition uses one consistent destination index for its delay,
duration, curve, and callback.
- Choose one phase completion contract and fire it exactly once; do not retain
two competing onEnd paths.
- Fail early with actionable errors for empty phase lists, unequal style/
curve-config counts, negative durations/delays, looping timelines with no
positive duration, and duplicate keyframe track IDs.
Acceptance criteria
Summary
Repair curve, spring, phase, and keyframe driver transitions so interrupted
animations hold the visible value, removing a configuration reaches the new
target, phase delays use the correct transition index, and completion
listeners fire exactly once. Treat this as one lifecycle-contract change —
fixing only one symptom risks leaving another old/new driver combination
inconsistent.
Why this matters
Several behaviors can render something other than the requested target:
CurveAnimationDriverbuilds its delay withConstantTween(_initialSpec).When an in-progress transition is interrupted, the next delay snaps back to
the driver's first target instead of holding the currently visible
interpolated spec.
StyleAnimationBuilderreplaces a driver withconfig ?? oldConfigon typechange. That fallback is valid for implicit curve/spring drivers (they
implement
didUpdateSpec) but phase/keyframe drivers do not retarget there.from the old config and keep the old sequence running instead of displaying
the new unanimated target.
configs[currentIndex].delaybut weights theinserted delay with
configs[nextIndex].delay, so placement and durationdisagree.
_setUpAnimationadds anonymous phase status listeners on every update andnever removes them, so completion callbacks accumulate.
PhaseAnimationConfig.onEndexists but the driver reads the last curveconfig's callback instead.
Source anchors
packages/mix/lib/src/animation/style_animation_builder.dartpackages/mix/lib/src/animation/style_animation_driver.dartpackages/mix/lib/src/animation/animation_config.dartRequired behavior
StyleSpec; a configured delay holds that value for its full duration with nobackward jump.
retargeting (curve, spring). Removing phase/keyframe config must stop/dispose
the old driver and expose the supplied target on the same update.
dispose old listeners/tickers and reach the correct target.
duration, curve, and callback.
two competing
onEndpaths.curve-config counts, negative durations/delays, looping timelines with no
positive duration, and duplicate keyframe track IDs.
Acceptance criteria
mainand pass with the fix.