diff --git a/src/Avalonia.Animation/AnimationInstance`1.cs b/src/Avalonia.Animation/AnimationInstance`1.cs index 468c9c93a4..1ad609bce8 100644 --- a/src/Avalonia.Animation/AnimationInstance`1.cs +++ b/src/Avalonia.Animation/AnimationInstance`1.cs @@ -131,7 +131,6 @@ namespace Avalonia.Animation private void InternalStep(TimeSpan time) { DoPlayStates(); - var delayEndpoint = _delay; var iterationEndpoint = delayEndpoint + _duration; @@ -163,10 +162,7 @@ namespace Avalonia.Animation if (!_isLooping) { - if (_currentIteration > _repeatCount) - DoComplete(); - - if (time > iterationEndpoint) + if ((_currentIteration > _repeatCount) || (time > iterationEndpoint)) DoComplete(); } diff --git a/src/Avalonia.Animation/Animator`1.cs b/src/Avalonia.Animation/Animator`1.cs index b79e2d9342..d1a8960a10 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -1,10 +1,14 @@ -using System; +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; using System.Collections.Generic; using System.Linq; using System.Reactive.Linq; using Avalonia.Animation.Utils; using Avalonia.Collections; using Avalonia.Data; +using Avalonia.Reactive; namespace Avalonia.Animation { @@ -17,7 +21,7 @@ namespace Avalonia.Animation /// List of type-converted keyframes. /// private readonly List _convertedKeyframes = new List(); - + private bool _isVerifiedAndConverted; /// @@ -28,21 +32,17 @@ namespace Avalonia.Animation public Animator() { // Invalidate keyframes when changed. - this.CollectionChanged += delegate { _isVerifiedAndConverted = false; }; + this.CollectionChanged += delegate { _isVerifiedAndConverted = false; }; } /// public virtual IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable match, Action onComplete) { - if (!_isVerifiedAndConverted) + if (!_isVerifiedAndConverted) VerifyConvertKeyFrames(); - return match - .Where(p => p) - .Subscribe(_ => - { - var timerObs = RunKeyFrames(animation, control, clock, onComplete); - }); + var subject = new DisposeAnimationInstanceSubject(this, animation, control, clock, onComplete); + return match.Subscribe(subject); } /// @@ -55,7 +55,7 @@ namespace Avalonia.Animation /// The time parameter, relative to the total animation time protected (double IntraKFTime, KeyFramePair KFPair) GetKFPairAndIntraKFTime(double animationTime) { - AnimatorKeyFrame firstKeyframe, lastKeyframe ; + AnimatorKeyFrame firstKeyframe, lastKeyframe; int kvCount = _convertedKeyframes.Count; if (kvCount > 2) { @@ -121,7 +121,7 @@ namespace Avalonia.Animation /// /// Runs the KeyFrames Animation. /// - private IDisposable RunKeyFrames(Animation animation, Animatable control, IClock clock, Action onComplete) + internal IDisposable Run(Animation animation, Animatable control, IClock clock, Action onComplete) { var instance = new AnimationInstance( animation, @@ -188,4 +188,4 @@ namespace Avalonia.Animation } } } -} +} \ No newline at end of file diff --git a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs new file mode 100644 index 0000000000..a535b30b58 --- /dev/null +++ b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs @@ -0,0 +1,65 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using Avalonia.Animation.Utils; +using Avalonia.Collections; +using Avalonia.Data; +using Avalonia.Reactive; + +namespace Avalonia.Animation +{ + /// + /// Manages the lifetime of animation instances as determined by its selector state. + /// + internal class DisposeAnimationInstanceSubject : IObserver, IDisposable + { + private IDisposable _lastInstance; + private bool _lastMatch; + private Animator _animator; + private Animation _animation; + private Animatable _control; + private Action _onComplete; + private IClock _clock; + + public DisposeAnimationInstanceSubject(Animator animator, Animation animation, Animatable control, IClock clock, Action onComplete) + { + this._animator = animator; + this._animation = animation; + this._control = control; + this._onComplete = onComplete; + this._clock = clock; + } + + + public void Dispose() + { + _lastInstance?.Dispose(); + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + _lastInstance?.Dispose(); + } + + void IObserver.OnNext(bool matchVal) + { + if (matchVal != _lastMatch) + { + _lastInstance?.Dispose(); + if (matchVal) + { + _lastInstance = _animator.Run(_animation, _control, _clock, _onComplete); + } + _lastMatch = matchVal; + } + } + } +} \ No newline at end of file diff --git a/src/Avalonia.Animation/DoubleAnimator.cs b/src/Avalonia.Animation/DoubleAnimator.cs index aeeb29a7dd..2e0ce64185 100644 --- a/src/Avalonia.Animation/DoubleAnimator.cs +++ b/src/Avalonia.Animation/DoubleAnimator.cs @@ -1,4 +1,7 @@ -namespace Avalonia.Animation +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Animation { /// /// Animator that handles properties. diff --git a/src/Avalonia.Animation/FillMode.cs b/src/Avalonia.Animation/FillMode.cs index 001e1cdeb4..39beecf455 100644 --- a/src/Avalonia.Animation/FillMode.cs +++ b/src/Avalonia.Animation/FillMode.cs @@ -1,4 +1,7 @@ -namespace Avalonia.Animation +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Animation { public enum FillMode { diff --git a/src/Avalonia.Animation/IAnimation.cs b/src/Avalonia.Animation/IAnimation.cs index ff85535d8a..26cf4a6fd1 100644 --- a/src/Avalonia.Animation/IAnimation.cs +++ b/src/Avalonia.Animation/IAnimation.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using System; using System.Threading.Tasks; diff --git a/src/Avalonia.Animation/IAnimationSetter.cs b/src/Avalonia.Animation/IAnimationSetter.cs index 2d22377286..9c8365ea37 100644 --- a/src/Avalonia.Animation/IAnimationSetter.cs +++ b/src/Avalonia.Animation/IAnimationSetter.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + namespace Avalonia.Animation { public interface IAnimationSetter diff --git a/src/Avalonia.Animation/IAnimator.cs b/src/Avalonia.Animation/IAnimator.cs index d0fb173c54..d09f396d70 100644 --- a/src/Avalonia.Animation/IAnimator.cs +++ b/src/Avalonia.Animation/IAnimator.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; using System.Collections.Generic; namespace Avalonia.Animation diff --git a/src/Avalonia.Animation/KeyFrame.cs b/src/Avalonia.Animation/KeyFrame.cs index 5eb0d2e901..44e39e042e 100644 --- a/src/Avalonia.Animation/KeyFrame.cs +++ b/src/Avalonia.Animation/KeyFrame.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; using System.Collections.Generic; using Avalonia.Collections; diff --git a/src/Avalonia.Animation/KeyFramePair`1.cs b/src/Avalonia.Animation/KeyFramePair`1.cs index b0622a1580..60a16d094f 100644 --- a/src/Avalonia.Animation/KeyFramePair`1.cs +++ b/src/Avalonia.Animation/KeyFramePair`1.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + namespace Avalonia.Animation { /// diff --git a/src/Avalonia.Animation/PlayState.cs b/src/Avalonia.Animation/PlayState.cs index 313d33d586..8d28f06eb1 100644 --- a/src/Avalonia.Animation/PlayState.cs +++ b/src/Avalonia.Animation/PlayState.cs @@ -1,4 +1,7 @@ -namespace Avalonia.Animation +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Animation { /// /// Determines the playback state of an animation. diff --git a/src/Avalonia.Animation/PlaybackDirection.cs b/src/Avalonia.Animation/PlaybackDirection.cs index bbce6106e1..a44dd388ae 100644 --- a/src/Avalonia.Animation/PlaybackDirection.cs +++ b/src/Avalonia.Animation/PlaybackDirection.cs @@ -1,4 +1,7 @@ -namespace Avalonia.Animation +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Animation { /// /// Determines the playback direction of an animation. diff --git a/src/Avalonia.Base/Reactive/ObservableEx.cs b/src/Avalonia.Base/Reactive/ObservableEx.cs index 5b2a39d5ff..a1ec8f9a8a 100644 --- a/src/Avalonia.Base/Reactive/ObservableEx.cs +++ b/src/Avalonia.Base/Reactive/ObservableEx.cs @@ -21,7 +21,7 @@ namespace Avalonia.Reactive { return new SingleValueImpl(value); } - + private class SingleValueImpl : IObservable { private T _value; @@ -30,7 +30,6 @@ namespace Avalonia.Reactive { _value = value; } - public IDisposable Subscribe(IObserver observer) { observer.OnNext(_value); @@ -38,4 +37,4 @@ namespace Avalonia.Reactive } } } -} +} \ No newline at end of file diff --git a/src/Avalonia.Controls/ProgressBar.cs b/src/Avalonia.Controls/ProgressBar.cs index 7f4b549849..a0f51099cd 100644 --- a/src/Avalonia.Controls/ProgressBar.cs +++ b/src/Avalonia.Controls/ProgressBar.cs @@ -37,7 +37,8 @@ namespace Avalonia.Controls PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Horizontal, ":horizontal"); PseudoClass(IsIndeterminateProperty, ":indeterminate"); - ValueProperty.Changed.AddClassHandler(x => x.ValueChanged); + ValueProperty.Changed.AddClassHandler(x => x.UpdateIndicatorWhenPropChanged); + IsIndeterminateProperty.Changed.AddClassHandler(x => x.UpdateIndicatorWhenPropChanged); } public bool IsIndeterminate @@ -114,9 +115,9 @@ namespace Avalonia.Controls } } - private void ValueChanged(AvaloniaPropertyChangedEventArgs e) + private void UpdateIndicatorWhenPropChanged(AvaloniaPropertyChangedEventArgs e) { UpdateIndicator(Bounds.Size); } } -} +} \ No newline at end of file