-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DRAFT] Add LottieIsland and LottieWinRT for frameworkless or native applications #557
base: main
Are you sure you want to change the base?
Changes from all commits
03637d8
15673a6
f715f7b
7d583f3
2669684
3e107ef
0329c09
9cf356a
567d126
aef4a7c
87525d0
e7a6d2f
381c02d
7263a34
807c32a
8fd5e6b
b41d8fd
66b537b
457d0b7
10d8542
623d418
ddcc1a6
144a389
af22bdc
7201843
95e6616
544cde6
8d9c060
5896c83
9e92f8e
1167c74
b40f53f
9a0ce7c
0840bbb
32e0e81
a542db3
05d2e1f
267afe5
f91bf4d
d8752d4
845f6f3
750f44c
81b8438
eac0dc2
0945863
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework> | ||
<OutputType>Library</OutputType> | ||
<IsPackable>true</IsPackable> | ||
<PackageId>CommunityToolkit.WinUI.Lottie.Controls</PackageId> | ||
<PackageTags>WinUI3 Toolkit Windows Animations Lottie XAML</PackageTags> | ||
|
||
<Nullable>enable</Nullable> | ||
<Platforms>x64;x86;ARM64</Platforms> | ||
<CsWinRTIncludes>Microsoft</CsWinRTIncludes> | ||
<SignAssembly>True</SignAssembly> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.0.4" /> | ||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240428000" /> | ||
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.7" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Lottie-Windows\Lottie-Windows-WinUI3\Lottie-Windows-WinUI3.csproj" /> | ||
</ItemGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
#nullable enable | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.InteropServices.WindowsRuntime; | ||
using System.Threading.Tasks; | ||
using CommunityToolkit.WinAppSDK.LottieIsland; | ||
using CommunityToolkit.WinUI.Lottie; | ||
using Microsoft.UI.Composition; | ||
using Microsoft.UI.Xaml; | ||
using Microsoft.UI.Xaml.Controls; | ||
using Windows.Foundation; | ||
using Windows.Foundation.Metadata; | ||
using Windows.Storage; | ||
using Windows.Storage.Streams; | ||
|
||
namespace CommunityToolkit.WinUI.Lottie.Controls | ||
{ | ||
/// <summary> | ||
/// An <see cref="IAnimatedVisualSource"/> for a Lottie composition. This allows | ||
/// a Lottie to be specified as the source for a <see cref="AnimatedVisualPlayer"/>. | ||
/// </summary> | ||
public sealed class LottieVisualSourceWinUI : DependencyObject, IDynamicAnimatedVisualSource | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having Will they ever both need to be used together though (if they're in different namespaces)? I'm not completely looped into how this all works, but just trying to provide some general guidance when I saw the namespace/class names come up in the discussion. |
||
{ | ||
LottieVisualSource _lottieVisualSource; | ||
|
||
HashSet<TypedEventHandler<IDynamicAnimatedVisualSource?, object?>> _compositionInvalidatedEventTokenTable = new HashSet<TypedEventHandler<IDynamicAnimatedVisualSource?, object?>>(); | ||
|
||
/// <summary> | ||
/// Gets the options for the <see cref="LottieVisualSourceWinUI"/>. | ||
/// </summary> | ||
// Optimize Lotties by default. Optimization takes a little longer but usually produces much | ||
// more efficient translations. The only reason someone would turn optimization off is if | ||
// the time to translate is too high, but in that case the Lottie is probably going to perform | ||
// so badly on the machine that it won't really be usable with our without optimization. | ||
public static DependencyProperty OptionsProperty { get; } = | ||
RegisterDp(nameof(Options), LottieVisualOptions.Optimize); | ||
|
||
/// <summary> | ||
/// Gets the URI from which to load a JSON Lottie file. | ||
/// </summary> | ||
public static DependencyProperty UriSourceProperty { get; } = | ||
RegisterDp<Uri>(nameof(UriSource), null, | ||
(owner, oldValue, newValue) => owner._lottieVisualSource.UriSource = newValue); | ||
|
||
static DependencyProperty RegisterDp<T>(string propertyName, T defaultValue) => | ||
DependencyProperty.Register(propertyName, typeof(T), typeof(LottieVisualSourceWinUI), new PropertyMetadata(defaultValue)); | ||
|
||
static DependencyProperty RegisterDp<T>(string propertyName, T? defaultValue, Action<LottieVisualSourceWinUI, T, T> callback) | ||
where T : class | ||
=> | ||
DependencyProperty.Register(propertyName, typeof(T), typeof(LottieVisualSourceWinUI), | ||
new PropertyMetadata(defaultValue, (d, e) => callback((LottieVisualSourceWinUI)d, (T)e.OldValue, (T)e.NewValue))); | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="LottieVisualSourceWinUI"/> class. | ||
/// </summary> | ||
public LottieVisualSourceWinUI() | ||
{ | ||
_lottieVisualSource = new LottieVisualSource(); | ||
_lottieVisualSource.AnimatedVisualInvalidated += OnAnimatedVisualInvalidated; | ||
} | ||
|
||
public LottieVisualSourceWinUI(LottieVisualSource lottieVisualSource) | ||
{ | ||
_lottieVisualSource = lottieVisualSource; | ||
_lottieVisualSource.AnimatedVisualInvalidated += OnAnimatedVisualInvalidated; | ||
} | ||
|
||
/// <summary> | ||
/// Gets or sets options for how the Lottie is loaded. | ||
/// </summary> | ||
public LottieVisualOptions Options | ||
{ | ||
get => (LottieVisualOptions)GetValue(OptionsProperty); | ||
set => SetValue(OptionsProperty, value); | ||
} | ||
|
||
/// <summary> | ||
/// Gets or sets the Uniform Resource Identifier (URI) of the JSON source file for this <see cref="LottieVisualSourceWinUI"/>. | ||
/// </summary> | ||
public Uri UriSource | ||
{ | ||
get => (Uri)GetValue(UriSourceProperty); | ||
set => SetValue(UriSourceProperty, value); | ||
} | ||
|
||
/// <summary> | ||
/// Called by XAML to convert a string to an <see cref="IAnimatedVisualSource"/>. | ||
/// </summary> | ||
/// <returns>The <see cref="LottieVisualSourceWinUI"/> for the given url.</returns> | ||
public static LottieVisualSourceWinUI? CreateFromString(string uri) | ||
{ | ||
LottieVisualSource? lottieVisualSource = LottieVisualSource.CreateFromString(uri); | ||
if (lottieVisualSource != null) | ||
{ | ||
return new LottieVisualSourceWinUI(lottieVisualSource); | ||
} | ||
else | ||
{ | ||
return new LottieVisualSourceWinUI(); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Sets the source for the <see cref="LottieVisualSourceWinUI"/>. | ||
/// </summary> | ||
/// <param name="stream">A stream containing the text of a JSON Lottie file encoded as UTF-8.</param> | ||
/// <returns>An <see cref="IAsyncAction"/> that completes when the load completes or fails.</returns> | ||
[Overload("SetSourceStreamAsync")] | ||
public IAsyncAction SetSourceAsync(IInputStream stream) | ||
{ | ||
return _lottieVisualSource.SetSourceAsync(stream); | ||
} | ||
|
||
/// <summary> | ||
/// Sets the source for the <see cref="LottieVisualSourceWinUI"/>. | ||
/// </summary> | ||
/// <param name="file">A file that is a JSON Lottie file.</param> | ||
/// <returns>An <see cref="IAsyncAction"/> that completes when the load completes or fails.</returns> | ||
[Overload("SetSourceFileAsync")] | ||
public IAsyncAction SetSourceAsync(StorageFile file) | ||
{ | ||
return _lottieVisualSource.SetSourceAsync(file); | ||
} | ||
|
||
/// <summary> | ||
/// Sets the source for the <see cref="LottieVisualSourceWinUI"/>. | ||
/// </summary> | ||
/// <param name="sourceUri">A URI that refers to a JSON Lottie file.</param> | ||
/// <returns>An <see cref="IAsyncAction"/> that completes when the load completes or fails.</returns> | ||
[DefaultOverload] | ||
[Overload("SetSourceUriAsync")] | ||
public IAsyncAction SetSourceAsync(Uri sourceUri) | ||
{ | ||
return _lottieVisualSource.SetSourceAsync(sourceUri); | ||
} | ||
|
||
/// <summary> | ||
/// Implements <see cref="IDynamicAnimatedVisualSource"/>. | ||
/// </summary> | ||
// TODO: currently explicitly implemented interfaces are causing a problem with .NET Native. Make them implicit for now. | ||
public event TypedEventHandler<IDynamicAnimatedVisualSource?, object?> AnimatedVisualInvalidated | ||
{ | ||
add | ||
{ | ||
_compositionInvalidatedEventTokenTable.Add(value); | ||
} | ||
|
||
remove | ||
{ | ||
_compositionInvalidatedEventTokenTable.Remove(value); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Sets a delegate that returns an <see cref="ICompositionSurface"/> for the given image uri. | ||
/// If this is null, no images will be loaded from references to external images. | ||
/// </summary> | ||
/// <remarks>Most Lottie files do not reference external images, but those that do | ||
/// will refer to the files via a uri. It is up to the user of <see cref="LottieVisualSourceWinUI"/> | ||
/// to manage the loading of the image, and return an <see cref="ICompositionSurface"/> for | ||
/// that image. Alternatively the delegate may return null, and the image will not be | ||
/// displayed.</remarks> | ||
public void SetImageAssetHandler(ImageAssetHandler? imageAssetHandler) | ||
{ | ||
_lottieVisualSource.SetImageAssetHandler(imageAssetHandler); | ||
} | ||
|
||
/// <summary> | ||
/// Implements <see cref="IAnimatedVisualSource"/>. | ||
/// </summary> | ||
/// <param name="compositor">The <see cref="Compositor"/> that can be used as a factory for the resulting <see cref="IAnimatedVisual"/>.</param> | ||
/// <param name="diagnostics">An optional object that may provide extra information about the result.</param> | ||
/// <returns>An <see cref="IAnimatedVisual"/>.</returns> | ||
// TODO: currently explicitly implemented interfaces are causing a problem with .NET Native. Make them implicit for now. | ||
//bool IAnimatedVisualSource.TryCreateAnimatedVisual( | ||
public IAnimatedVisual? TryCreateAnimatedVisual( | ||
Compositor compositor, | ||
out object? diagnostics) | ||
{ | ||
if (_lottieVisualSource is null) | ||
{ | ||
// No content has been loaded yet. | ||
// Return an IAnimatedVisual that produces nothing. | ||
diagnostics = null; | ||
return null; | ||
} | ||
else | ||
{ | ||
// Some content was loaded. Ask the factory to produce an | ||
// IAnimatedVisual. If it returns null, the player will treat it | ||
// as an error. | ||
IAnimatedVisualFrameworkless? animatedVisual = _lottieVisualSource.TryCreateAnimatedVisual(compositor, out diagnostics); | ||
if (animatedVisual != null) | ||
{ | ||
return new LottieVisualWinUI(animatedVisual); | ||
} | ||
else | ||
{ | ||
return null; | ||
} | ||
} | ||
} | ||
|
||
private void OnAnimatedVisualInvalidated(LottieVisualSource? sender, object? args) | ||
{ | ||
foreach (var v in _compositionInvalidatedEventTokenTable) | ||
{ | ||
v.Invoke(this, null); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
#nullable enable | ||
|
||
using System; | ||
using System.Numerics; | ||
using CommunityToolkit.WinAppSDK.LottieIsland; | ||
using Microsoft.UI.Composition; | ||
using Microsoft.UI.Xaml.Controls; | ||
using WinRT; | ||
|
||
namespace CommunityToolkit.WinUI.Lottie.Controls | ||
{ | ||
/// <summary> | ||
/// Simple wrapper to convert an <see cref="IAnimatedVisualFrameworkless"/> to an | ||
/// <see cref="IAnimatedVisual"/> for a Lottie composition. This allows | ||
/// a Lottie to be specified as the source for a <see cref="AnimatedVisualPlayer"/>. | ||
/// </summary> | ||
internal class LottieVisualWinUI : IAnimatedVisual | ||
{ | ||
IAnimatedVisualFrameworkless _animatedVisual; | ||
|
||
internal LottieVisualWinUI(IAnimatedVisualFrameworkless animatedVisual) | ||
{ | ||
_animatedVisual = animatedVisual; | ||
} | ||
|
||
public TimeSpan Duration => _animatedVisual.Duration; | ||
|
||
public Visual RootVisual => _animatedVisual.RootVisual; | ||
|
||
public Vector2 Size => _animatedVisual.Size; | ||
|
||
public void Dispose() | ||
{ | ||
_animatedVisual.As<IDisposable>().Dispose(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're adding new code, would be good to start switching to file-scoped namespaces and reduce indentation.