Skip to content

Commit

Permalink
Improve Window and AnimationManager (#1653)
Browse files Browse the repository at this point in the history
* Improve Window and AnimationManager

* More tweaks

* -

* and that

* fix that

* Lazy

* not readonly

* ??=
  • Loading branch information
mattleibow authored Jul 13, 2021
1 parent 87ce84c commit 6c5b3c7
Show file tree
Hide file tree
Showing 19 changed files with 201 additions and 221 deletions.
9 changes: 0 additions & 9 deletions src/Controls/src/Core/HandlerImpl/Window.Impl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,6 @@ protected override void OnPropertyChanged([CallerMemberName] string? propertyNam
internal IMauiContext MauiContext =>
Handler?.MauiContext ?? throw new InvalidOperationException("MauiContext is null.");

internal IAnimationManager AnimationManager
{
get
{
var handler = Handler as IWindowHandler;
return handler?.AnimationManager ?? throw new InvalidOperationException("The AnimationManager was not provided for this window.");
}
}

IView IWindow.Content =>
Page ?? throw new InvalidOperationException("No page was set on the window.");

Expand Down
10 changes: 8 additions & 2 deletions src/Controls/src/Core/ViewExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Maui.Animations;
using Microsoft.Maui.Graphics;

Expand Down Expand Up @@ -170,8 +171,13 @@ public static Task<bool> TranslateTo(this VisualElement view, double x, double y

internal static IAnimationManager? GetAnimationManager(this IAnimatable animatable)
{
if (animatable is Element e && e.FindParentOfType<Window>(true) is Window window)
return window.AnimationManager;
if (animatable is Element e && e.FindMauiContext() is IMauiContext mauiContext)
{
if (mauiContext is IScopedMauiContext scoped)
return scoped.AnimationManager;
else
return mauiContext.Services.GetService<IAnimationManager>();
}

throw new ArgumentException($"Unable to find {nameof(IAnimationManager)} for '{animatable.GetType().FullName}'.", nameof(animatable));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/tests/Core.UnitTests/AnimationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class AnimationTests : BaseTestFixture
//https://bugzilla.xamarin.com/show_bug.cgi?id=51424
public async Task AnimationRepeats()
{
var box = AnimationReadyWindow.Prepare(new BoxView());
var box = AnimationReadyHandler.Prepare(new BoxView());
Assume.That(box.Rotation, Is.EqualTo(0d));
var sb = new Animation();
var animcount = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/Controls/tests/Core.UnitTests/MotionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void ThrowsWithNullSelf()
[Test]
public void Kinetic()
{
var view = AnimationReadyWindow.Prepare(new View());
var view = AnimationReadyHandler.Prepare(new View());
var resultList = new List<Tuple<double, double>>();
view.AnimateKinetic(
name: "Kinetics",
Expand All @@ -74,7 +74,7 @@ public void Kinetic()
[Test]
public void KineticFinished()
{
var view = AnimationReadyWindow.Prepare(new View());
var view = AnimationReadyHandler.Prepare(new View());
bool finished = false;
view.AnimateKinetic(
name: "Kinetics",
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/tests/Core.UnitTests/ProgressBarTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public void TestClamp()
[Test]
public void TestProgressTo()
{
var bar = AnimationReadyWindow.Prepare(new ProgressBar());
var bar = AnimationReadyHandler.Prepare(new ProgressBar());

bar.ProgressTo(0.8, 250, Easing.Linear);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using System.Threading.Tasks;
using Microsoft.Maui.Animations;
using Microsoft.Maui.Handlers;

namespace Microsoft.Maui.Controls.Core.UnitTests
{
class AnimationReadyHandler : AnimationReadyHandler<BlockingTicker>
{
public AnimationReadyHandler()
: base(new TestAnimationManager(new BlockingTicker()))
{
}
}

class AnimationReadyHandlerAsync : AnimationReadyHandler<AsyncTicker>
{
public AnimationReadyHandlerAsync()
: base(new TestAnimationManager(new AsyncTicker()))
{
}
}

class AnimationReadyHandler<TTicker> : ViewHandler<IView, object>
where TTicker : ITicker, new()
{
public AnimationReadyHandler(IAnimationManager animationManager)
: base(new PropertyMapper<IView>())
{
SetMauiContext(new AnimationReadyMauiContext(animationManager));
}

public static AnimationReadyHandler<TTicker> Prepare<T>(params T[] views)
where T : View
{
var handler = new AnimationReadyHandler<TTicker>(new TestAnimationManager(new TTicker()));

foreach (var view in views)
view.Handler = handler;

return handler;
}

public static T Prepare<T>(T view, out AnimationReadyHandler<TTicker> handler)
where T : View
{
handler = new AnimationReadyHandler<TTicker>(new TestAnimationManager(new TTicker()));

view.Handler = handler;

return view;
}

public static T Prepare<T>(T view)
where T : View
{
view.Handler = new AnimationReadyHandler();

return view;
}

protected override object CreateNativeView() => new();

public IAnimationManager AnimationManager => ((AnimationReadyMauiContext)MauiContext).AnimationManager;

class AnimationReadyMauiContext : IMauiContext, IScopedMauiContext
{
readonly IAnimationManager _animationManager;

public AnimationReadyMauiContext(IAnimationManager manager = null)
{
_animationManager = manager ?? new TestAnimationManager();
}

public IServiceProvider Services => throw new NotImplementedException();

public IMauiHandlersServiceProvider Handlers => throw new NotImplementedException();

public IAnimationManager AnimationManager => _animationManager;
}
}

static class AnimationReadyWindowExtensions
{
public static async Task DisableTicker(this AnimationReadyHandler<AsyncTicker> handler)
{
await Task.Delay(32);

((AsyncTicker)handler.AnimationManager.Ticker).SetEnabled(false);
}

public static async Task EnableTicker(this AnimationReadyHandler<AsyncTicker> handler)
{
await Task.Delay(32);

((AsyncTicker)handler.AnimationManager.Ticker).SetEnabled(true);
}
}
}
116 changes: 0 additions & 116 deletions src/Controls/tests/Core.UnitTests/TestClasses/AnimationReadyWindow.cs

This file was deleted.

28 changes: 12 additions & 16 deletions src/Controls/tests/Core.UnitTests/TickerSystemEnabledTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ async Task SwapFadeViews(View view1, View view2)
[Test, Timeout(3000), Ignore("https://github.com/dotnet/maui/pull/1511")]
public async Task DisablingTickerFinishesAnimationInProgress()
{
var view = AnimationReadyWindowAsync.Prepare(new View { Opacity = 1 }, out var window);
var view = AnimationReadyHandlerAsync.Prepare(new View { Opacity = 1 }, out var handler);

await Task.WhenAll(view.FadeTo(0, 2000), window.DisableTicker());
await Task.WhenAll(view.FadeTo(0, 2000), handler.DisableTicker());

Assert.That(view.Opacity, Is.EqualTo(0));
}
Expand All @@ -40,9 +40,9 @@ public async Task DisablingTickerFinishesAllAnimationsInChain()
var view1 = new View { Opacity = 1 };
var view2 = new View { Opacity = 0 };

var window = new AnimationReadyWindowAsync(view1, view2);
var handler = AnimationReadyHandlerAsync.Prepare(view1, view2);

await Task.WhenAll(SwapFadeViews(view1, view2), window.DisableTicker());
await Task.WhenAll(SwapFadeViews(view1, view2), handler.DisableTicker());

Assert.That(view1.Opacity, Is.EqualTo(0));
}
Expand All @@ -64,19 +64,19 @@ static Task<bool> RepeatFade(View view)
[Test, Timeout(3000), Ignore("https://github.com/dotnet/maui/pull/1511")]
public async Task DisablingTickerPreventsAnimationFromRepeating()
{
var view = AnimationReadyWindowAsync.Prepare(new View { Opacity = 0 }, out var window);
var view = AnimationReadyHandlerAsync.Prepare(new View { Opacity = 0 }, out var handler);

await Task.WhenAll(RepeatFade(view), window.DisableTicker());
await Task.WhenAll(RepeatFade(view), handler.DisableTicker());

Assert.That(view.Opacity, Is.EqualTo(1));
}

[Test]
public async Task NewAnimationsFinishImmediatelyWhenTickerDisabled()
{
var view = AnimationReadyWindowAsync.Prepare(new View(), out var window);
var view = AnimationReadyHandlerAsync.Prepare(new View(), out var handler);

await window.DisableTicker();
await handler.DisableTicker();

await view.RotateYTo(200);

Expand All @@ -86,11 +86,9 @@ public async Task NewAnimationsFinishImmediatelyWhenTickerDisabled()
[Test]
public async Task AnimationExtensionsReturnTrueIfAnimationsDisabled()
{
var window = new AnimationReadyWindowAsync();
var label = AnimationReadyHandlerAsync.Prepare(new Label { Text = "Foo" }, out var handler);

await window.DisableTicker();

var label = window.SetChild(new Label { Text = "Foo" });
await handler.DisableTicker();

var result = await label.ScaleTo(2, 500);

Expand All @@ -100,14 +98,12 @@ public async Task AnimationExtensionsReturnTrueIfAnimationsDisabled()
[Test, Timeout(2000)]
public async Task CanExitAnimationLoopIfAnimationsDisabled()
{
var window = new AnimationReadyWindowAsync();
var label = AnimationReadyHandlerAsync.Prepare(new Label { Text = "Foo" }, out var handler);

await window.DisableTicker();
await handler.DisableTicker();

var run = true;

var label = window.SetChild(new Label { Text = "Foo" });

while (run)
{
await label.ScaleTo(2, 500);
Expand Down
Loading

0 comments on commit 6c5b3c7

Please sign in to comment.