From ec695433dec3a6b66967f692b66538e95366a842 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Mon, 10 Sep 2018 01:02:35 +0800 Subject: [PATCH 01/11] Cancel an animation instance when the selector turns false. --- src/Avalonia.Animation/Animator`1.cs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Animation/Animator`1.cs b/src/Avalonia.Animation/Animator`1.cs index f0ef55aa9e..74f09d5488 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -37,12 +37,29 @@ namespace Avalonia.Animation if (!_isVerifiedAndConverted) VerifyConvertKeyFrames(); - return match + var matchStream = match + .DistinctUntilChanged() + .Publish() + .RefCount(); + + var activeInstance = matchStream .Where(p => p) - .Subscribe(_ => - { - var timerObs = RunKeyFrames(animation, control, onComplete); - }); + .Select(p => RunKeyFrames(animation, control, onComplete)); + + var negationStream = matchStream + .Where(p => !p); + + return Observable + .WithLatestFrom( + negationStream, + activeInstance, + (isMatch, instance) => + { + if (!isMatch && animation.RepeatCount.IsLoop) + instance?.Dispose(); + return true; + }) + .Subscribe(); } /// From 64a4a6d82af01a3ba2c69182b2fcd16c33ddc153 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Tue, 11 Sep 2018 15:04:12 +0800 Subject: [PATCH 02/11] Simplify Fix; Invalidate when IsIndeterminate property changes. --- src/Avalonia.Animation/Animator`1.cs | 39 ++++++++++------------------ src/Avalonia.Controls/ProgressBar.cs | 8 +++++- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/Avalonia.Animation/Animator`1.cs b/src/Avalonia.Animation/Animator`1.cs index 74f09d5488..ab82bfb35d 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -17,7 +17,7 @@ namespace Avalonia.Animation /// List of type-converted keyframes. /// private readonly List _convertedKeyframes = new List(); - + private bool _isVerifiedAndConverted; /// @@ -28,38 +28,25 @@ 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, IObservable match, Action onComplete) { - if (!_isVerifiedAndConverted) + if (!_isVerifiedAndConverted) VerifyConvertKeyFrames(); - var matchStream = match - .DistinctUntilChanged() - .Publish() - .RefCount(); - - var activeInstance = matchStream - .Where(p => p) - .Select(p => RunKeyFrames(animation, control, onComplete)); - - var negationStream = matchStream - .Where(p => !p); - - return Observable - .WithLatestFrom( - negationStream, - activeInstance, - (isMatch, instance) => + return match + .DistinctUntilChanged() + .Select(x => x ? RunKeyFrames(animation, control, onComplete) : null) + .Buffer(2, 1) + .Where(x => x.Count > 1) + .Subscribe(x => { - if (!isMatch && animation.RepeatCount.IsLoop) - instance?.Dispose(); - return true; - }) - .Subscribe(); + if (animation.RepeatCount.IsLoop) + x[0]?.Dispose(); + }); } /// @@ -72,7 +59,7 @@ namespace Avalonia.Animation /// The time parameter, relative to the total animation time protected (double IntraKFTime, KeyFramePair KFPair) GetKFPairAndIntraKFTime(double t) { - AnimatorKeyFrame firstCue, lastCue ; + AnimatorKeyFrame firstCue, lastCue; int kvCount = _convertedKeyframes.Count; if (kvCount > 2) { diff --git a/src/Avalonia.Controls/ProgressBar.cs b/src/Avalonia.Controls/ProgressBar.cs index 7f4b549849..fe7b8e64c7 100644 --- a/src/Avalonia.Controls/ProgressBar.cs +++ b/src/Avalonia.Controls/ProgressBar.cs @@ -38,6 +38,7 @@ namespace Avalonia.Controls PseudoClass(IsIndeterminateProperty, ":indeterminate"); ValueProperty.Changed.AddClassHandler(x => x.ValueChanged); + IsIndeterminateProperty.Changed.AddClassHandler(x => x.IsIndeterminateChanged); } public bool IsIndeterminate @@ -118,5 +119,10 @@ namespace Avalonia.Controls { UpdateIndicator(Bounds.Size); } + + private void IsIndeterminateChanged(AvaloniaPropertyChangedEventArgs e) + { + UpdateIndicator(Bounds.Size); + } } -} +} \ No newline at end of file From 3cbcd0ac0fab750a413b0e9aaeba88d092faa238 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Wed, 12 Sep 2018 10:42:44 +0800 Subject: [PATCH 03/11] Match CSS's behavior on selectors & animations. --- src/Avalonia.Animation/Animator`1.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.Animation/Animator`1.cs b/src/Avalonia.Animation/Animator`1.cs index ab82bfb35d..e4af0f356d 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -37,16 +37,11 @@ namespace Avalonia.Animation if (!_isVerifiedAndConverted) VerifyConvertKeyFrames(); - return match - .DistinctUntilChanged() - .Select(x => x ? RunKeyFrames(animation, control, onComplete) : null) - .Buffer(2, 1) - .Where(x => x.Count > 1) - .Subscribe(x => - { - if (animation.RepeatCount.IsLoop) - x[0]?.Dispose(); - }); + return match.DistinctUntilChanged() + .Select(x => x ? RunKeyFrames(animation, control, onComplete) : null) + .Buffer(2, 1) + .Where(x => x.Count > 1) + .Subscribe(x => x[0]?.Dispose()); } /// From a8d4c8d799ee1abf5338028361b0855745ebae47 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Thu, 13 Sep 2018 14:24:13 +0800 Subject: [PATCH 04/11] Add a new Disposable Extention. --- src/Avalonia.Animation/Animator`1.cs | 11 +++-- .../Reactive/DisposeOnNextObservable.cs | 40 +++++++++++++++++++ src/Avalonia.Base/Reactive/ObservableEx.cs | 17 +++++++- 3 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs diff --git a/src/Avalonia.Animation/Animator`1.cs b/src/Avalonia.Animation/Animator`1.cs index e4af0f356d..888450e7f0 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reactive.Disposables; using System.Reactive.Linq; using Avalonia.Animation.Utils; using Avalonia.Collections; using Avalonia.Data; +using Avalonia.Reactive; + namespace Avalonia.Animation { @@ -38,10 +41,10 @@ namespace Avalonia.Animation VerifyConvertKeyFrames(); return match.DistinctUntilChanged() - .Select(x => x ? RunKeyFrames(animation, control, onComplete) : null) - .Buffer(2, 1) - .Where(x => x.Count > 1) - .Subscribe(x => x[0]?.Dispose()); + .ObserveOn(Avalonia.Threading.AvaloniaScheduler.Instance) + .Select(x => x ? RunKeyFrames(animation, control, onComplete) : Disposable.Empty) + .DisposeCurrentOnNext() + .Subscribe(); } /// diff --git a/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs b/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs new file mode 100644 index 0000000000..8650fe5400 --- /dev/null +++ b/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs @@ -0,0 +1,40 @@ +using System; +using Avalonia.Threading; + +namespace Avalonia.Reactive +{ + public class DisposeOnNextObservable : LightweightObservableBase, IObserver where T : IDisposable + { + private IDisposable lastValue; + + private void ValueNext(T value) + { + this.PublishNext(value); + lastValue?.Dispose(); + lastValue = value; + } + + public void OnCompleted() + { + this.PublishCompleted(); + } + + public void OnError(Exception error) + { + this.PublishError(error); + } + + void IObserver.OnNext(T value) + { + ValueNext(value); + } + + protected override void Initialize() + { + } + + protected override void Deinitialize() + { + } + } +} \ No newline at end of file diff --git a/src/Avalonia.Base/Reactive/ObservableEx.cs b/src/Avalonia.Base/Reactive/ObservableEx.cs index 5b2a39d5ff..dc3be36015 100644 --- a/src/Avalonia.Base/Reactive/ObservableEx.cs +++ b/src/Avalonia.Base/Reactive/ObservableEx.cs @@ -22,6 +22,20 @@ namespace Avalonia.Reactive return new SingleValueImpl(value); } + /// + /// Disposes the current and saves the next. + /// + /// The type of the value. + /// The source . + /// The observable. + public static IObservable DisposeCurrentOnNext(this IObservable observable) + where T : IDisposable + { + var subject = new DisposeOnNextObservable(); + observable.Subscribe(subject); + return subject; + } + private class SingleValueImpl : IObservable { private T _value; @@ -30,7 +44,6 @@ namespace Avalonia.Reactive { _value = value; } - public IDisposable Subscribe(IObserver observer) { observer.OnNext(_value); @@ -38,4 +51,4 @@ namespace Avalonia.Reactive } } } -} +} \ No newline at end of file From 74c8cedde9070956d283137e0407d1888572c72b Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Thu, 13 Sep 2018 15:17:32 +0800 Subject: [PATCH 05/11] Try fixing the sporadic Bindings Exceptions. --- src/Avalonia.Animation/Animator`1.cs | 7 ++----- src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Animation/Animator`1.cs b/src/Avalonia.Animation/Animator`1.cs index 888450e7f0..decca8e858 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -1,14 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reactive.Disposables; using System.Reactive.Linq; using Avalonia.Animation.Utils; using Avalonia.Collections; using Avalonia.Data; using Avalonia.Reactive; - namespace Avalonia.Animation { /// @@ -41,8 +39,7 @@ namespace Avalonia.Animation VerifyConvertKeyFrames(); return match.DistinctUntilChanged() - .ObserveOn(Avalonia.Threading.AvaloniaScheduler.Instance) - .Select(x => x ? RunKeyFrames(animation, control, onComplete) : Disposable.Empty) + .Select(x => x ? RunKeyFrames(animation, control, onComplete) : null) .DisposeCurrentOnNext() .Subscribe(); } @@ -172,4 +169,4 @@ namespace Avalonia.Animation } } } -} +} \ No newline at end of file diff --git a/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs b/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs index 8650fe5400..18af9e8752 100644 --- a/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs +++ b/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs @@ -9,9 +9,9 @@ namespace Avalonia.Reactive private void ValueNext(T value) { - this.PublishNext(value); lastValue?.Dispose(); lastValue = value; + this.PublishNext(value); } public void OnCompleted() From f2f96e2f46a520be9f84febfeb79276b5da91586 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 13 Sep 2018 20:42:18 +0200 Subject: [PATCH 06/11] Don't dispose completed binding. --- src/Avalonia.Base/PriorityBindingEntry.cs | 7 +++++++ src/Avalonia.Base/PriorityLevel.cs | 14 +++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Base/PriorityBindingEntry.cs b/src/Avalonia.Base/PriorityBindingEntry.cs index 570bfe03dc..d4a47306a7 100644 --- a/src/Avalonia.Base/PriorityBindingEntry.cs +++ b/src/Avalonia.Base/PriorityBindingEntry.cs @@ -50,6 +50,11 @@ namespace Avalonia get; } + /// + /// Gets a value indicating whether the binding has completed. + /// + public bool HasCompleted { get; private set; } + /// /// The current value of the binding. /// @@ -129,6 +134,8 @@ namespace Avalonia private void Completed() { + HasCompleted = true; + if (Dispatcher.UIThread.CheckAccess()) { _owner.Completed(this); diff --git a/src/Avalonia.Base/PriorityLevel.cs b/src/Avalonia.Base/PriorityLevel.cs index 96661bd7ea..909558b0ce 100644 --- a/src/Avalonia.Base/PriorityLevel.cs +++ b/src/Avalonia.Base/PriorityLevel.cs @@ -112,12 +112,16 @@ namespace Avalonia return Disposable.Create(() => { - Bindings.Remove(node); - entry.Dispose(); - - if (entry.Index >= ActiveBindingIndex) + if (!entry.HasCompleted) { - ActivateFirstBinding(); + Bindings.Remove(node); + + entry.Dispose(); + + if (entry.Index >= ActiveBindingIndex) + { + ActivateFirstBinding(); + } } }); } From ee1a8ee30fb0f10e94335ce666af4fe19e59734d Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Fri, 14 Sep 2018 10:49:49 +0800 Subject: [PATCH 07/11] Make a specialized observable for instance lifetime handling. Delete DisposeOnNextObservable. --- src/Avalonia.Animation/AnimationInstance`1.cs | 7 +-- src/Avalonia.Animation/Animator`1.cs | 18 +++--- .../DisposeAnimationInstanceObservable.cs | 62 +++++++++++++++++++ .../Reactive/DisposeOnNextObservable.cs | 40 ------------ src/Avalonia.Base/Reactive/ObservableEx.cs | 16 +---- 5 files changed, 73 insertions(+), 70 deletions(-) create mode 100644 src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs delete mode 100644 src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs diff --git a/src/Avalonia.Animation/AnimationInstance`1.cs b/src/Avalonia.Animation/AnimationInstance`1.cs index 5a72904ed2..c264663b56 100644 --- a/src/Avalonia.Animation/AnimationInstance`1.cs +++ b/src/Avalonia.Animation/AnimationInstance`1.cs @@ -154,7 +154,7 @@ namespace Avalonia.Animation private void InternalStep(TimeSpan systemTime) { DoPlayStatesAndTime(systemTime); - + var time = _internalClock - _firstFrameCount; var delayEndpoint = _delay; var iterationEndpoint = delayEndpoint + _duration; @@ -188,10 +188,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 decca8e858..0de3991a88 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.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 System.Linq; using System.Reactive.Linq; @@ -38,10 +41,8 @@ namespace Avalonia.Animation if (!_isVerifiedAndConverted) VerifyConvertKeyFrames(); - return match.DistinctUntilChanged() - .Select(x => x ? RunKeyFrames(animation, control, onComplete) : null) - .DisposeCurrentOnNext() - .Subscribe(); + var subject = new DisposeAnimationInstanceObservable(this, animation, control, onComplete); + return match.Subscribe(subject); } /// @@ -96,11 +97,8 @@ namespace Avalonia.Animation var lastFrameData = (lastCue.GetTypedValue(), lastCue.isNeutral); return (intraframeTime, new KeyFramePair(firstFrameData, lastFrameData)); } - - /// - /// Runs the KeyFrames Animation. - /// - private IDisposable RunKeyFrames(Animation animation, Animatable control, Action onComplete) + + internal IDisposable Run(Animation animation, Animatable control, Action onComplete) { var instance = new AnimationInstance(animation, control, this, onComplete, DoInterpolation); return control.Bind((AvaloniaProperty)Property, instance, BindingPriority.Animation); diff --git a/src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs b/src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs new file mode 100644 index 0000000000..902a09030b --- /dev/null +++ b/src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs @@ -0,0 +1,62 @@ +// 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 DisposeAnimationInstanceObservable : IObserver, IDisposable + { + private IDisposable _lastInstance; + private bool _lastMatch; + private Animator _animator; + private Animation _animation; + private Animatable _control; + private Action _onComplete; + + public DisposeAnimationInstanceObservable(Animator animator, Animation animation, Animatable control, Action onComplete) + { + this._animator = animator; + this._animation = animation; + this._control = control; + this._onComplete = onComplete; + } + + 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.RunAnimation(_animation, _control, _onComplete); + } + _lastMatch = matchVal; + } + } + } +} \ No newline at end of file diff --git a/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs b/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs deleted file mode 100644 index 18af9e8752..0000000000 --- a/src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using Avalonia.Threading; - -namespace Avalonia.Reactive -{ - public class DisposeOnNextObservable : LightweightObservableBase, IObserver where T : IDisposable - { - private IDisposable lastValue; - - private void ValueNext(T value) - { - lastValue?.Dispose(); - lastValue = value; - this.PublishNext(value); - } - - public void OnCompleted() - { - this.PublishCompleted(); - } - - public void OnError(Exception error) - { - this.PublishError(error); - } - - void IObserver.OnNext(T value) - { - ValueNext(value); - } - - protected override void Initialize() - { - } - - protected override void Deinitialize() - { - } - } -} \ No newline at end of file diff --git a/src/Avalonia.Base/Reactive/ObservableEx.cs b/src/Avalonia.Base/Reactive/ObservableEx.cs index dc3be36015..a1ec8f9a8a 100644 --- a/src/Avalonia.Base/Reactive/ObservableEx.cs +++ b/src/Avalonia.Base/Reactive/ObservableEx.cs @@ -21,21 +21,7 @@ namespace Avalonia.Reactive { return new SingleValueImpl(value); } - - /// - /// Disposes the current and saves the next. - /// - /// The type of the value. - /// The source . - /// The observable. - public static IObservable DisposeCurrentOnNext(this IObservable observable) - where T : IDisposable - { - var subject = new DisposeOnNextObservable(); - observable.Subscribe(subject); - return subject; - } - + private class SingleValueImpl : IObservable { private T _value; From a462d0563c75e8c4c461e57847d7b4ad55e94157 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Fri, 14 Sep 2018 10:50:18 +0800 Subject: [PATCH 08/11] Add missing license headers on Avalonia.Animations. --- src/Avalonia.Animation/DoubleAnimator.cs | 5 ++++- src/Avalonia.Animation/FillMode.cs | 5 ++++- src/Avalonia.Animation/IAnimation.cs | 3 +++ src/Avalonia.Animation/IAnimationSetter.cs | 3 +++ src/Avalonia.Animation/IAnimator.cs | 5 ++++- src/Avalonia.Animation/KeyFrame.cs | 5 ++++- src/Avalonia.Animation/KeyFramePair`1.cs | 3 +++ src/Avalonia.Animation/PlayState.cs | 5 ++++- src/Avalonia.Animation/PlaybackDirection.cs | 5 ++++- 9 files changed, 33 insertions(+), 6 deletions(-) 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 1d545a322a..831391ce46 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 9a4da35a02..0f26b7dc2f 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. From d9f1da005251757fcee83de2600f65ecd15f4ba9 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Fri, 14 Sep 2018 10:51:59 +0800 Subject: [PATCH 09/11] Fix missed method rename. --- src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs b/src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs index 902a09030b..f58e816e54 100644 --- a/src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs +++ b/src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs @@ -53,7 +53,7 @@ namespace Avalonia.Animation _lastInstance?.Dispose(); if (matchVal) { - _lastInstance = _animator.RunAnimation(_animation, _control, _onComplete); + _lastInstance = _animator.Run(_animation, _control, _onComplete); } _lastMatch = matchVal; } From e4fff20551f80f06e3bdd82861d272814667c445 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 15 Sep 2018 11:56:57 +0800 Subject: [PATCH 10/11] Address PR Reviews --- src/Avalonia.Animation/AnimationInstance`1.cs | 2 +- src/Avalonia.Animation/Animator`1.cs | 2 +- ...servable.cs => DisposeAnimationInstanceSubject.cs} | 4 ++-- src/Avalonia.Controls/ProgressBar.cs | 11 +++-------- 4 files changed, 7 insertions(+), 12 deletions(-) rename src/Avalonia.Animation/{DisposeAnimationInstanceObservable.cs => DisposeAnimationInstanceSubject.cs} (87%) diff --git a/src/Avalonia.Animation/AnimationInstance`1.cs b/src/Avalonia.Animation/AnimationInstance`1.cs index c264663b56..1480fbe741 100644 --- a/src/Avalonia.Animation/AnimationInstance`1.cs +++ b/src/Avalonia.Animation/AnimationInstance`1.cs @@ -188,7 +188,7 @@ namespace Avalonia.Animation if (!_isLooping) { - if ((_currentIteration > _repeatCount) | (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 0de3991a88..bdf655b5cb 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -41,7 +41,7 @@ namespace Avalonia.Animation if (!_isVerifiedAndConverted) VerifyConvertKeyFrames(); - var subject = new DisposeAnimationInstanceObservable(this, animation, control, onComplete); + var subject = new DisposeAnimationInstanceSubject(this, animation, control, onComplete); return match.Subscribe(subject); } diff --git a/src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs similarity index 87% rename from src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs rename to src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs index f58e816e54..1ac2ac8b98 100644 --- a/src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs +++ b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs @@ -15,7 +15,7 @@ namespace Avalonia.Animation /// /// Manages the lifetime of animation instances as determined by its selector state. /// - internal class DisposeAnimationInstanceObservable : IObserver, IDisposable + internal class DisposeAnimationInstanceSubject : IObserver, IDisposable { private IDisposable _lastInstance; private bool _lastMatch; @@ -24,7 +24,7 @@ namespace Avalonia.Animation private Animatable _control; private Action _onComplete; - public DisposeAnimationInstanceObservable(Animator animator, Animation animation, Animatable control, Action onComplete) + public DisposeAnimationInstanceSubject(Animator animator, Animation animation, Animatable control, Action onComplete) { this._animator = animator; this._animation = animation; diff --git a/src/Avalonia.Controls/ProgressBar.cs b/src/Avalonia.Controls/ProgressBar.cs index fe7b8e64c7..a0f51099cd 100644 --- a/src/Avalonia.Controls/ProgressBar.cs +++ b/src/Avalonia.Controls/ProgressBar.cs @@ -37,8 +37,8 @@ namespace Avalonia.Controls PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Horizontal, ":horizontal"); PseudoClass(IsIndeterminateProperty, ":indeterminate"); - ValueProperty.Changed.AddClassHandler(x => x.ValueChanged); - IsIndeterminateProperty.Changed.AddClassHandler(x => x.IsIndeterminateChanged); + ValueProperty.Changed.AddClassHandler(x => x.UpdateIndicatorWhenPropChanged); + IsIndeterminateProperty.Changed.AddClassHandler(x => x.UpdateIndicatorWhenPropChanged); } public bool IsIndeterminate @@ -115,12 +115,7 @@ namespace Avalonia.Controls } } - private void ValueChanged(AvaloniaPropertyChangedEventArgs e) - { - UpdateIndicator(Bounds.Size); - } - - private void IsIndeterminateChanged(AvaloniaPropertyChangedEventArgs e) + private void UpdateIndicatorWhenPropChanged(AvaloniaPropertyChangedEventArgs e) { UpdateIndicator(Bounds.Size); } From 12747f3175b590f6b3796714a2a729e6d6cd99d8 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 15 Sep 2018 12:09:43 +0800 Subject: [PATCH 11/11] Fix missed merge conflict. --- src/Avalonia.Animation/Animator`1.cs | 6 +++--- src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Animation/Animator`1.cs b/src/Avalonia.Animation/Animator`1.cs index 3a30c60e79..d1a8960a10 100644 --- a/src/Avalonia.Animation/Animator`1.cs +++ b/src/Avalonia.Animation/Animator`1.cs @@ -41,7 +41,7 @@ namespace Avalonia.Animation if (!_isVerifiedAndConverted) VerifyConvertKeyFrames(); - var subject = new DisposeAnimationInstanceSubject(this, animation, control, 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) { @@ -89,7 +89,7 @@ namespace Avalonia.Animation var lastFrameData = (lastKeyframe.GetTypedValue(), lastKeyframe.isNeutral); return (intraframeTime, new KeyFramePair(firstFrameData, lastFrameData)); } - + private int FindClosestBeforeKeyFrame(double time) { int FindClosestBeforeKeyFrame(int startIndex, int length) diff --git a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs index 1ac2ac8b98..a535b30b58 100644 --- a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs +++ b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs @@ -23,15 +23,18 @@ namespace Avalonia.Animation private Animation _animation; private Animatable _control; private Action _onComplete; + private IClock _clock; - public DisposeAnimationInstanceSubject(Animator animator, Animation animation, Animatable control, Action onComplete) + 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(); @@ -53,7 +56,7 @@ namespace Avalonia.Animation _lastInstance?.Dispose(); if (matchVal) { - _lastInstance = _animator.Run(_animation, _control, _onComplete); + _lastInstance = _animator.Run(_animation, _control, _clock, _onComplete); } _lastMatch = matchVal; }