Răsfoiți Sursa

Merge remote-tracking branch 'origin/master' into wpf-winforms-interop-core

# Conflicts:
#	src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
Max Katz 2 ani în urmă
părinte
comite
94e709972b
100 a modificat fișierele cu 401 adăugiri și 328 ștergeri
  1. 5 6
      Avalonia.Desktop.slnf
  2. 1 1
      build/SharedVersion.props
  3. 1 1
      nukebuild/Build.cs
  4. 42 6
      nukebuild/RefAssemblyGenerator.cs
  5. 1 0
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  6. 3 2
      samples/ControlCatalog/MainView.xaml.cs
  7. 2 2
      samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
  8. 1 1
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  9. 1 2
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
  10. 25 4
      samples/ControlCatalog/Pages/TabControlPage.xaml
  11. 1 1
      samples/GpuInterop/MainWindow.axaml.cs
  12. 1 1
      samples/IntegrationTestApp/MainWindow.axaml.cs
  13. 0 21
      samples/MobileSandbox.Desktop/MobileSandbox.Desktop.csproj
  14. 0 15
      samples/MobileSandbox/MobileSandbox.csproj
  15. 1 1
      samples/RenderDemo/MainWindow.xaml.cs
  16. 0 4
      samples/RenderDemo/Pages/AnimationsPage.xaml
  17. 0 15
      samples/RenderDemo/Pages/AnimationsPage.xaml.cs
  18. 10 2
      samples/RenderDemo/Pages/CustomAnimatorPage.xaml
  19. 3 2
      samples/RenderDemo/Pages/CustomStringAnimator.cs
  20. 0 3
      samples/RenderDemo/Pages/Transform3DPage.axaml
  21. 0 4
      samples/RenderDemo/Pages/TransitionsPage.xaml
  22. 0 15
      samples/RenderDemo/Pages/TransitionsPage.xaml.cs
  23. 1 0
      samples/Sandbox/Sandbox.csproj
  24. 1 6
      src/Android/Avalonia.Android/AndroidPlatform.cs
  25. 2 2
      src/Android/Avalonia.Android/AvaloniaView.cs
  26. 1 1
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  27. 92 81
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  28. 2 2
      src/Avalonia.Base/Animation/Animatable.cs
  29. 17 10
      src/Avalonia.Base/Animation/Animation.cs
  30. 4 5
      src/Avalonia.Base/Animation/AnimatorDrivenTransition.cs
  31. 1 1
      src/Avalonia.Base/Animation/AnimatorKeyFrame.cs
  32. 2 4
      src/Avalonia.Base/Animation/AnimatorTransitionObservable.cs
  33. 1 1
      src/Avalonia.Base/Animation/Animators/Animator`1.cs
  34. 1 1
      src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs
  35. 1 1
      src/Avalonia.Base/Animation/Animators/BoolAnimator.cs
  36. 1 1
      src/Avalonia.Base/Animation/Animators/BoxShadowAnimator.cs
  37. 1 1
      src/Avalonia.Base/Animation/Animators/BoxShadowsAnimator.cs
  38. 1 1
      src/Avalonia.Base/Animation/Animators/ByteAnimator.cs
  39. 1 1
      src/Avalonia.Base/Animation/Animators/ColorAnimator.cs
  40. 1 1
      src/Avalonia.Base/Animation/Animators/CornerRadiusAnimator.cs
  41. 1 1
      src/Avalonia.Base/Animation/Animators/DecimalAnimator.cs
  42. 1 1
      src/Avalonia.Base/Animation/Animators/DoubleAnimator.cs
  43. 1 1
      src/Avalonia.Base/Animation/Animators/FloatAnimator.cs
  44. 1 1
      src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
  45. 1 1
      src/Avalonia.Base/Animation/Animators/Int16Animator.cs
  46. 1 1
      src/Avalonia.Base/Animation/Animators/Int32Animator.cs
  47. 1 1
      src/Avalonia.Base/Animation/Animators/Int64Animator.cs
  48. 1 1
      src/Avalonia.Base/Animation/Animators/PointAnimator.cs
  49. 1 1
      src/Avalonia.Base/Animation/Animators/RectAnimator.cs
  50. 1 1
      src/Avalonia.Base/Animation/Animators/RelativePointAnimator.cs
  51. 1 1
      src/Avalonia.Base/Animation/Animators/SizeAnimator.cs
  52. 1 1
      src/Avalonia.Base/Animation/Animators/SolidColorBrushAnimator.cs
  53. 1 1
      src/Avalonia.Base/Animation/Animators/ThicknessAnimator.cs
  54. 1 1
      src/Avalonia.Base/Animation/Animators/TransformAnimator.cs
  55. 1 1
      src/Avalonia.Base/Animation/Animators/TransformOperationsAnimator.cs
  56. 1 1
      src/Avalonia.Base/Animation/Animators/UInt16Animator.cs
  57. 1 1
      src/Avalonia.Base/Animation/Animators/UInt32Animator.cs
  58. 1 1
      src/Avalonia.Base/Animation/Animators/UInt64Animator.cs
  59. 1 1
      src/Avalonia.Base/Animation/Animators/VectorAnimator.cs
  60. 4 1
      src/Avalonia.Base/Animation/Clock.cs
  61. 1 1
      src/Avalonia.Base/Animation/ClockBase.cs
  62. 3 0
      src/Avalonia.Base/Animation/Easings/IEasing.cs
  63. 0 5
      src/Avalonia.Base/Animation/Easings/SpringEasing.cs
  64. 2 2
      src/Avalonia.Base/Animation/IAnimation.cs
  65. 1 1
      src/Avalonia.Base/Animation/IAnimationSetter.cs
  66. 1 2
      src/Avalonia.Base/Animation/IAnimator.cs
  67. 1 2
      src/Avalonia.Base/Animation/IClock.cs
  68. 30 0
      src/Avalonia.Base/Animation/ICustomAnimator.cs
  69. 1 2
      src/Avalonia.Base/Animation/IGlobalClock.cs
  70. 2 2
      src/Avalonia.Base/Animation/ITransition.cs
  71. 1 1
      src/Avalonia.Base/Animation/KeyFrame.cs
  72. 1 1
      src/Avalonia.Base/Animation/KeyFrames.cs
  73. 1 1
      src/Avalonia.Base/Animation/KeySpline.cs
  74. 0 26
      src/Avalonia.Base/Animation/RenderLoopClock.cs
  75. 1 1
      src/Avalonia.Base/Animation/Spring.cs
  76. 1 1
      src/Avalonia.Base/Animation/SpringTypeConverter.cs
  77. 5 2
      src/Avalonia.Base/Animation/Transition.cs
  78. 3 3
      src/Avalonia.Base/Animation/TransitionObservableBase.cs
  79. 1 1
      src/Avalonia.Base/Animation/Transitions.cs
  80. 5 1
      src/Avalonia.Base/Animation/Transitions/BoxShadowsTransition.cs
  81. 1 1
      src/Avalonia.Base/Animation/Transitions/BrushTransition.cs
  82. 5 2
      src/Avalonia.Base/Animation/Transitions/ColorTransition.cs
  83. 6 1
      src/Avalonia.Base/Animation/Transitions/CornerRadiusTransition.cs
  84. 4 1
      src/Avalonia.Base/Animation/Transitions/DoubleTransition.cs
  85. 4 1
      src/Avalonia.Base/Animation/Transitions/FloatTransition.cs
  86. 4 1
      src/Avalonia.Base/Animation/Transitions/IntegerTransition.cs
  87. 4 1
      src/Avalonia.Base/Animation/Transitions/PointTransition.cs
  88. 4 1
      src/Avalonia.Base/Animation/Transitions/RelativePointTransition.cs
  89. 4 1
      src/Avalonia.Base/Animation/Transitions/SizeTransition.cs
  90. 4 1
      src/Avalonia.Base/Animation/Transitions/ThicknessTransition.cs
  91. 1 1
      src/Avalonia.Base/Animation/Transitions/TransformOperationsTransition.cs
  92. 4 1
      src/Avalonia.Base/Animation/Transitions/VectorTransition.cs
  93. 4 0
      src/Avalonia.Base/AvaloniaLocator.cs
  94. 31 6
      src/Avalonia.Base/Data/TemplateBinding.cs
  95. 2 2
      src/Avalonia.Base/Input/AccessKeyHandler.cs
  96. 2 0
      src/Avalonia.Base/Input/DragDropDevice.cs
  97. 1 1
      src/Avalonia.Base/Input/IInputDevice.cs
  98. 1 1
      src/Avalonia.Base/Input/IInputManager.cs
  99. 1 0
      src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs
  100. 1 1
      src/Avalonia.Base/Input/IMainMenu.cs

+ 5 - 6
Avalonia.Desktop.slnf

@@ -39,14 +39,13 @@
       "src\\Markup\\Avalonia.Markup.Xaml\\Avalonia.Markup.Xaml.csproj",
       "src\\Markup\\Avalonia.Markup\\Avalonia.Markup.csproj",
       "src\\Skia\\Avalonia.Skia\\Avalonia.Skia.csproj",
-      "src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
-      "src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
-      "src\\tools\\DevAnalyzers\\DevAnalyzers.csproj",
-      "src\\tools\\DevGenerators\\DevGenerators.csproj",
-      "src\\tools\\PublicAnalyzers\\Avalonia.Analyzers.csproj",
       "src\\Windows\\Avalonia.Direct2D1\\Avalonia.Direct2D1.csproj",
       "src\\Windows\\Avalonia.Win32.Interop\\Avalonia.Win32.Interop.csproj",
       "src\\Windows\\Avalonia.Win32\\Avalonia.Win32.csproj",
+      "src\\tools\\Avalonia.Analyzers\\Avalonia.Analyzers.csproj",
+      "src\\tools\\Avalonia.Generators\\Avalonia.Generators.csproj",
+      "src\\tools\\DevAnalyzers\\DevAnalyzers.csproj",
+      "src\\tools\\DevGenerators\\DevGenerators.csproj",
       "tests\\Avalonia.Base.UnitTests\\Avalonia.Base.UnitTests.csproj",
       "tests\\Avalonia.Benchmarks\\Avalonia.Benchmarks.csproj",
       "tests\\Avalonia.Controls.DataGrid.UnitTests\\Avalonia.Controls.DataGrid.UnitTests.csproj",
@@ -66,4 +65,4 @@
       "tests\\Avalonia.UnitTests\\Avalonia.UnitTests.csproj"
     ]
   }
-}
+}

+ 1 - 1
build/SharedVersion.props

@@ -4,7 +4,7 @@
     <Product>Avalonia</Product>
     <Version>11.0.999</Version>
     <Authors>Avalonia Team</Authors>
-    <Copyright>Copyright 2022 &#169; The AvaloniaUI Project</Copyright>
+    <Copyright>Copyright 2013-$([System.DateTime]::Now.ToString(`yyyy`)) &#169; The AvaloniaUI Project</Copyright>
     <PackageProjectUrl>https://avaloniaui.net</PackageProjectUrl>
     <RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>

+ 1 - 1
nukebuild/Build.cs

@@ -312,7 +312,7 @@ partial class Build : NukeBuild
 
     public static int Main() =>
         RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
-            ? Execute<Build>(x => x.RunToolsTests)
+            ? Execute<Build>(x => x.Package)
             : Execute<Build>(x => x.RunTests);
 
 }

+ 42 - 6
nukebuild/RefAssemblyGenerator.cs

@@ -71,10 +71,10 @@ public class RefAssemblyGenerator
         foreach (var nested in type.NestedTypes)
             ProcessType(nested, obsoleteCtor);
 
-        var hideMethods = (type.IsInterface && type.Name.EndsWith("Impl"))
+        var hideMembers = (type.IsInterface && type.Name.EndsWith("Impl"))
                           || HasPrivateApi(type.CustomAttributes);
 
-        var injectMethod = hideMethods
+        var injectMethod = hideMembers
                            || type.CustomAttributes.Any(a =>
                                a.AttributeType.FullName == "Avalonia.Metadata.NotClientImplementableAttribute");
 
@@ -95,21 +95,57 @@ public class RefAssemblyGenerator
 
         foreach (var m in type.Methods)
         {
-            if (hideMethods || HasPrivateApi(m.CustomAttributes))
+            if (hideMembers || HasPrivateApi(m.CustomAttributes))
             {
-                var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem |
-                             MethodAttributes.FamANDAssem | MethodAttributes.Assembly;
-                m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly;
+                HideMethod(m);
             }
             MarkAsUnstable(m, obsoleteCtor, forceUnstable);
         }
 
+        foreach (var p in type.Properties)
+        {
+            if (HasPrivateApi(p.CustomAttributes))
+            {
+                if (p.SetMethod != null)
+                    HideMethod(p.SetMethod);
+                if (p.GetMethod != null)
+                    HideMethod(p.GetMethod);
+            }
+        }
+
+        foreach (var f in type.Fields)
+        {
+            if (hideMembers || HasPrivateApi(f.CustomAttributes))
+            {
+                var dflags = FieldAttributes.Public | FieldAttributes.Family | FieldAttributes.FamORAssem |
+                             FieldAttributes.FamANDAssem | FieldAttributes.Assembly;
+                f.Attributes = ((f.Attributes | dflags) ^ dflags) | FieldAttributes.Assembly;
+            }
+        }
+
+        foreach (var cl in type.NestedTypes)
+        {
+            ProcessType(cl, obsoleteCtor);
+            if (hideMembers)
+            {
+                var dflags = TypeAttributes.Public;
+                cl.Attributes = ((cl.Attributes | dflags) ^ dflags) | TypeAttributes.NotPublic;
+            }
+        }
+
         foreach (var m in type.Properties)
             MarkAsUnstable(m, obsoleteCtor, forceUnstable);
         foreach (var m in type.Events)
             MarkAsUnstable(m, obsoleteCtor, forceUnstable);
     }
 
+    static void HideMethod(MethodDefinition m)
+    {
+        var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem |
+                     MethodAttributes.FamANDAssem | MethodAttributes.Assembly;
+        m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly;
+    }
+    
     static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, ICustomAttribute unstableAttribute)
     {
         if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))

+ 1 - 0
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@@ -16,6 +16,7 @@
 
   <ItemGroup>
     <Compile Include="..\..\src\Avalonia.X11\NativeDialogs\Gtk.cs" Link="NativeControls\Gtk\Gtk.cs" />
+    <Compile Include="..\..\src\Avalonia.Base\Platform\Interop\Utf8Buffer.cs" Link="NativeControls\Utf8Buffer.cs" />
   </ItemGroup>
 
   <ItemGroup>

+ 3 - 2
samples/ControlCatalog/MainView.xaml.cs

@@ -83,9 +83,10 @@ namespace ControlCatalog
                 if (transparencyLevels.SelectedItem is WindowTransparencyLevel selected)
                 {
                     var topLevel = (TopLevel)this.GetVisualRoot()!;
-                    topLevel.TransparencyLevelHint = selected;
+                    topLevel.TransparencyLevelHint = new[] { selected };
 
-                    if (selected != WindowTransparencyLevel.None)
+                    if (topLevel.ActualTransparencyLevel != WindowTransparencyLevel.None &&
+                        topLevel.ActualTransparencyLevel == selected)
                     {
                         var transparentBrush = new ImmutableSolidColorBrush(Colors.White, 0);
                         var semiTransparentBrush = new ImmutableSolidColorBrush(Colors.Gray, 0.2);

+ 2 - 2
samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs

@@ -19,8 +19,8 @@ namespace ControlCatalog.Pages
             customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel);
 
             var cancellableContextBorder = this.Get<Border>("CancellableContextBorder");
-            cancellableContextBorder.ContextMenu!.ContextMenuClosing += ContextFlyoutPage_Closing;
-            cancellableContextBorder.ContextMenu!.ContextMenuOpening += ContextFlyoutPage_Opening;
+            cancellableContextBorder.ContextMenu!.Closing += ContextFlyoutPage_Closing;
+            cancellableContextBorder.ContextMenu!.Opening += ContextFlyoutPage_Opening;
         }
 
         private ContextPageViewModel? _model;

+ 1 - 1
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@@ -307,7 +307,7 @@ namespace ControlCatalog.Pages
             Content:
             ";
 
-                        resultText += await ReadTextFromFile(file, 10000);
+                        resultText += await ReadTextFromFile(file, 500);
                     }
 
                     openedFileContent.Text = resultText;

+ 1 - 2
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs

@@ -117,9 +117,8 @@ namespace ControlCatalog.Pages
         private void ScrollTo(int index)
         {
             System.Diagnostics.Debug.WriteLine("Scroll to " + index);
-            var layoutManager = ((TopLevel)VisualRoot!).LayoutManager;
             var element = _repeater.GetOrCreateElement(index);
-            layoutManager.ExecuteLayoutPass();
+            ((TopLevel)VisualRoot!).UpdateLayout();
             element.BringIntoView();
         }
 

+ 25 - 4
samples/ControlCatalog/Pages/TabControlPage.xaml

@@ -4,7 +4,27 @@
     xmlns="https://github.com/avaloniaui"
     xmlns:viewModels="using:ControlCatalog.ViewModels"
     x:DataType="viewModels:TabControlPageViewModel">
-    <DockPanel>
+    <DockPanel Classes.WithContentTemplates="{Binding IsChecked, ElementName=UseContentTemplates}">
+        <DockPanel.Styles>
+            <Style Selector="DockPanel.WithContentTemplates">
+                <Style Selector="^ TabItem">
+                    <Setter Property="ContentTemplate">
+                        <DataTemplate x:CompileBindings="False">
+                            <Border BorderBrush="Red" BorderThickness="10">
+                                <ContentPresenter Content="{Binding}"/>
+                            </Border>
+                        </DataTemplate>
+                    </Setter>
+                </Style>
+                <Style Selector="^ TabControl">
+                    <Setter Property="ContentTemplate">
+                        <DataTemplate>
+                            <TextBlock Text="This template should be overriden by each TabItem's template."/>
+                        </DataTemplate>
+                    </Setter>
+                </Style>
+            </Style>
+        </DockPanel.Styles>
         <TextBlock 
             DockPanel.Dock="Top" 
             Classes="h2"
@@ -55,14 +75,14 @@
                     Margin="0 16"
                     DisplayMemberBinding="{Binding Header, x:DataType=viewModels:TabControlPageViewModelItem}"
                     TabStripPlacement="{Binding TabPlacement}">
-                    <TabControl.ContentTemplate>
+                    <TabControl.DataTemplates>
                         <DataTemplate x:DataType="viewModels:TabControlPageViewModelItem">
                             <StackPanel Orientation="Vertical" Spacing="8">
                                 <TextBlock Text="{Binding Text}"/>
                                 <Image Source="{Binding Image}" Width="300"/>
                             </StackPanel>
                         </DataTemplate>
-                    </TabControl.ContentTemplate>
+                    </TabControl.DataTemplates>
                     <TabControl.Styles>
                         <Style Selector="TabItem" x:DataType="viewModels:TabControlPageViewModelItem">
                             <Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
@@ -78,12 +98,13 @@
                 HorizontalAlignment="Center"
                 VerticalAlignment="Center">
                 <TextBlock VerticalAlignment="Center">Tab Placement:</TextBlock>
-                <ComboBox SelectedIndex="{Binding TabPlacement, Mode=TwoWay}">
+                <ComboBox SelectedIndex="{Binding TabPlacement, Mode=TwoWay}" Width="100">
                     <ComboBoxItem>Left</ComboBoxItem>
                     <ComboBoxItem>Bottom</ComboBoxItem>
                     <ComboBoxItem>Right</ComboBoxItem>
                     <ComboBoxItem>Top</ComboBoxItem>
                 </ComboBox>
+                <CheckBox Name="UseContentTemplates">Set TabItem.ContentTemplate</CheckBox>
             </StackPanel>
         </Grid>
     </DockPanel>

+ 1 - 1
samples/GpuInterop/MainWindow.axaml.cs

@@ -11,7 +11,7 @@ namespace GpuInterop
         {
             InitializeComponent();
             this.AttachDevTools();
-            Renderer.Diagnostics.DebugOverlays = RendererDebugOverlays.Fps;
+            RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps;
         }
 
         private void InitializeComponent()

+ 1 - 1
samples/IntegrationTestApp/MainWindow.axaml.cs

@@ -136,7 +136,7 @@ namespace IntegrationTestApp
                 Name = "TransparentWindow",
                 SystemDecorations = SystemDecorations.None,
                 Background = Brushes.Transparent,
-                TransparencyLevelHint = WindowTransparencyLevel.Transparent,
+                TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent },
                 WindowStartupLocation = WindowStartupLocation.CenterOwner,
                 Width = 200,
                 Height = 200,

+ 0 - 21
samples/MobileSandbox.Desktop/MobileSandbox.Desktop.csproj

@@ -4,37 +4,16 @@
     <OutputType>WinExe</OutputType>
     <TargetFramework>net6.0</TargetFramework>
     <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
-    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-  </PropertyGroup>
-
-  <PropertyGroup Condition="'$(RunNativeAotCompilation)' == 'true'">
-    <IlcTrimMetadata>true</IlcTrimMetadata>
-    <RestoreAdditionalProjectSources>https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json</RestoreAdditionalProjectSources>
-    <NativeAotCompilerVersion>7.0.0-*</NativeAotCompilerVersion>
   </PropertyGroup>
 
-  <ItemGroup>
-    <Compile Include="..\..\src\Avalonia.X11\NativeDialogs\Gtk.cs" Link="NativeControls\Gtk\Gtk.cs" />
-  </ItemGroup>
-
   <ItemGroup>
     <ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
-    <ProjectReference Include="..\..\src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
     <ProjectReference Include="..\..\src\Avalonia.Dialogs\Avalonia.Dialogs.csproj" />
-    <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
     <ProjectReference Include="..\MobileSandbox\MobileSandbox.csproj" />
-    <ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
     <!-- For native controls test -->
     <PackageReference Include="MonoMac.NetStandard" Version="0.0.4" />
   </ItemGroup>
 
-  <ItemGroup Condition="'$(RunNativeAotCompilation)' == 'true'">
-    <PackageReference Include="Microsoft.DotNet.ILCompiler" Version="$(NativeAotCompilerVersion)" />
-    <!-- Cross-compilation for Windows x64-arm64 and Linux x64-arm64 -->
-    <PackageReference Condition="'$(RuntimeIdentifier)'=='win-arm64'" Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="$(NativeAotCompilerVersion)" />
-    <PackageReference Condition="'$(RuntimeIdentifier)'=='linux-arm64'" Include="runtime.linux-x64.Microsoft.DotNet.ILCompiler" Version="$(NativeAotCompilerVersion)" />
-  </ItemGroup>
-
   <PropertyGroup>
     <!-- For Microsoft.CodeAnalysis -->
     <SatelliteResourceLanguages>en</SatelliteResourceLanguages>

+ 0 - 15
samples/MobileSandbox/MobileSandbox.csproj

@@ -14,9 +14,6 @@
     <AvaloniaResource Include="Assets\*" />
     <AvaloniaResource Include="Assets\Fonts\*" />
   </ItemGroup>
-  <ItemGroup>
-    <None Remove="Pages\NativeEmbedPage.xaml" />
-  </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Assets\Fonts\SourceSansPro-Bold.ttf" />
     <EmbeddedResource Include="Assets\Fonts\SourceSansPro-BoldItalic.ttf" />
@@ -34,17 +31,5 @@
     <ProjectReference Include="..\SampleControls\ControlSamples.csproj" />
   </ItemGroup>
 
-  <ItemGroup>
-    <AvaloniaResource Update="Pages\NativeEmbedPage.xaml">
-      <Generator>MSBuild:Compile</Generator>
-    </AvaloniaResource>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Compile Update="Pages\NativeEmbedPage.xaml.cs">
-      <DependentUpon>%(Filename)</DependentUpon>
-    </Compile>
-  </ItemGroup>
-
   <Import Project="..\..\build\BuildTargets.targets" />
 </Project>

+ 1 - 1
samples/RenderDemo/MainWindow.xaml.cs

@@ -21,7 +21,7 @@ namespace RenderDemo
             void BindOverlay(Expression<Func<MainWindowViewModel, bool>> expr, RendererDebugOverlays overlay)
                 => vm.WhenAnyValue(expr).Subscribe(x =>
                 {
-                    var diagnostics = Renderer.Diagnostics;
+                    var diagnostics = RendererDiagnostics;
                     diagnostics.DebugOverlays = x ?
                         diagnostics.DebugOverlays | overlay :
                         diagnostics.DebugOverlays & ~overlay;

+ 0 - 4
samples/RenderDemo/Pages/AnimationsPage.xaml

@@ -347,12 +347,8 @@
   </UserControl.Styles>
   <Grid>
     <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="False">
-      <StackPanel.Clock>
-        <Clock />
-      </StackPanel.Clock>
       <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Spacing="20">
         <TextBlock VerticalAlignment="Center">Hover to activate Keyframe Animations.</TextBlock>
-        <Button Content="{Binding PlayStateText}" Command="{Binding TogglePlayState}" Click="ToggleClock" />
       </StackPanel>
       <WrapPanel ClipToBounds="False">
         <Border Classes="Test Rect1" Background="DarkRed"/>

+ 0 - 15
samples/RenderDemo/Pages/AnimationsPage.xaml.cs

@@ -24,20 +24,5 @@ namespace RenderDemo.Pages
         {
             AvaloniaXamlLoader.Load(this);
         }
-
-        private void ToggleClock(object sender, RoutedEventArgs args)
-        {
-            var button = sender as Button;
-            var clock = button.Clock;
-
-            if (clock.PlayState == PlayState.Run)
-            {
-                clock.PlayState = PlayState.Pause;
-            }
-            else if (clock.PlayState == PlayState.Pause)
-            {
-                clock.PlayState = PlayState.Run;
-            }
-        }
     }
 }

+ 10 - 2
samples/RenderDemo/Pages/CustomAnimatorPage.xaml

@@ -11,10 +11,18 @@
           <Style.Animations>
             <Animation Duration="0:0:1" IterationCount="Infinite">
               <KeyFrame Cue="0%">
-                <Setter Property="Text" Value="" Animation.Animator="{x:Type pages:CustomStringAnimator}"/>
+                <Setter Property="Text" Value="">
+                  <Animation.Animator>
+                    <pages:CustomStringAnimator/>
+                  </Animation.Animator>
+                </Setter>
               </KeyFrame>
               <KeyFrame Cue="100%">
-                <Setter Property="Text" Value="0123456789" Animation.Animator="{x:Type pages:CustomStringAnimator}"/>
+                <Setter Property="Text" Value="0123456789" >
+                  <Animation.Animator>
+                    <pages:CustomStringAnimator/>
+                  </Animation.Animator>
+                </Setter>
               </KeyFrame>
             </Animation>
           </Style.Animations>

+ 3 - 2
samples/RenderDemo/Pages/CustomStringAnimator.cs

@@ -1,8 +1,9 @@
-using Avalonia.Animation.Animators;
+using Avalonia.Animation;
+using Avalonia.Animation.Animators;
 
 namespace RenderDemo.Pages
 {
-    public class CustomStringAnimator : Animator<string>
+    public class CustomStringAnimator : CustomAnimatorBase<string>
     {
         public override string Interpolate(double progress, string oldValue, string newValue)
         {

+ 0 - 3
samples/RenderDemo/Pages/Transform3DPage.axaml

@@ -134,9 +134,6 @@
     </UserControl.Styles>
 
     <Grid ColumnDefinitions="Auto,*,Auto,*" RowDefinitions="*, Auto, Auto, Auto, Auto, Auto, Auto, Auto">
-        <Grid.Clock>
-            <Clock />
-        </Grid.Clock>
         <Border Name="B1" Background="DarkRed" Classes="Test">
             <Border.RenderTransform>
                 <Rotate3DTransform CenterZ="-100"

+ 0 - 4
samples/RenderDemo/Pages/TransitionsPage.xaml

@@ -248,12 +248,8 @@
 
   <Grid>
     <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="False">
-      <StackPanel.Clock>
-        <Clock />
-      </StackPanel.Clock>
       <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Spacing="20">
         <TextBlock VerticalAlignment="Center">Hover to activate Transitions.</TextBlock>
-        <Button Content="{Binding PlayStateText}" Command="{Binding TogglePlayState}" Click="ToggleClock" />
       </StackPanel>
       <WrapPanel ClipToBounds="False">
         <Border Classes="Test Rect1" Background="DarkRed"/>

+ 0 - 15
samples/RenderDemo/Pages/TransitionsPage.xaml.cs

@@ -18,20 +18,5 @@ namespace RenderDemo.Pages
         {
             AvaloniaXamlLoader.Load(this);
         }
-
-        private void ToggleClock(object sender, RoutedEventArgs args)
-        {
-            var button = sender as Button;
-            var clock = button.Clock;
-
-            if (clock.PlayState == PlayState.Run)
-            {
-                clock.PlayState = PlayState.Pause;
-            }
-            else if (clock.PlayState == PlayState.Pause)
-            {
-                clock.PlayState = PlayState.Run;
-            }
-        }
     }
 }

+ 1 - 0
samples/Sandbox/Sandbox.csproj

@@ -5,6 +5,7 @@
     <TargetFramework>net6.0</TargetFramework>
     <TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
     <IncludeAvaloniaGenerators>true</IncludeAvaloniaGenerators>
+<!--    <AvaloniaXamlIlDebuggerLaunch>true</AvaloniaXamlIlDebuggerLaunch>-->
   </PropertyGroup>
 
   <ItemGroup>

+ 1 - 6
src/Android/Avalonia.Android/AndroidPlatform.cs

@@ -45,7 +45,6 @@ namespace Avalonia.Android
                 .Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
                 .Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoaderStub>()
                 .Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
-                .Bind<IRenderLoop>().ToConstant(new RenderLoop())
                 .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
 
             if (Options.UseGpu)
@@ -53,11 +52,7 @@ namespace Avalonia.Android
                 EglPlatformGraphics.TryInitialize();
             }
             
-            Compositor = new Compositor(
-                AvaloniaLocator.Current.GetRequiredService<IRenderLoop>(),
-                AvaloniaLocator.Current.GetService<IPlatformGraphics>());
-            
-
+            Compositor = new Compositor(AvaloniaLocator.Current.GetService<IPlatformGraphics>());
         }
     }
 

+ 2 - 2
src/Android/Avalonia.Android/AvaloniaView.cs

@@ -67,7 +67,7 @@ namespace Avalonia.Android
                     _timerSubscription = timer.SubscribeView(this);
                 }
 
-                _root.Renderer.Start();
+                _root.StartRendering();
 
                 if (_view.TryGetFeature<IInsetsManager>(out var insetsManager) == true)
                 {
@@ -76,7 +76,7 @@ namespace Avalonia.Android
             }
             else
             {
-                _root.Renderer.Stop();
+                _root.StopRendering();
                 _timerSubscription?.Dispose();
             }
         }

+ 1 - 1
src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@@ -10,7 +10,7 @@ using Avalonia.Platform;
 
 namespace Avalonia.Android
 {
-    internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformNativeSurfaceHandle
+    internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, INativePlatformHandleSurface
     {
         bool _invalidateQueued;
         readonly object _lock = new object();

+ 92 - 81
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Runtime.Versioning;
 using Android.App;
 using Android.Content;
 using Android.Graphics;
@@ -45,6 +46,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
         private readonly AndroidInsetsManager _insetsManager;
         private readonly ClipboardImpl _clipboard;
         private ViewImpl _view;
+        private WindowTransparencyLevel _transparencyLevel;
 
         public TopLevelImpl(AvaloniaView avaloniaView, bool placeOnTop = false)
         {
@@ -68,6 +70,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
 
             _nativeControlHost = new AndroidNativeControlHostImpl(avaloniaView);
             _storageProvider = new AndroidStorageProvider((Activity)avaloniaView.Context);
+            _transparencyLevel = WindowTransparencyLevel.None;
 
             _systemNavigationManager = new AndroidSystemNavigationManagerImpl(avaloniaView.Context as IActivityNavigationService);
         }
@@ -103,9 +106,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
 
         public IEnumerable<object> Surfaces => new object[] { _gl, _framebuffer, Handle };
 
-        public IRenderer CreateRenderer(IRenderRoot root) =>
-            new CompositingRenderer(root, AndroidPlatform.Compositor, () => Surfaces);
-
+        public Compositor Compositor => AndroidPlatform.Compositor;
+        
         public virtual void Hide()
         {
             _view.Visibility = ViewStates.Invisible;
@@ -274,7 +276,18 @@ namespace Avalonia.Android.Platform.SkiaPlatform
         public Action LostFocus { get; set; }
         public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; }
 
-        public WindowTransparencyLevel TransparencyLevel { get; private set; }
+        public WindowTransparencyLevel TransparencyLevel 
+        {
+            get => _transparencyLevel;
+            private set
+            {
+                if (_transparencyLevel != value)
+                {
+                    _transparencyLevel = value;
+                    TransparencyLevelChanged?.Invoke(value);
+                }
+            }
+        }
 
         public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
         {
@@ -299,91 +312,64 @@ namespace Avalonia.Android.Platform.SkiaPlatform
 
         public double Scaling => RenderScaling;
 
-        public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
+        public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels)
         {
-            if (TransparencyLevel != transparencyLevel)
+            if (_view.Context is not AvaloniaMainActivity activity)
+                return;
+
+            foreach (var level in transparencyLevels)
             {
-                bool isBelowR = Build.VERSION.SdkInt < BuildVersionCodes.R;
-                bool isAboveR = Build.VERSION.SdkInt > BuildVersionCodes.R;
-                if (_view.Context is AvaloniaMainActivity activity)
+                if (!IsSupported(level))
+                {
+                    continue;
+                }
+
+                if (level == TransparencyLevel)
+                {
+                    return;
+                }
+
+                if (level == WindowTransparencyLevel.None)
+                {
+                    if (OperatingSystem.IsAndroidVersionAtLeast(30))
+                    {
+                        activity.SetTranslucent(false);
+                    }
+
+                    activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.White));
+                }
+                else if (level == WindowTransparencyLevel.Transparent)
+                {
+                    if (OperatingSystem.IsAndroidVersionAtLeast(30))
+                    {
+                        activity.SetTranslucent(true);
+                        SetBlurBehind(activity, 0);
+                        activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
+                    }
+                }
+                else if (level == WindowTransparencyLevel.Blur)
                 {
-                    switch (transparencyLevel)
+                    if (OperatingSystem.IsAndroidVersionAtLeast(31))
                     {
-                        case WindowTransparencyLevel.AcrylicBlur:
-                        case WindowTransparencyLevel.ForceAcrylicBlur:
-                        case WindowTransparencyLevel.Mica:
-                        case WindowTransparencyLevel.None:
-                            if (!isBelowR)
-                            {
-                                activity.SetTranslucent(false);
-                            }
-                            if (isAboveR)
-                            {
-                                activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
-
-                                var attr = activity.Window?.Attributes;
-                                if (attr != null)
-                                {
-                                    attr.BlurBehindRadius = 0;
-
-                                    activity.Window.Attributes = attr;
-                                }
-                            }
-                            activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
-
-                            if(transparencyLevel != WindowTransparencyLevel.None)
-                            {
-                                return;
-                            }
-                            break;
-                        case WindowTransparencyLevel.Transparent:
-                            if (!isBelowR)
-                            {
-                                activity.SetTranslucent(true);
-                            }
-                            if (isAboveR)
-                            {
-                                activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
-
-                                var attr = activity.Window?.Attributes;
-                                if (attr != null)
-                                {
-                                    attr.BlurBehindRadius = 0;
-
-                                    activity.Window.Attributes = attr;
-                                }
-                            }
-                            activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
-                            break;
-                        case WindowTransparencyLevel.Blur:
-                            if (isAboveR)
-                            {
-                                activity.SetTranslucent(true);
-                                activity.Window?.AddFlags(WindowManagerFlags.BlurBehind);
-
-                                var attr = activity.Window?.Attributes;
-                                if (attr != null)
-                                {
-                                    attr.BlurBehindRadius = 120;
-
-                                    activity.Window.Attributes = attr;
-                                }
-                                activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
-                            }
-                            else
-                            {
-                                activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
-                                activity.Window.SetBackgroundDrawable(new ColorDrawable(Color.White));
-
-                                return;
-                            }
-                            break;
+                        activity.SetTranslucent(true);
+                        SetBlurBehind(activity, 120);
+                        activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
                     }
-                    TransparencyLevel = transparencyLevel;
                 }
+
+                TransparencyLevel = level;
+                return;
             }
+
+            // If we get here, we didn't find a supported level. Use the default of None.
+            if (OperatingSystem.IsAndroidVersionAtLeast(30))
+            {
+                activity.SetTranslucent(false);
+            }
+
+            activity.Window?.SetBackgroundDrawable(new ColorDrawable(Color.White));
         }
-        
+
         public virtual object TryGetFeature(Type featureType)
         {
             if (featureType == typeof(IStorageProvider))
@@ -418,6 +404,31 @@ namespace Avalonia.Android.Platform.SkiaPlatform
 
             return null;
         }
+
+        private static bool IsSupported(WindowTransparencyLevel level)
+        {
+            if (level == WindowTransparencyLevel.None)
+                return true;
+            if (level == WindowTransparencyLevel.Transparent)
+                return OperatingSystem.IsAndroidVersionAtLeast(30);
+            if (level == WindowTransparencyLevel.Blur)
+                return OperatingSystem.IsAndroidVersionAtLeast(31);
+            return false;
+        }
+
+        private static void SetBlurBehind(AvaloniaMainActivity activity, int radius)
+        {
+            if (radius == 0)
+                activity.Window?.ClearFlags(WindowManagerFlags.BlurBehind);
+            else
+                activity.Window?.AddFlags(WindowManagerFlags.BlurBehind);
+
+            if (OperatingSystem.IsAndroidVersionAtLeast(31) && activity.Window?.Attributes is { } attr)
+            {
+                attr.BlurBehindRadius = radius;
+                activity.Window.Attributes = attr;
+            }
+        }
     }
 
     internal class AvaloniaInputConnection : BaseInputConnection

+ 2 - 2
src/Avalonia.Base/Animation/Animatable.cs

@@ -17,7 +17,7 @@ namespace Avalonia.Animation
         /// <summary>
         /// Defines the <see cref="Clock"/> property.
         /// </summary>
-        public static readonly StyledProperty<IClock> ClockProperty =
+        internal static readonly StyledProperty<IClock> ClockProperty =
             AvaloniaProperty.Register<Animatable, IClock>(nameof(Clock), inherits: true);
 
         /// <summary>
@@ -36,7 +36,7 @@ namespace Avalonia.Animation
         /// <summary>
         /// Gets or sets the clock which controls the animations on the control.
         /// </summary>
-        public IClock Clock
+        internal IClock Clock
         {
             get => GetValue(ClockProperty);
             set => SetValue(ClockProperty, value);

+ 17 - 10
src/Avalonia.Base/Animation/Animation.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Animation
     /// <summary>
     /// Tracks the progress of an animation.
     /// </summary>
-    public class Animation : AvaloniaObject, IAnimation
+    public sealed class Animation : AvaloniaObject, IAnimation
     {
         /// <summary>
         /// Defines the <see cref="Duration"/> property.
@@ -186,7 +186,7 @@ namespace Avalonia.Animation
         /// </summary>
         /// <param name="setter">The animation setter.</param>
         /// <returns>The property animator type.</returns>
-        public static (Type Type, Func<IAnimator> Factory)? GetAnimator(IAnimationSetter setter)
+        internal static (Type Type, Func<IAnimator> Factory)? GetAnimator(IAnimationSetter setter)
         {
             if (s_animators.TryGetValue(setter, out var type))
             {
@@ -200,11 +200,9 @@ namespace Avalonia.Animation
         /// </summary>
         /// <param name="setter">The animation setter.</param>
         /// <param name="value">The property animator value.</param>
-        public static void SetAnimator(IAnimationSetter setter,
-            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicMethods)]
-            Type value)
+        public static void SetAnimator(IAnimationSetter setter, CustomAnimatorBase value)
         {
-            s_animators[setter] = (value, () => (IAnimator)Activator.CreateInstance(value)!);
+            s_animators[setter] = (value.WrapperType, value.CreateWrapper);
         }
 
         private readonly static List<(Func<AvaloniaProperty, bool> Condition, Type Animator, Func<IAnimator> Factory)> Animators = new()
@@ -233,7 +231,7 @@ namespace Avalonia.Animation
         /// <typeparam name="TAnimator">
         /// The type of the animator to instantiate.
         /// </typeparam>
-        public static void RegisterAnimator<TAnimator>(Func<AvaloniaProperty, bool> condition)
+        internal static void RegisterAnimator<TAnimator>(Func<AvaloniaProperty, bool> condition)
             where TAnimator : IAnimator, new()
         {
             Animators.Insert(0, (condition, typeof(TAnimator), () => new TAnimator()));
@@ -312,8 +310,11 @@ namespace Avalonia.Animation
             return (newAnimatorInstances, subscriptions);
         }
 
+        IDisposable IAnimation.Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
+            => Apply(control, clock, match, onComplete);
+        
         /// <inheritdoc/>
-        public IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
+        internal IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete)
         {
             var (animators, subscriptions) = InterpretKeyframes(control);
             if (animators.Count == 1)
@@ -358,14 +359,20 @@ namespace Avalonia.Animation
             return new CompositeDisposable(subscriptions);
         }
 
+        public Task RunAsync(Animatable control, CancellationToken cancellationToken = default) =>
+            RunAsync(control, null, cancellationToken);
+        
         /// <inheritdoc/>
-        public Task RunAsync(Animatable control, IClock? clock = null)
+        internal Task RunAsync(Animatable control, IClock? clock)
         {
             return RunAsync(control, clock, default);
         }
 
+        Task IAnimation.RunAsync(Animatable control, IClock? clock, CancellationToken cancellationToken)
+            => RunAsync(control, clock, cancellationToken);
+        
         /// <inheritdoc/>
-        public Task RunAsync(Animatable control, IClock? clock = null, CancellationToken cancellationToken = default)
+        internal Task RunAsync(Animatable control, IClock? clock, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
             {

+ 4 - 5
src/Avalonia.Base/Animation/AnimatorDrivenTransition.cs

@@ -1,5 +1,6 @@
 using System;
 using Avalonia.Animation.Animators;
+using Avalonia.Animation.Easings;
 
 namespace Avalonia.Animation
 {
@@ -8,13 +9,11 @@ namespace Avalonia.Animation
     /// </summary>
     /// <typeparam name="T">Type of the transitioned value.</typeparam>
     /// <typeparam name="TAnimator">Type of the animator.</typeparam>
-    public abstract class AnimatorDrivenTransition<T, TAnimator> : Transition<T> where TAnimator : Animator<T>, new()
+    internal static class AnimatorDrivenTransition<T, TAnimator> where TAnimator : Animator<T>, new()
     {
         private static readonly TAnimator s_animator = new TAnimator();
 
-        public override IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue)
-        {
-            return new AnimatorTransitionObservable<T, TAnimator>(s_animator, progress, Easing, oldValue, newValue);
-        }
+        public static IObservable<T> Transition(IEasing easing, IObservable<double> progress, T oldValue, T newValue) =>
+            new AnimatorTransitionObservable<T, TAnimator>(s_animator, progress, easing, oldValue, newValue);
     }
 }

+ 1 - 1
src/Avalonia.Base/Animation/AnimatorKeyFrame.cs

@@ -11,7 +11,7 @@ namespace Avalonia.Animation
     /// Defines a KeyFrame that is used for
     /// <see cref="Animator{T}"/> objects.
     /// </summary>
-    public class AnimatorKeyFrame : AvaloniaObject
+    internal class AnimatorKeyFrame : AvaloniaObject
     {
         public static readonly DirectProperty<AnimatorKeyFrame, object?> ValueProperty =
             AvaloniaProperty.RegisterDirect<AnimatorKeyFrame, object?>(nameof(Value), k => k.Value, (k, v) => k.Value = v);

+ 2 - 4
src/Avalonia.Base/Animation/AnimatorTransitionObservable.cs

@@ -9,17 +9,15 @@ namespace Avalonia.Animation
     /// </summary>
     /// <typeparam name="T">Type of the transitioned value.</typeparam>
     /// <typeparam name="TAnimator">Type of the animator.</typeparam>
-    public class AnimatorTransitionObservable<T, TAnimator> : TransitionObservableBase<T> where TAnimator : Animator<T>
+    internal class AnimatorTransitionObservable<T, TAnimator> : TransitionObservableBase<T> where TAnimator : Animator<T>
     {
         private readonly TAnimator _animator;
-        private readonly Easing _easing;
         private readonly T _oldValue;
         private readonly T _newValue;
 
-        public AnimatorTransitionObservable(TAnimator animator, IObservable<double> progress, Easing easing, T oldValue, T newValue) : base(progress, easing)
+        public AnimatorTransitionObservable(TAnimator animator, IObservable<double> progress, IEasing easing, T oldValue, T newValue) : base(progress, easing)
         {
             _animator = animator;
-            _easing = easing;
             _oldValue = oldValue;
             _newValue = newValue;
         }

+ 1 - 1
src/Avalonia.Base/Animation/Animators/Animator`1.cs

