Browse Source

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

pull/1885/head
Jumar Macato 8 years ago
parent
commit
ee1a8ee30f
No known key found for this signature in database GPG Key ID: B19884DAC3A5BF3F
  1. 7
      src/Avalonia.Animation/AnimationInstance`1.cs
  2. 18
      src/Avalonia.Animation/Animator`1.cs
  3. 62
      src/Avalonia.Animation/DisposeAnimationInstanceObservable.cs
  4. 40
      src/Avalonia.Base/Reactive/DisposeOnNextObservable.cs
  5. 16
      src/Avalonia.Base/Reactive/ObservableEx.cs

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

18
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
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;
}
}
}
}

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()
{
}
}
}

16
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;

Loading…
Cancel
Save