Browse Source

Make a specialized observable for instance lifetime handling. Delete DisposeOnNextObservable.

Jumar Macato 7 years ago
parent
commit
ee1a8ee30f

+ 2 - 5
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();
             }
 

+ 8 - 10
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<T>(this, animation, control, onComplete);
+            return match.Subscribe(subject);
         }
 
         /// <summary>
@@ -96,11 +97,8 @@ namespace Avalonia.Animation
             var lastFrameData = (lastCue.GetTypedValue<T>(), lastCue.isNeutral);
             return (intraframeTime, new KeyFramePair<T>(firstFrameData, lastFrameData));
         }
-
-        /// <summary>
-        /// Runs the KeyFrames Animation.
-        /// </summary>
-        private IDisposable RunKeyFrames(Animation animation, Animatable control, Action onComplete)
+ 
+        internal IDisposable Run(Animation animation, Animatable control, Action onComplete)
         {
             var instance = new AnimationInstance<T>(animation, control, this, onComplete, DoInterpolation);
             return control.Bind<T>((AvaloniaProperty<T>)Property, instance, BindingPriority.Animation);

+ 62 - 0
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
+{
+    /// <summary>
+    /// Manages the lifetime of animation instances as determined by its selector state.
+    /// </summary>
+    internal class DisposeAnimationInstanceObservable<T> : IObserver<bool>, IDisposable
+    {
+        private IDisposable _lastInstance;
+        private bool _lastMatch;
+        private Animator<T> _animator;
+        private Animation _animation;
+        private Animatable _control;
+        private Action _onComplete;
+
+        public DisposeAnimationInstanceObservable(Animator<T> 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<bool>.OnNext(bool matchVal)
+        {
+            if (matchVal != _lastMatch)
+            {
+                _lastInstance?.Dispose();
+                if (matchVal)
+                {
+                    _lastInstance = _animator.RunAnimation(_animation, _control, _onComplete);
+                }
+                _lastMatch = matchVal;
+            }
+        }
+    }
+}

+ 0 - 40
src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs

@@ -1,40 +0,0 @@
-using System;
-using Avalonia.Threading;
-
-namespace Avalonia.Reactive
-{
-    public class DisposeOnNextObservable<T> : LightweightObservableBase<T>, IObserver<T> 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<T>.OnNext(T value)
-        {
-            ValueNext(value);
-        }
- 
-        protected override void Initialize()
-        {
-        }
-
-        protected override void Deinitialize()
-        {
-        }
-    }
-}

+ 1 - 15
src/Avalonia.Base/Reactive/ObservableEx.cs

@@ -21,21 +21,7 @@ namespace Avalonia.Reactive
         {
             return new SingleValueImpl<T>(value);
         }
-
-        /// <summary>
-        /// Disposes the current <see cref="IDisposable"/> and saves the next.
-        /// </summary>
-        /// <typeparam name="T">The type of the value.</typeparam>
-        /// <param name="observable">The source <see cref="IObservable{T}"/>.</param>
-        /// <returns>The observable.</returns>
-        public static IObservable<T> DisposeCurrentOnNext<T>(this IObservable<T> observable)
-            where T : IDisposable
-        {
-            var subject = new DisposeOnNextObservable<T>();
-            observable.Subscribe(subject);
-            return subject;
-        }
-
+ 
         private class SingleValueImpl<T> : IObservable<T>
         {
             private T _value;