@@ -11,7 +11,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Base class for <see cref="Animator{T}"/> objects
     /// </summary>
-    public abstract class Animator<T> : AvaloniaList<AnimatorKeyFrame>, IAnimator
+    internal abstract class Animator<T> : AvaloniaList<AnimatorKeyFrame>, IAnimator
     {
         /// <summary>
         /// List of type-converted keyframes.

+ 1 - 1
src/Avalonia.Base/Animation/Animators/BaseBrushAnimator.cs

@@ -15,7 +15,7 @@ namespace Avalonia.Animation.Animators
     /// redirect them to the properly registered
     /// animators in this class.
     /// </summary>
-    public class BaseBrushAnimator : Animator<IBrush?>
+    internal class BaseBrushAnimator : Animator<IBrush?>
     {
         private static readonly List<(Func<Type, bool> Match, Type AnimatorType, Func<IAnimator> AnimatorFactory)> _brushAnimators = new();
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/BoolAnimator.cs

@@ -3,7 +3,7 @@
     /// <summary>
     /// Animator that handles <see cref="bool"/> properties.
     /// </summary>
-    public class BoolAnimator : Animator<bool>
+    internal class BoolAnimator : Animator<bool>
     {
         /// <inheritdocs/>
         public override bool Interpolate(double progress, bool oldValue, bool newValue)

+ 1 - 1
src/Avalonia.Base/Animation/Animators/BoxShadowAnimator.cs

@@ -2,7 +2,7 @@ using Avalonia.Media;
 
 namespace Avalonia.Animation.Animators
 {
-    public class BoxShadowAnimator : Animator<BoxShadow>
+    internal class BoxShadowAnimator : Animator<BoxShadow>
     {
         static ColorAnimator s_colorAnimator = new ColorAnimator();
         static DoubleAnimator s_doubleAnimator = new DoubleAnimator();

+ 1 - 1
src/Avalonia.Base/Animation/Animators/BoxShadowsAnimator.cs

@@ -2,7 +2,7 @@ using Avalonia.Media;
 
 namespace Avalonia.Animation.Animators
 {
-    public class BoxShadowsAnimator :  Animator<BoxShadows>
+    internal class BoxShadowsAnimator : Animator<BoxShadows>
     {
         private static readonly BoxShadowAnimator s_boxShadowAnimator = new BoxShadowAnimator();
         public override BoxShadows Interpolate(double progress, BoxShadows oldValue, BoxShadows newValue)

+ 1 - 1
src/Avalonia.Base/Animation/Animators/ByteAnimator.cs

@@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="byte"/> properties.
     /// </summary>
-    public class ByteAnimator : Animator<byte>
+    internal class ByteAnimator : Animator<byte>
     {
         const double maxVal = (double)byte.MaxValue;
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/ColorAnimator.cs

@@ -12,7 +12,7 @@ namespace Avalonia.Animation.Animators
     /// Animator that interpolates <see cref="Color"/> through 
     /// gamma sRGB color space for better visual result.
     /// </summary>
-    public class ColorAnimator : Animator<Color>
+    internal class ColorAnimator : Animator<Color>
     {
         /// <summary>
         /// Opto-electronic conversion function for the sRGB color space.

+ 1 - 1
src/Avalonia.Base/Animation/Animators/CornerRadiusAnimator.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="CornerRadius"/> properties.
     /// </summary>
-    public class CornerRadiusAnimator : Animator<CornerRadius>
+    internal class CornerRadiusAnimator : Animator<CornerRadius>
     {
         public override CornerRadius Interpolate(double progress, CornerRadius oldValue, CornerRadius newValue)
         {

+ 1 - 1
src/Avalonia.Base/Animation/Animators/DecimalAnimator.cs

@@ -3,7 +3,7 @@
     /// <summary>
     /// Animator that handles <see cref="decimal"/> properties.
     /// </summary>
-    public class DecimalAnimator : Animator<decimal>
+    internal class DecimalAnimator : Animator<decimal>
     {
         /// <inheritdocs/>
         public override decimal Interpolate(double progress, decimal oldValue, decimal newValue)

+ 1 - 1
src/Avalonia.Base/Animation/Animators/DoubleAnimator.cs

@@ -3,7 +3,7 @@
     /// <summary>
     /// Animator that handles <see cref="double"/> properties.
     /// </summary>
-    public class DoubleAnimator : Animator<double>
+    internal class DoubleAnimator : Animator<double>
     {
         /// <inheritdocs/>
         public override double Interpolate(double progress, double oldValue, double newValue)

+ 1 - 1
src/Avalonia.Base/Animation/Animators/FloatAnimator.cs

@@ -3,7 +3,7 @@
     /// <summary>
     /// Animator that handles <see cref="float"/> properties.
     /// </summary>
-    public class FloatAnimator : Animator<float>
+    internal class FloatAnimator : Animator<float>
     {
         /// <inheritdocs/>
         public override float Interpolate(double progress, float oldValue, float newValue)

+ 1 - 1
src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs

@@ -13,7 +13,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="SolidColorBrush"/> values. 
     /// </summary>
-    public class GradientBrushAnimator : Animator<IGradientBrush?>
+    internal class GradientBrushAnimator : Animator<IGradientBrush?>
     {
         private static readonly RelativePointAnimator s_relativePointAnimator = new RelativePointAnimator();
         private static readonly DoubleAnimator s_doubleAnimator = new DoubleAnimator();

+ 1 - 1
src/Avalonia.Base/Animation/Animators/Int16Animator.cs

@@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="Int16"/> properties.
     /// </summary>
-    public class Int16Animator : Animator<Int16>
+    internal class Int16Animator : Animator<Int16>
     {
         const double maxVal = (double)Int16.MaxValue;
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/Int32Animator.cs

@@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="Int32"/> properties.
     /// </summary>
-    public class Int32Animator : Animator<Int32>
+    internal class Int32Animator : Animator<Int32>
     {
         const double maxVal = (double)Int32.MaxValue;
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/Int64Animator.cs

@@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="Int64"/> properties.
     /// </summary>
-    public class Int64Animator : Animator<Int64>
+    internal class Int64Animator : Animator<Int64>
     {
         const double maxVal = (double)Int64.MaxValue;
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/PointAnimator.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="Point"/> properties.
     /// </summary>
-    public class PointAnimator : Animator<Point>
+    internal class PointAnimator : Animator<Point>
     {
         public override Point Interpolate(double progress, Point oldValue, Point newValue)
         { 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/RectAnimator.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="Rect"/> properties.
     /// </summary>
-    public class RectAnimator : Animator<Rect>
+    internal class RectAnimator : Animator<Rect>
     {
         public override Rect Interpolate(double progress, Rect oldValue, Rect newValue)
         {

+ 1 - 1
src/Avalonia.Base/Animation/Animators/RelativePointAnimator.cs

@@ -3,7 +3,7 @@
     /// <summary>
     /// Animator that handles <see cref="RelativePoint"/> properties.
     /// </summary>
-    public class RelativePointAnimator : Animator<RelativePoint>
+    internal class RelativePointAnimator : Animator<RelativePoint>
     {
         private static readonly PointAnimator s_pointAnimator = new PointAnimator();
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/SizeAnimator.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="Size"/> properties.
     /// </summary>
-    public class SizeAnimator : Animator<Size>
+    internal class SizeAnimator : Animator<Size>
     {
         public override Size Interpolate(double progress, Size oldValue, Size newValue)
         {

+ 1 - 1
src/Avalonia.Base/Animation/Animators/SolidColorBrushAnimator.cs

@@ -10,7 +10,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="SolidColorBrush"/> values. 
     /// </summary>
-    public class ISolidColorBrushAnimator : Animator<ISolidColorBrush?>
+    internal class ISolidColorBrushAnimator : Animator<ISolidColorBrush?>
     {
         private static readonly DoubleAnimator s_doubleAnimator = new DoubleAnimator();
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/ThicknessAnimator.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="Thickness"/> properties.
     /// </summary>
-    public class ThicknessAnimator : Animator<Thickness>
+    internal class ThicknessAnimator : Animator<Thickness>
     {
         public override Thickness Interpolate(double progress, Thickness oldValue, Thickness newValue)
         {

+ 1 - 1
src/Avalonia.Base/Animation/Animators/TransformAnimator.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="Transform"/> properties.
     /// </summary>
-    public class TransformAnimator : Animator<double>
+    internal class TransformAnimator : Animator<double>
     {
         DoubleAnimator? _doubleAnimator;
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/TransformOperationsAnimator.cs

@@ -4,7 +4,7 @@ using Avalonia.Media.Transformation;
 
 namespace Avalonia.Animation.Animators
 {
-    public class TransformOperationsAnimator : Animator<TransformOperations>
+    internal class TransformOperationsAnimator : Animator<TransformOperations>
     {
         public TransformOperationsAnimator()
         {

+ 1 - 1
src/Avalonia.Base/Animation/Animators/UInt16Animator.cs

@@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="UInt16"/> properties.
     /// </summary>
-    public class UInt16Animator : Animator<UInt16>
+    internal class UInt16Animator : Animator<UInt16>
     {
         const double maxVal = (double)UInt16.MaxValue;
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/UInt32Animator.cs

@@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="UInt32"/> properties.
     /// </summary>
-    public class UInt32Animator : Animator<UInt32>
+    internal class UInt32Animator : Animator<UInt32>
     {
         const double maxVal = (double)UInt32.MaxValue;
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/UInt64Animator.cs

@@ -5,7 +5,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="UInt64"/> properties.
     /// </summary>
-    public class UInt64Animator : Animator<UInt64>
+    internal class UInt64Animator : Animator<UInt64>
     {
         const double maxVal = (double)UInt64.MaxValue;
 

+ 1 - 1
src/Avalonia.Base/Animation/Animators/VectorAnimator.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Animation.Animators
     /// <summary>
     /// Animator that handles <see cref="Vector"/> properties.
     /// </summary>
-    public class VectorAnimator : Animator<Vector>
+    internal class VectorAnimator : Animator<Vector>
     {
         public override Vector Interpolate(double progress, Vector oldValue, Vector newValue)
         {

+ 4 - 1
src/Avalonia.Base/Animation/Clock.cs

@@ -3,7 +3,10 @@ using Avalonia.Reactive;
 
 namespace Avalonia.Animation
 {
-    public class Clock : ClockBase
+    // Note: this class was always broken: it subscribes to the global clock immediately even it if
+    // doesn't actually have subscriptions
+    
+    internal class Clock : ClockBase
     {
         public static IClock GlobalClock => AvaloniaLocator.Current.GetRequiredService<IGlobalClock>();
 

+ 1 - 1
src/Avalonia.Base/Animation/ClockBase.cs

@@ -3,7 +3,7 @@ using Avalonia.Reactive;
 
 namespace Avalonia.Animation
 {
-    public class ClockBase : IClock
+    internal class ClockBase : IClock
     {
         private readonly ClockObservable _observable;
 

+ 3 - 0
src/Avalonia.Base/Animation/Easings/IEasing.cs

@@ -1,8 +1,11 @@
+using Avalonia.Metadata;
+
 namespace Avalonia.Animation.Easings
 {
     /// <summary>
     /// Defines the interface for easing classes.
     /// </summary>
+    [NotClientImplementable]
     public interface IEasing
     {
         /// <summary>

+ 0 - 5
src/Avalonia.Base/Animation/Easings/SpringEasing.cs

@@ -64,11 +64,6 @@ public class SpringEasing : Easing
         Damping = damping;
         InitialVelocity = initialVelocity;
     }
-
-    public SpringEasing(Spring keySpline)
-    {
-        _internalSpring = keySpline;
-    }
     
     public SpringEasing()
     {

+ 2 - 2
src/Avalonia.Base/Animation/IAnimation.cs

@@ -14,11 +14,11 @@ namespace Avalonia.Animation
         /// <summary>
         /// Apply the animation to the specified control and run it when <paramref name="match" /> produces <c>true</c>.
         /// </summary>
-        IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete = null);
+        internal IDisposable Apply(Animatable control, IClock? clock, IObservable<bool> match, Action? onComplete = null);
 
         /// <summary>
         /// Run the animation on the specified control.
         /// </summary>
-        Task RunAsync(Animatable control, IClock clock, CancellationToken cancellationToken = default);
+        internal Task RunAsync(Animatable control, IClock clock, CancellationToken cancellationToken = default);
     }
 }

+ 1 - 1
src/Avalonia.Base/Animation/IAnimationSetter.cs

@@ -2,7 +2,7 @@ using Avalonia.Metadata;
 
 namespace Avalonia.Animation
 {
-    [NotClientImplementable]
+    [NotClientImplementable, PrivateApi]
     public interface IAnimationSetter
     {
         AvaloniaProperty? Property { get; set; }

+ 1 - 2
src/Avalonia.Base/Animation/IAnimator.cs

@@ -7,8 +7,7 @@ namespace Avalonia.Animation
     /// <summary>
     /// Interface for Animator objects
     /// </summary>
-    [NotClientImplementable]
-    public interface IAnimator : IList<AnimatorKeyFrame>
+    internal interface IAnimator : IList<AnimatorKeyFrame>
     {
         /// <summary>
         /// The target property.

+ 1 - 2
src/Avalonia.Base/Animation/IClock.cs

@@ -3,8 +3,7 @@ using Avalonia.Metadata;
 
 namespace Avalonia.Animation
 {
-    [NotClientImplementable]
-    public interface IClock : IObservable<TimeSpan>
+    internal interface IClock : IObservable<TimeSpan>
     {
         PlayState PlayState { get; set; }
     }

+ 30 - 0
src/Avalonia.Base/Animation/ICustomAnimator.cs

@@ -0,0 +1,30 @@
+using System;
+using Avalonia.Animation.Animators;
+
+namespace Avalonia.Animation;
+
+public abstract class CustomAnimatorBase
+{
+    internal abstract IAnimator CreateWrapper();
+    internal abstract Type WrapperType { get; }
+}
+
+public abstract class CustomAnimatorBase<T> : CustomAnimatorBase
+{
+    public abstract T Interpolate(double progress, T oldValue, T newValue);
+
+    internal override Type WrapperType => typeof(AnimatorWrapper);
+    internal override IAnimator CreateWrapper() => new AnimatorWrapper(this);
+
+    internal class AnimatorWrapper : Animator<T>
+    {
+        private readonly CustomAnimatorBase<T> _parent;
+
+        public AnimatorWrapper(CustomAnimatorBase<T> parent)
+        {
+            _parent = parent;
+        }
+        
+        public override T Interpolate(double progress, T oldValue, T newValue) => _parent.Interpolate(progress, oldValue, newValue);
+    }
+}

+ 1 - 2
src/Avalonia.Base/Animation/IGlobalClock.cs

@@ -2,8 +2,7 @@ using Avalonia.Metadata;
 
 namespace Avalonia.Animation
 {
-    [NotClientImplementable]
-    public interface IGlobalClock : IClock
+    internal interface IGlobalClock : IClock
     {
     }
 }

+ 2 - 2
src/Avalonia.Base/Animation/ITransition.cs

@@ -6,13 +6,13 @@ namespace Avalonia.Animation
     /// <summary>
     /// Interface for Transition objects.
     /// </summary>
-    [NotClientImplementable]
+    [NotClientImplementable, PrivateApi]
     public interface ITransition
     {
         /// <summary>
         /// Applies the transition to the specified <see cref="Animatable"/>.
         /// </summary>
-        IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);
+        internal IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue);
 
         /// <summary>
         /// Gets the property to be animated.

+ 1 - 1
src/Avalonia.Base/Animation/KeyFrame.cs

@@ -15,7 +15,7 @@ namespace Avalonia.Animation
     /// Stores data regarding a specific key
     /// point and value in an animation.
     /// </summary>
-    public class KeyFrame : AvaloniaObject
+    public sealed class KeyFrame : AvaloniaObject
     {
         private TimeSpan _ktimeSpan;
         private Cue _kCue;

+ 1 - 1
src/Avalonia.Base/Animation/KeyFrames.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Animation
     /// <summary>
     /// A collection of <see cref="KeyFrame"/>s.
     /// </summary>
-    public class KeyFrames : AvaloniaList<KeyFrame>
+    public sealed class KeyFrames : AvaloniaList<KeyFrame>
     {
         /// <summary>
         /// Initializes a new instance of the <see cref="KeyFrames"/> class.

+ 1 - 1
src/Avalonia.Base/Animation/KeySpline.cs

@@ -17,7 +17,7 @@ namespace Avalonia.Animation
     /// See https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.animation.keyspline
     /// </summary>
     [TypeConverter(typeof(KeySplineTypeConverter))]
-    public class KeySpline : AvaloniaObject
+    public sealed class KeySpline : AvaloniaObject
     {
         // Control points
         private double _controlPointX1;

+ 0 - 26
src/Avalonia.Base/Animation/RenderLoopClock.cs

@@ -1,26 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Avalonia.Rendering;
-
-namespace Avalonia.Animation
-{
-    public class RenderLoopClock : ClockBase, IRenderLoopTask, IGlobalClock
-    {
-        protected override void Stop()
-        {
-            AvaloniaLocator.Current.GetRequiredService<IRenderLoop>().Remove(this);
-        }
-
-        bool IRenderLoopTask.NeedsUpdate => HasSubscriptions;
-
-        void IRenderLoopTask.Render()
-        {
-        }
-
-        void IRenderLoopTask.Update(TimeSpan time)
-        {
-            Pulse(time);
-        }
-    }
-}

+ 1 - 1
src/Avalonia.Base/Animation/Spring.cs

@@ -10,7 +10,7 @@ namespace Avalonia.Animation;
 /// Determines how an animation is used based on spring formula.
 /// </summary>
 [TypeConverter(typeof(SpringTypeConverter))]
-public class Spring
+internal class Spring
 {
     private SpringSolver _springSolver;
     private double _mass;

+ 1 - 1
src/Avalonia.Base/Animation/SpringTypeConverter.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Animation;
 /// <summary>
 /// Converts string values to <see cref="Spring"/> values.
 /// </summary>
-public class SpringTypeConverter : TypeConverter
+internal class SpringTypeConverter : TypeConverter
 {
     public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
     {

+ 5 - 2
src/Avalonia.Base/Animation/Transition.cs

@@ -53,10 +53,13 @@ namespace Avalonia.Animation
         /// <summary>
         /// Apply interpolation to the property.
         /// </summary>
-        public abstract IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue);
+        internal abstract IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue);
 
         /// <inheritdocs/>
-        public virtual IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
+        IDisposable ITransition.Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
+            => Apply(control, clock, oldValue, newValue);
+        
+        internal virtual IDisposable Apply(Animatable control, IClock clock, object? oldValue, object? newValue)
         {
             if (Property is null)
                 throw new InvalidOperationException("Transition has no property specified.");

+ 3 - 3
src/Avalonia.Base/Animation/TransitionObservableBase.cs

@@ -10,13 +10,13 @@ namespace Avalonia.Animation
     /// Provides base for observables implementing transitions.
     /// </summary>
     /// <typeparam name="T">Type of the transitioned value.</typeparam>
-    public abstract class TransitionObservableBase<T> : SingleSubscriberObservableBase<T>, IObserver<double>
+    internal abstract class TransitionObservableBase<T> : SingleSubscriberObservableBase<T>, IObserver<double>
     {
-        private readonly Easing _easing;
+        private readonly IEasing _easing;
         private readonly IObservable<double> _progress;
         private IDisposable? _progressSubscription;
 
-        protected TransitionObservableBase(IObservable<double> progress, Easing easing)
+        protected TransitionObservableBase(IObservable<double> progress, IEasing easing)
         {
             _progress = progress;
             _easing = easing;

+ 1 - 1
src/Avalonia.Base/Animation/Transitions.cs

@@ -7,7 +7,7 @@ namespace Avalonia.Animation
     /// <summary>
     /// A collection of <see cref="ITransition"/> definitions.
     /// </summary>
-    public class Transitions : AvaloniaList<ITransition>
+    public sealed class Transitions : AvaloniaList<ITransition>
     {
         /// <summary>
         /// Initializes a new instance of the <see cref="Transitions"/> class.

+ 5 - 1
src/Avalonia.Base/Animation/Transitions/BoxShadowsTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 using Avalonia.Media;
 
@@ -6,7 +7,10 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="BoxShadows"/> type.
     /// </summary>  
-    public class BoxShadowsTransition : AnimatorDrivenTransition<BoxShadows, BoxShadowsAnimator>
+    public class BoxShadowsTransition : Transition<BoxShadows>
     {
+        internal override IObservable<BoxShadows> DoTransition(IObservable<double> progress, BoxShadows oldValue,
+            BoxShadows newValue) =>
+            AnimatorDrivenTransition<BoxShadows, BoxShadowsAnimator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 1 - 1
src/Avalonia.Base/Animation/Transitions/BrushTransition.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Animation
         private static readonly GradientBrushAnimator s_gradientAnimator = new GradientBrushAnimator();
         private static readonly ISolidColorBrushAnimator s_solidColorBrushAnimator = new ISolidColorBrushAnimator();
 
-        public override IObservable<IBrush?> DoTransition(IObservable<double> progress, IBrush? oldValue, IBrush? newValue)
+        internal override IObservable<IBrush?> DoTransition(IObservable<double> progress, IBrush? oldValue, IBrush? newValue)
         {
             if (oldValue is null || newValue is null)
             {

+ 5 - 2
src/Avalonia.Base/Animation/Transitions/ColorTransition.cs

@@ -1,4 +1,5 @@
-using Avalonia.Animation.Animators;
+using System;
+using Avalonia.Animation.Animators;
 using Avalonia.Media;
 
 namespace Avalonia.Animation
@@ -6,7 +7,9 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="Color"/> type.
     /// </summary>
-    public class ColorTransition : AnimatorDrivenTransition<Color, ColorAnimator>
+    public class ColorTransition : Transition<Color>
     {
+        internal override IObservable<Color> DoTransition(IObservable<double> progress, Color oldValue, Color newValue)
+            => AnimatorDrivenTransition<Color, ColorAnimator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 6 - 1
src/Avalonia.Base/Animation/Transitions/CornerRadiusTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 
 namespace Avalonia.Animation
@@ -5,7 +6,11 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="CornerRadius"/> type.
     /// </summary>  
-    public class CornerRadiusTransition : AnimatorDrivenTransition<CornerRadius, CornerRadiusAnimator>
+    public class CornerRadiusTransition : Transition<CornerRadius>
     {
+        internal override IObservable<CornerRadius> DoTransition(IObservable<double> progress, CornerRadius oldValue,
+            CornerRadius newValue) =>
+            AnimatorDrivenTransition<CornerRadius, CornerRadiusAnimator>.Transition(Easing, progress, oldValue,
+                newValue);
     }
 }

+ 4 - 1
src/Avalonia.Base/Animation/Transitions/DoubleTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 
 namespace Avalonia.Animation
@@ -5,7 +6,9 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="double"/> types.
     /// </summary>  
-    public class DoubleTransition : AnimatorDrivenTransition<double, DoubleAnimator>
+    public class DoubleTransition : Transition<double>
     {
+        internal override IObservable<double> DoTransition(IObservable<double> progress, double oldValue, double newValue) => 
+            AnimatorDrivenTransition<double, DoubleAnimator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 4 - 1
src/Avalonia.Base/Animation/Transitions/FloatTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 
 namespace Avalonia.Animation
@@ -5,7 +6,9 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="float"/> types.
     /// </summary>  
-    public class FloatTransition : AnimatorDrivenTransition<float, FloatAnimator>
+    public class FloatTransition : Transition<float>
     {
+        internal override IObservable<float> DoTransition(IObservable<double> progress, float oldValue, float newValue) => 
+            AnimatorDrivenTransition<float, FloatAnimator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 4 - 1
src/Avalonia.Base/Animation/Transitions/IntegerTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 
 namespace Avalonia.Animation
@@ -5,7 +6,9 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="int"/> types.
     /// </summary>  
-    public class IntegerTransition : AnimatorDrivenTransition<int, Int32Animator>
+    public class IntegerTransition : Transition<int>
     {
+        internal override IObservable<int> DoTransition(IObservable<double> progress, int oldValue, int newValue) => 
+            AnimatorDrivenTransition<int, Int32Animator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 4 - 1
src/Avalonia.Base/Animation/Transitions/PointTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 
 namespace Avalonia.Animation
@@ -5,7 +6,9 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="Point"/> type.
     /// </summary>  
-    public class PointTransition : AnimatorDrivenTransition<Point, PointAnimator>
+    public class PointTransition : Transition<Point>
     {
+        internal override IObservable<Point> DoTransition(IObservable<double> progress, Point oldValue, Point newValue) => 
+            AnimatorDrivenTransition<Point, PointAnimator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 4 - 1
src/Avalonia.Base/Animation/Transitions/RelativePointTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 
 namespace Avalonia.Animation
@@ -5,7 +6,9 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="RelativePoint"/> type.
     /// </summary>  
-    public class RelativePointTransition : AnimatorDrivenTransition<RelativePoint, RelativePointAnimator>
+    public class RelativePointTransition : Transition<RelativePoint>
     {
+        internal override IObservable<RelativePoint> DoTransition(IObservable<double> progress, RelativePoint oldValue, RelativePoint newValue) =>
+            AnimatorDrivenTransition<RelativePoint, RelativePointAnimator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 4 - 1
src/Avalonia.Base/Animation/Transitions/SizeTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 
 namespace Avalonia.Animation
@@ -5,7 +6,9 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="Size"/> type.
     /// </summary>  
-    public class SizeTransition : AnimatorDrivenTransition<Size, SizeAnimator>
+    public class SizeTransition : Transition<Size>
     {
+        internal override IObservable<Size> DoTransition(IObservable<double> progress, Size oldValue, Size newValue) => 
+            AnimatorDrivenTransition<Size, SizeAnimator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 4 - 1
src/Avalonia.Base/Animation/Transitions/ThicknessTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 
 namespace Avalonia.Animation
@@ -5,7 +6,9 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="Thickness"/> type.
     /// </summary>  
-    public class ThicknessTransition : AnimatorDrivenTransition<Thickness, ThicknessAnimator>
+    public class ThicknessTransition : Transition<Thickness>
     {
+        internal override IObservable<Thickness> DoTransition(IObservable<double> progress, Thickness oldValue, Thickness newValue) => 
+            AnimatorDrivenTransition<Thickness, ThicknessAnimator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 1 - 1
src/Avalonia.Base/Animation/Transitions/TransformOperationsTransition.cs

@@ -11,7 +11,7 @@ namespace Avalonia.Animation
     {
         private static readonly TransformOperationsAnimator s_operationsAnimator = new TransformOperationsAnimator();
 
-        public override IObservable<ITransform> DoTransition(
+        internal override IObservable<ITransform> DoTransition(
             IObservable<double> progress,
             ITransform oldValue,
             ITransform newValue)

+ 4 - 1
src/Avalonia.Base/Animation/Transitions/VectorTransition.cs

@@ -1,3 +1,4 @@
+using System;
 using Avalonia.Animation.Animators;
 
 namespace Avalonia.Animation
@@ -5,7 +6,9 @@ namespace Avalonia.Animation
     /// <summary>
     /// Transition class that handles <see cref="AvaloniaProperty"/> with <see cref="Vector"/> type.
     /// </summary>  
-    public class VectorTransition : AnimatorDrivenTransition<Vector, VectorAnimator>
+    public class VectorTransition : Transition<Vector>
     {
+        internal override IObservable<Vector> DoTransition(IObservable<double> progress, Vector oldValue, Vector newValue) => 
+            AnimatorDrivenTransition<Vector, VectorAnimator>.Transition(Easing, progress, oldValue, newValue);
     }
 }

+ 4 - 0
src/Avalonia.Base/AvaloniaLocator.cs

@@ -1,10 +1,12 @@
 using System;
 using System.Collections.Generic;
+using Avalonia.Metadata;
 
 #pragma warning disable CS1591 // Enable me later
 
 namespace Avalonia
 {
+    [PrivateApi]
     public class AvaloniaLocator : IAvaloniaDependencyResolver
     {
         private readonly IAvaloniaDependencyResolver? _parentScope;
@@ -114,11 +116,13 @@ namespace Avalonia
         }
     }
 
+    [PrivateApi]
     public interface IAvaloniaDependencyResolver
     {
         object? GetService(Type t);
     }
 
+    [PrivateApi]
     public static class LocatorExtensions
     {
         public static T? GetService<T>(this IAvaloniaDependencyResolver resolver)

+ 31 - 6
src/Avalonia.Base/Data/TemplateBinding.cs

@@ -3,18 +3,21 @@ using System.Globalization;
 using Avalonia.Data.Converters;
 using Avalonia.Reactive;
 using Avalonia.Styling;
+using Avalonia.Threading;
 
 namespace Avalonia.Data
 {
     /// <summary>
     /// A XAML binding to a property on a control's templated parent.
     /// </summary>
-    public class TemplateBinding : SingleSubscriberObservableBase<object?>,
+    public class TemplateBinding : IObservable<object?>,
         IBinding,
         IDescription,
         IAvaloniaSubject<object?>,
-        ISetterValue
+        ISetterValue,
+        IDisposable
     {
+        private IObserver<object?>? _observer;
         private bool _isSetterValue;
         private StyledElement? _target;
         private Type? _targetType;
@@ -29,6 +32,28 @@ namespace Avalonia.Data
             Property = property;
         }
 
+        public IDisposable Subscribe(IObserver<object?> observer)
+        {
+            _ = observer ?? throw new ArgumentNullException(nameof(observer));
+            Dispatcher.UIThread.VerifyAccess();
+
+            if (_observer != null)
+            {
+                throw new InvalidOperationException("The observable can only be subscribed once.");
+            }
+
+            _observer = observer;
+            Subscribed();
+
+            return this;
+        }
+
+        public virtual void Dispose()
+        {
+            Unsubscribed();
+            _observer = null;
+        }
+
         /// <inheritdoc/>
         public InstancedBinding? Initiate(
             AvaloniaObject target,
@@ -111,7 +136,7 @@ namespace Avalonia.Data
         /// <inheritdoc/>
         void ISetterValue.Initialize(SetterBase setter) => _isSetterValue = true;
 
-        protected override void Subscribed()
+        private void Subscribed()
         {
             TemplatedParentChanged();
 
@@ -121,7 +146,7 @@ namespace Avalonia.Data
             }
         }
 
-        protected override void Unsubscribed()
+        private void Unsubscribed()
         {
             if (_target?.TemplatedParent is { } templatedParent)
             {
@@ -147,12 +172,12 @@ namespace Avalonia.Data
                     value = Converter.Convert(value, _targetType ?? typeof(object), ConverterParameter, CultureInfo.CurrentCulture);
                 }
 
-                PublishNext(value);
+                _observer?.OnNext(value);
                 _hasProducedValue = true;
             }
             else if (_hasProducedValue)
             {
-                PublishNext(AvaloniaProperty.UnsetValue);
+                _observer?.OnNext(AvaloniaProperty.UnsetValue);
                 _hasProducedValue = false;
             }
         }

+ 2 - 2
src/Avalonia.Base/Input/AccessKeyHandler.cs

@@ -65,14 +65,14 @@ namespace Avalonia.Input
             {
                 if (_mainMenu != null)
                 {
-                    _mainMenu.MenuClosed -= MainMenuClosed;
+                    _mainMenu.Closed -= MainMenuClosed;
                 }
 
                 _mainMenu = value;
 
                 if (_mainMenu != null)
                 {
-                    _mainMenu.MenuClosed += MainMenuClosed;
+                    _mainMenu.Closed += MainMenuClosed;
                 }
             }
         }

+ 2 - 0
src/Avalonia.Base/Input/DragDropDevice.cs

@@ -2,9 +2,11 @@
 using Avalonia.VisualTree;
 using System.Linq;
 using Avalonia.Input.Raw;
+using Avalonia.Metadata;
 
 namespace Avalonia.Input
 {
+    [PrivateApi]
     public class DragDropDevice : IDragDropDevice
     {
         public static readonly DragDropDevice Instance = new DragDropDevice();

+ 1 - 1
src/Avalonia.Base/Input/IInputDevice.cs

@@ -3,7 +3,7 @@ using Avalonia.Metadata;
 
 namespace Avalonia.Input
 {
-    [NotClientImplementable]
+    [NotClientImplementable, PrivateApi]
     public interface IInputDevice
     {
         /// <summary>

+ 1 - 1
src/Avalonia.Base/Input/IInputManager.cs

@@ -8,7 +8,7 @@ namespace Avalonia.Input
     /// Receives input from the windowing subsystem and dispatches it to interested parties
     /// for processing.
     /// </summary>
-    [NotClientImplementable]
+    [NotClientImplementable, PrivateApi]
     public interface IInputManager
     {
         /// <summary>

+ 1 - 0
src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs

@@ -15,6 +15,7 @@ namespace Avalonia.Input
         /// <remarks>
         /// This method can only be called once, typically by the owner itself on creation.
         /// </remarks>
+        [PrivateApi]
         void SetOwner(IInputRoot owner);
 
         /// <summary>

+ 1 - 1
src/Avalonia.Base/Input/IMainMenu.cs

@@ -26,6 +26,6 @@ namespace Avalonia.Input
         /// <summary>
         /// Occurs when the main menu closes.
         /// </summary>
-        event EventHandler<RoutedEventArgs>? MenuClosed;
+        event EventHandler<RoutedEventArgs>? Closed;
     }
 }

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff