diff --git a/src/Avalonia.Animation/AnimationInstance`1.cs b/src/Avalonia.Animation/AnimationInstance`1.cs index eca1942cac..0c7ae9c13c 100644 --- a/src/Avalonia.Animation/AnimationInstance`1.cs +++ b/src/Avalonia.Animation/AnimationInstance`1.cs @@ -56,7 +56,7 @@ namespace Avalonia.Animation if (animation.IterationCount.RepeatType == IterationType.Many) _iterationCount = animation.IterationCount.Value; - + _animationDirection = animation.PlaybackDirection; _fillMode = animation.FillMode; _onCompleteAction = OnComplete; @@ -174,11 +174,13 @@ namespace Avalonia.Animation } else if (playbackTime > iterDuration & playbackTime <= iterationTime & - iterDelay > 0 & - // The last iteration's trailing delay should be skipped. - (_currentIteration + 1) < _iterationCount) + iterDelay > 0) { - DoDelay(); + // The last iteration's trailing delay should be skipped. + if ((_currentIteration + 1) < _iterationCount) + DoDelay(); + else + DoComplete(); } } } diff --git a/tests/Avalonia.Animation.UnitTests/AnimationIterationTests.cs b/tests/Avalonia.Animation.UnitTests/AnimationIterationTests.cs new file mode 100644 index 0000000000..9b59dd4cc9 --- /dev/null +++ b/tests/Avalonia.Animation.UnitTests/AnimationIterationTests.cs @@ -0,0 +1,72 @@ +using System; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Animation; +using Avalonia.Controls; +using Avalonia.Styling; +using Avalonia.UnitTests; +using Avalonia.Data; +using Xunit; + +namespace Avalonia.Animation.UnitTests +{ + public class AnimationIterationTests + { + [Fact] + public void Check_Initial_Inter_and_Trailing_Delay_Values() + { + var keyframe1 = new KeyFrame() + { + new Setter(Border.WidthProperty, 200d), + }; + + var keyframe2 = new KeyFrame() + { + new Setter(Border.WidthProperty, 100d), + }; + + keyframe1.Cue = new Cue(1d); + keyframe2.Cue = new Cue(0d); + + var animation = new Animation() + { + Duration = TimeSpan.FromSeconds(3), + Delay = TimeSpan.FromSeconds(3), + DelayBetweenIterations = TimeSpan.FromSeconds(3), + IterationCount = new IterationCount(2), + Children = + { + keyframe2, + keyframe1 + } + }; + + var border = new Border() + { + Height = 100d, + Width = 100d + }; + + var clock = new TestClock(); + var animationRun = animation.RunAsync(border, clock); + + clock.Step(TimeSpan.Zero); + + // Initial Delay. + clock.Step(TimeSpan.FromSeconds(1)); + Assert.Equal(border.Width, 0d); + + clock.Step(TimeSpan.FromSeconds(6)); + + // First Inter-Iteration delay. + clock.Step(TimeSpan.FromSeconds(8)); + Assert.Equal(border.Width, 200d); + + // Trailing Delay should be non-existent. + clock.Step(TimeSpan.FromSeconds(14)); + Assert.True(animationRun.Status == TaskStatus.RanToCompletion); + Assert.Equal(border.Width, 100d); + } + } +} \ No newline at end of file diff --git a/tests/Avalonia.Animation.UnitTests/Avalonia.Animation.UnitTests.csproj b/tests/Avalonia.Animation.UnitTests/Avalonia.Animation.UnitTests.csproj new file mode 100644 index 0000000000..1b2ba3c7de --- /dev/null +++ b/tests/Avalonia.Animation.UnitTests/Avalonia.Animation.UnitTests.csproj @@ -0,0 +1,25 @@ + + + netcoreapp2.0 + Library + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Avalonia.Animation.UnitTests/Properties/AssemblyInfo.cs b/tests/Avalonia.Animation.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b00c205f10 --- /dev/null +++ b/tests/Avalonia.Animation.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// 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.Reflection; +using Xunit; + +[assembly: AssemblyTitle("Avalonia.Animation.UnitTests")] + +// Don't run tests in parallel. +[assembly: CollectionBehavior(DisableTestParallelization = true)] \ No newline at end of file diff --git a/tests/Avalonia.Animation.UnitTests/TestClock.cs b/tests/Avalonia.Animation.UnitTests/TestClock.cs new file mode 100644 index 0000000000..a1c4ff9277 --- /dev/null +++ b/tests/Avalonia.Animation.UnitTests/TestClock.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +namespace Avalonia.Animation.UnitTests +{ + internal class TestClock : IClock, IDisposable + { + private IObserver _observer; + + public PlayState PlayState { get; set; } = PlayState.Run; + + public void Dispose() + { + _observer?.OnCompleted(); + } + + public void Step(TimeSpan time) + { + _observer?.OnNext(time); + } + + public IDisposable Subscribe(IObserver observer) + { + _observer = observer; + return this; + } + } +} \ No newline at end of file