diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
index a43ea4539a..f668067f80 100644
--- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
+++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
@@ -10,6 +10,11 @@
apk
true
+
+
+
+
+
Resources\drawable\Icon.png
@@ -37,6 +42,10 @@
+
+
+
+
diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs
index 486d14661e..9b5b06e5fb 100644
--- a/samples/ControlCatalog.Android/MainActivity.cs
+++ b/samples/ControlCatalog.Android/MainActivity.cs
@@ -5,8 +5,16 @@ using Avalonia.Android;
namespace ControlCatalog.Android
{
- [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.Main", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
- public class MainActivity : AvaloniaMainActivity
+ [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
+ public class MainActivity : AvaloniaMainActivity
{
+ protected override Avalonia.AppBuilder CustomizeAppBuilder(Avalonia.AppBuilder builder)
+ {
+ return base.CustomizeAppBuilder(builder)
+ .AfterSetup(_ =>
+ {
+ Pages.EmbedSample.Implementation = new EmbedSampleAndroid();
+ });
+ }
}
}
diff --git a/samples/ControlCatalog.Android/Resources/drawable-night-v31/avalonia_anim.xml b/samples/ControlCatalog.Android/Resources/drawable-night-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..dde4b5a7dd
--- /dev/null
+++ b/samples/ControlCatalog.Android/Resources/drawable-night-v31/avalonia_anim.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Android/Resources/drawable-v31/avalonia_anim.xml b/samples/ControlCatalog.Android/Resources/drawable-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..94f27d9e63
--- /dev/null
+++ b/samples/ControlCatalog.Android/Resources/drawable-v31/avalonia_anim.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Android/Resources/values-v31/styles.xml b/samples/ControlCatalog.Android/Resources/values-v31/styles.xml
new file mode 100644
index 0000000000..d5ecec4391
--- /dev/null
+++ b/samples/ControlCatalog.Android/Resources/values-v31/styles.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Android/Resources/values/styles.xml b/samples/ControlCatalog.Android/Resources/values/styles.xml
index 3e1270256d..6e534de2f0 100644
--- a/samples/ControlCatalog.Android/Resources/values/styles.xml
+++ b/samples/ControlCatalog.Android/Resources/values/styles.xml
@@ -6,16 +6,7 @@
-
-
-
-
-
diff --git a/samples/ControlCatalog.Android/SplashActivity.cs b/samples/ControlCatalog.Android/SplashActivity.cs
deleted file mode 100644
index a0b68b129b..0000000000
--- a/samples/ControlCatalog.Android/SplashActivity.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using Android.App;
-using Android.Content;
-using Android.Content.PM;
-using Android.OS;
-using Avalonia.Android;
-
-namespace ControlCatalog.Android
-{
- [Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
- public class SplashActivity : AvaloniaSplashActivity
- {
- protected override Avalonia.AppBuilder CustomizeAppBuilder(Avalonia.AppBuilder builder)
- {
- return base.CustomizeAppBuilder(builder)
- .AfterSetup(_ =>
- {
- Pages.EmbedSample.Implementation = new EmbedSampleAndroid();
- });
- }
-
- protected override void OnCreate(Bundle? savedInstanceState)
- {
- base.OnCreate(savedInstanceState);
- }
-
- protected override void OnResume()
- {
- base.OnResume();
-
- StartActivity(new Intent(Application.Context, typeof(MainActivity)));
-
- Finish();
- }
- }
-}
diff --git a/samples/MobileSandbox.Android/MainActivity.cs b/samples/MobileSandbox.Android/MainActivity.cs
index d65f0dec92..807afb0bd0 100644
--- a/samples/MobileSandbox.Android/MainActivity.cs
+++ b/samples/MobileSandbox.Android/MainActivity.cs
@@ -1,12 +1,11 @@
using Android.App;
using Android.Content.PM;
-using Avalonia;
using Avalonia.Android;
namespace MobileSandbox.Android
{
- [Activity(Label = "MobileSandbox.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
- public class MainActivity : AvaloniaMainActivity
+ [Activity(Label = "MobileSandbox.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
+ public class MainActivity : AvaloniaMainActivity
{
}
}
diff --git a/samples/MobileSandbox.Android/MobileSandbox.Android.csproj b/samples/MobileSandbox.Android/MobileSandbox.Android.csproj
index 94f0d31e4d..3b67d79f7b 100644
--- a/samples/MobileSandbox.Android/MobileSandbox.Android.csproj
+++ b/samples/MobileSandbox.Android/MobileSandbox.Android.csproj
@@ -10,6 +10,12 @@
apk
true
+
+
+
+
+
+
Resources\drawable\Icon.png
@@ -37,6 +43,10 @@
+
+
+
+
diff --git a/samples/MobileSandbox.Android/Resources/drawable-night-v31/avalonia_anim.xml b/samples/MobileSandbox.Android/Resources/drawable-night-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..dde4b5a7dd
--- /dev/null
+++ b/samples/MobileSandbox.Android/Resources/drawable-night-v31/avalonia_anim.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/MobileSandbox.Android/Resources/drawable-v31/avalonia_anim.xml b/samples/MobileSandbox.Android/Resources/drawable-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..94f27d9e63
--- /dev/null
+++ b/samples/MobileSandbox.Android/Resources/drawable-v31/avalonia_anim.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/MobileSandbox.Android/Resources/values-night/colors.xml b/samples/MobileSandbox.Android/Resources/values-night/colors.xml
new file mode 100644
index 0000000000..3d47b6fc58
--- /dev/null
+++ b/samples/MobileSandbox.Android/Resources/values-night/colors.xml
@@ -0,0 +1,4 @@
+
+
+ #212121
+
diff --git a/samples/MobileSandbox.Android/Resources/values-v31/styles.xml b/samples/MobileSandbox.Android/Resources/values-v31/styles.xml
new file mode 100644
index 0000000000..7518f078e5
--- /dev/null
+++ b/samples/MobileSandbox.Android/Resources/values-v31/styles.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/samples/MobileSandbox.Android/Resources/values/styles.xml b/samples/MobileSandbox.Android/Resources/values/styles.xml
index 2759d2904a..22085806da 100644
--- a/samples/MobileSandbox.Android/Resources/values/styles.xml
+++ b/samples/MobileSandbox.Android/Resources/values/styles.xml
@@ -6,12 +6,7 @@
-
-
-
diff --git a/samples/MobileSandbox.Android/SplashActivity.cs b/samples/MobileSandbox.Android/SplashActivity.cs
deleted file mode 100644
index ced092554d..0000000000
--- a/samples/MobileSandbox.Android/SplashActivity.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Android.App;
-using Android.Content;
-using Avalonia.Android;
-
-namespace MobileSandbox.Android
-{
- [Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
- public class SplashActivity : AvaloniaSplashActivity
- {
- protected override void OnResume()
- {
- base.OnResume();
-
- StartActivity(new Intent(Application.Context, typeof(MainActivity)));
- }
- }
-}
diff --git a/samples/SafeAreaDemo.Android/MainActivity.cs b/samples/SafeAreaDemo.Android/MainActivity.cs
index b0f0a6e419..1df575eb4d 100644
--- a/samples/SafeAreaDemo.Android/MainActivity.cs
+++ b/samples/SafeAreaDemo.Android/MainActivity.cs
@@ -4,8 +4,8 @@ using Avalonia.Android;
namespace SafeAreaDemo.Android
{
- [Activity(Label = "SafeAreaDemo.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
- public class MainActivity : AvaloniaMainActivity
+ [Activity(Label = "SafeAreaDemo.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
+ public class MainActivity : AvaloniaMainActivity
{
}
}
diff --git a/samples/SafeAreaDemo.Android/Resources/drawable-night-v31/avalonia_anim.xml b/samples/SafeAreaDemo.Android/Resources/drawable-night-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..dde4b5a7dd
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/drawable-night-v31/avalonia_anim.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/Resources/drawable-v31/avalonia_anim.xml b/samples/SafeAreaDemo.Android/Resources/drawable-v31/avalonia_anim.xml
new file mode 100644
index 0000000000..94f27d9e63
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/drawable-v31/avalonia_anim.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/Resources/values-night/colors.xml b/samples/SafeAreaDemo.Android/Resources/values-night/colors.xml
new file mode 100644
index 0000000000..3d47b6fc58
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/values-night/colors.xml
@@ -0,0 +1,4 @@
+
+
+ #212121
+
diff --git a/samples/SafeAreaDemo.Android/Resources/values-v31/styles.xml b/samples/SafeAreaDemo.Android/Resources/values-v31/styles.xml
new file mode 100644
index 0000000000..7518f078e5
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/values-v31/styles.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/Resources/values/styles.xml b/samples/SafeAreaDemo.Android/Resources/values/styles.xml
index 2759d2904a..22085806da 100644
--- a/samples/SafeAreaDemo.Android/Resources/values/styles.xml
+++ b/samples/SafeAreaDemo.Android/Resources/values/styles.xml
@@ -6,12 +6,7 @@
-
-
-
diff --git a/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj b/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
index f5d2af79d0..cc182b2b56 100644
--- a/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
+++ b/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
@@ -1,4 +1,4 @@
-
+
Exe
net7.0-android
@@ -12,13 +12,14 @@
-
- Resources\drawable\Icon.png
-
+
+
-
-
+
+ Resources\drawable\Icon.png
+
+
diff --git a/samples/SafeAreaDemo.Android/SplashActivity.cs b/samples/SafeAreaDemo.Android/SplashActivity.cs
deleted file mode 100644
index 621ad1c675..0000000000
--- a/samples/SafeAreaDemo.Android/SplashActivity.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using Android.App;
-using Android.Content;
-using Android.OS;
-using Avalonia;
-using Avalonia.Android;
-using Application = Android.App.Application;
-
-namespace SafeAreaDemo.Android
-{
- [Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
- public class SplashActivity : AvaloniaSplashActivity
- {
- protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
- {
- return base.CustomizeAppBuilder(builder);
- }
-
- protected override void OnCreate(Bundle? savedInstanceState)
- {
- base.OnCreate(savedInstanceState);
- }
-
- protected override void OnResume()
- {
- base.OnResume();
-
- StartActivity(new Intent(Application.Context, typeof(MainActivity)));
- }
- }
-}
diff --git a/src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs b/src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs
new file mode 100644
index 0000000000..3fcfde3ee4
--- /dev/null
+++ b/src/Android/Avalonia.Android/AvaloniaMainActivity.App.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalonia.Android
+{
+ partial class AvaloniaMainActivity where TApp : Application, new()
+ {
+ protected virtual AppBuilder CustomizeAppBuilder(AppBuilder builder) => builder.UseAndroid();
+
+ private static AppBuilder? s_appBuilder;
+ internal static object ViewContent;
+
+ public object Content
+ {
+ get
+ {
+ return ViewContent;
+ }
+ set
+ {
+ ViewContent = value;
+ if (View != null)
+ View.Content = value;
+ }
+ }
+
+ protected AppBuilder CreateAppBuilder()
+ {
+ var builder = AppBuilder.Configure();
+
+ return CustomizeAppBuilder(builder);
+ }
+
+ private void InitializeApp()
+ {
+ if (s_appBuilder == null)
+ {
+ var builder = CreateAppBuilder();
+
+ builder.SetupWithLifetime(new SingleViewLifetime());
+
+ s_appBuilder = builder;
+ }
+
+ View = new AvaloniaView(this);
+ if (ViewContent != null)
+ {
+ View.Content = ViewContent;
+ }
+
+ if (Avalonia.Application.Current.ApplicationLifetime is SingleViewLifetime lifetime)
+ {
+ lifetime.View = View;
+ }
+ }
+ }
+}
diff --git a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
index b2cd150933..499924d8fb 100644
--- a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
+++ b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
@@ -11,27 +11,49 @@ using AndroidX.AppCompat.App;
namespace Avalonia.Android
{
- public abstract class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler, IActivityNavigationService
+ public class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler, IActivityNavigationService
{
- internal static object ViewContent;
-
public Action ActivityResult { get; set; }
public Action RequestPermissionsResult { get; set; }
+
+ public event EventHandler BackRequested;
+
+ public override void OnBackPressed()
+ {
+ var eventArgs = new AndroidBackRequestedEventArgs();
+
+ BackRequested?.Invoke(this, eventArgs);
+
+ if (!eventArgs.Handled)
+ {
+ base.OnBackPressed();
+ }
+ }
+
+ protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
+ {
+ base.OnActivityResult(requestCode, resultCode, data);
+
+ ActivityResult?.Invoke(requestCode, resultCode, data);
+ }
+
+ public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
+ {
+ base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
+
+ RequestPermissionsResult?.Invoke(requestCode, permissions, grantResults);
+ }
+ }
+
+ public abstract partial class AvaloniaMainActivity : AvaloniaMainActivity where TApp : Application, new()
+ {
internal AvaloniaView View;
private GlobalLayoutListener _listener;
protected override void OnCreate(Bundle savedInstanceState)
{
- View = new AvaloniaView(this);
- if (ViewContent != null)
- {
- View.Content = ViewContent;
- }
+ InitializeApp();
- if (Avalonia.Application.Current.ApplicationLifetime is SingleViewLifetime lifetime)
- {
- lifetime.View = View;
- }
base.OnCreate(savedInstanceState);
SetContentView(View);
@@ -41,20 +63,6 @@ namespace Avalonia.Android
View.ViewTreeObserver?.AddOnGlobalLayoutListener(_listener);
}
- public object Content
- {
- get
- {
- return ViewContent;
- }
- set
- {
- ViewContent = value;
- if (View != null)
- View.Content = value;
- }
- }
-
protected override void OnResume()
{
base.OnResume();
@@ -66,20 +74,6 @@ namespace Avalonia.Android
}
}
- public event EventHandler BackRequested;
-
- public override void OnBackPressed()
- {
- var eventArgs = new AndroidBackRequestedEventArgs();
-
- BackRequested?.Invoke(this, eventArgs);
-
- if (!eventArgs.Handled)
- {
- base.OnBackPressed();
- }
- }
-
protected override void OnDestroy()
{
View.Content = null;
@@ -89,20 +83,6 @@ namespace Avalonia.Android
base.OnDestroy();
}
- protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
- {
- base.OnActivityResult(requestCode, resultCode, data);
-
- ActivityResult?.Invoke(requestCode, resultCode, data);
- }
-
- public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
- {
- base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
-
- RequestPermissionsResult?.Invoke(requestCode, permissions, grantResults);
- }
-
class GlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
{
private AvaloniaView _view;
diff --git a/src/Android/Avalonia.Android/AvaloniaSplashActivity.cs b/src/Android/Avalonia.Android/AvaloniaSplashActivity.cs
deleted file mode 100644
index 38038ef26c..0000000000
--- a/src/Android/Avalonia.Android/AvaloniaSplashActivity.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using Android.OS;
-using AndroidX.AppCompat.App;
-
-namespace Avalonia.Android
-{
- public abstract class AvaloniaSplashActivity : AppCompatActivity
- {
- protected abstract AppBuilder CreateAppBuilder();
-
- private static AppBuilder s_appBuilder;
-
- protected override void OnCreate(Bundle? savedInstanceState)
- {
- base.OnCreate(savedInstanceState);
-
- if (s_appBuilder == null)
- {
- var builder = CreateAppBuilder();
-
- var lifetime = new SingleViewLifetime();
-
- builder.SetupWithLifetime(lifetime);
-
- s_appBuilder = builder;
- }
- }
- }
-
- public abstract class AvaloniaSplashActivity : AvaloniaSplashActivity where TApp : Application, new()
- {
- protected virtual AppBuilder CustomizeAppBuilder(AppBuilder builder) => builder.UseAndroid();
-
- protected override AppBuilder CreateAppBuilder()
- {
- var builder = AppBuilder.Configure();
-
- return CustomizeAppBuilder(builder);
- }
- }
-}
diff --git a/src/Avalonia.Base/Input/Pointer.cs b/src/Avalonia.Base/Input/Pointer.cs
index 91358712a0..5744ddf963 100644
--- a/src/Avalonia.Base/Input/Pointer.cs
+++ b/src/Avalonia.Base/Input/Pointer.cs
@@ -88,7 +88,6 @@ namespace Avalonia.Input
/// Captures pointer input to the specified gesture recognizer.
///
/// The gesture recognizer.
- ///
internal void CaptureGestureRecognizer(GestureRecognizer? gestureRecognizer)
{
if (CapturedGestureRecognizer != gestureRecognizer)
diff --git a/src/Avalonia.Base/Media/MediaContext.cs b/src/Avalonia.Base/Media/MediaContext.cs
index 84a4a8c873..0a290052c7 100644
--- a/src/Avalonia.Base/Media/MediaContext.cs
+++ b/src/Avalonia.Base/Media/MediaContext.cs
@@ -213,10 +213,10 @@ internal partial class MediaContext : ICompositorScheduler
}
///
- /// Executes the callback in the next iteration of the current UI-thread
+ /// Executes the callback in the next iteration of the current UI-thread
/// render loop / layout pass that.
///
- /// Code to execute.
+ ///
public void BeginInvokeOnRender(Action callback)
{
if (_invokeOnRenderCallbacks == null)
diff --git a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
index a0cd2a8dcd..df3c9ebfc5 100644
--- a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
+++ b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs
@@ -161,7 +161,7 @@ namespace Avalonia.Platform
void PopGeometryClip();
///
-
+ /// Get Fetaure from type
///
/// Attempts to get an optional feature from the drawing context implementation
///
diff --git a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
index 4518289335..a69d7b7094 100644
--- a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
+++ b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
@@ -216,7 +216,7 @@ namespace Avalonia.PropertyStore
valueChanged = !EqualityComparer.Default.Equals(Value, v);
Value = v;
Priority = priority;
- if (_uncommon is not null)
+ if (!isCoercedDefaultValue && _uncommon is not null)
_uncommon._uncoercedValue = value;
}
@@ -225,7 +225,7 @@ namespace Avalonia.PropertyStore
baseValueChanged = !EqualityComparer.Default.Equals(_baseValue, v);
_baseValue = v;
BasePriority = priority;
- if (_uncommon is not null)
+ if (!isCoercedDefaultValue && _uncommon is not null)
_uncommon._uncoercedBaseValue = value;
}
diff --git a/src/Avalonia.Base/Rendering/RenderLoop.cs b/src/Avalonia.Base/Rendering/RenderLoop.cs
index aaecf5deaf..80410ba181 100644
--- a/src/Avalonia.Base/Rendering/RenderLoop.cs
+++ b/src/Avalonia.Base/Rendering/RenderLoop.cs
@@ -42,7 +42,6 @@ namespace Avalonia.Rendering
/// Initializes a new instance of the class.
///
/// The render timer.
- /// The UI thread dispatcher.
public RenderLoop(IRenderTimer timer)
{
_timer = timer;
diff --git a/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs b/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs
index bb1663eac0..7d586e1cbd 100644
--- a/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs
+++ b/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs
@@ -581,11 +581,6 @@ public partial class Dispatcher
///
/// A Func<Task<TResult>> delegate to invoke through the dispatcher.
///
- ///
- /// The priority that determines in what order the specified
- /// callback is invoked relative to the other pending operations
- /// in the Dispatcher.
- ///
///
/// An task that completes after the task returned from callback finishes
///
diff --git a/src/Avalonia.Controls/LayoutTransformControl.cs b/src/Avalonia.Controls/LayoutTransformControl.cs
index 06069a897e..5f8d4a561d 100644
--- a/src/Avalonia.Controls/LayoutTransformControl.cs
+++ b/src/Avalonia.Controls/LayoutTransformControl.cs
@@ -215,7 +215,7 @@ namespace Avalonia.Controls
///
/// Transformation matrix corresponding to _matrixTransform.
///
- private Matrix _transformation;
+ private Matrix _transformation = Matrix.Identity;
private IDisposable? _transformChangedEvent;
///
@@ -256,13 +256,16 @@ namespace Avalonia.Controls
///
private void ApplyLayoutTransform()
{
- if (LayoutTransform == null)
- return;
-
// Get the transform matrix and apply it
- _transformation = RoundMatrix(LayoutTransform.Value, DecimalsAfterRound);
+ var matrix = LayoutTransform is null ?
+ Matrix.Identity :
+ RoundMatrix(LayoutTransform.Value, DecimalsAfterRound);
+
+ if (_transformation == matrix)
+ return;
- _matrixTransform.Matrix = _transformation;
+ _transformation = matrix;
+ _matrixTransform.Matrix = matrix;
// New transform means re-layout is necessary
InvalidateMeasure();
diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs
index 1bb53f90a8..40d6b6b0f4 100644
--- a/src/Avalonia.Controls/MenuItem.cs
+++ b/src/Avalonia.Controls/MenuItem.cs
@@ -394,6 +394,14 @@ namespace Avalonia.Controls
_isEmbeddedInMenu = parent?.FindLogicalAncestorOfType(true) != null;
}
+ ///
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+
+ TryUpdateCanExecute();
+ }
+
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
// This will cause the hotkey manager to dispose the observer and the reference to this control
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs
index aec0cb37bc..f6e9842ac8 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs
@@ -265,7 +265,7 @@ namespace Avalonia.Diagnostics.Views
static bool IsValidNumeric(Type? type)
{
- if (type == null)
+ if (type == null || type.IsEnum == true)
{
return false;
}
diff --git a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml
index 22362fa5f5..b58df71ba2 100644
--- a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml
+++ b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml
@@ -6,106 +6,71 @@
MinWidth="430"
MinHeight="475"
Title="About Avalonia"
- Background="Purple"
FontFamily="/Assets/Roboto-Light.ttf#Roboto"
x:Class="Avalonia.Dialogs.AboutAvaloniaDialog"
x:DataType="dialogs:AboutAvaloniaDialog">
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml.cs b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml.cs
index 2dc377a242..ba432337dc 100644
--- a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml.cs
+++ b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Avalonia.Controls;
+using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace Avalonia.Dialogs
@@ -11,35 +12,19 @@ namespace Avalonia.Dialogs
{
private static readonly Version s_version = typeof(AboutAvaloniaDialog).Assembly.GetName().Version;
- public static string Version { get; } = s_version.ToString(2);
+ public static string Version { get; } = $@"v{s_version.ToString(2)}";
public static bool IsDevelopmentBuild { get; } = s_version.Revision == 999;
+ public static string Copyright { get; } = $"© {DateTime.Now.Year} The Avalonia Project";
+
public AboutAvaloniaDialog()
{
AvaloniaXamlLoader.Load(this);
DataContext = this;
}
- public static void OpenBrowser(string url)
- {
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
- {
- // If no associated application/json MimeType is found xdg-open opens retrun error
- // but it tries to open it anyway using the console editor (nano, vim, other..)
- ShellExec($"xdg-open {url}", waitForExit: false);
- }
- else
- {
- using Process process = Process.Start(new ProcessStartInfo
- {
- FileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? url : "open",
- Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? $"{url}" : "",
- CreateNoWindow = true,
- UseShellExecute = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
- });
- }
- }
+
private static void ShellExec(string cmd, bool waitForExit = true)
{
@@ -64,5 +49,26 @@ namespace Avalonia.Dialogs
}
}
}
+
+ private void Button_OnClick(object sender, RoutedEventArgs e)
+ {
+ var url = "https://www.avaloniaui.net/";
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ // If no associated application/json MimeType is found xdg-open opens retrun error
+ // but it tries to open it anyway using the console editor (nano, vim, other..)
+ ShellExec($"xdg-open {url}", waitForExit: false);
+ }
+ else
+ {
+ using Process process = Process.Start(new ProcessStartInfo
+ {
+ FileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? url : "open",
+ Arguments = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? $"{url}" : "",
+ CreateNoWindow = true,
+ UseShellExecute = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+ });
+ }
+ }
}
}
diff --git a/src/Avalonia.Dialogs/Internal/ManagedFileChooserFilterViewModel.cs b/src/Avalonia.Dialogs/Internal/ManagedFileChooserFilterViewModel.cs
index 8389a25386..8e24da97a4 100644
--- a/src/Avalonia.Dialogs/Internal/ManagedFileChooserFilterViewModel.cs
+++ b/src/Avalonia.Dialogs/Internal/ManagedFileChooserFilterViewModel.cs
@@ -18,9 +18,9 @@ namespace Avalonia.Dialogs.Internal
return;
}
- _patterns = filter.Patterns?
- .Select(e => new Regex(Regex.Escape(e).Replace(@"\*", ".*").Replace(@"\?", "."), RegexOptions.Singleline | RegexOptions.IgnoreCase))
- .ToArray();
+ _patterns = filter.Patterns?
+ .Select(e => new Regex("^" + Regex.Escape(e).Replace("\\*", ".*") + "$", RegexOptions.Singleline | RegexOptions.IgnoreCase))
+ .ToArray();
}
public bool Match(string filename)
diff --git a/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml b/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml
index ceccdf56c7..5f532df848 100644
--- a/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml
+++ b/src/Avalonia.Themes.Simple/Controls/TransitioningContentControl.xaml
@@ -13,11 +13,10 @@
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
ContentTemplate="{TemplateBinding ContentTemplate}"
- Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" />
- $(DefineConstants);XAMLX_INTERNAL
true
true
+ true
diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs
index 42720cbb4c..e664829677 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Coercion.cs
@@ -243,6 +243,19 @@ namespace Avalonia.Base.UnitTests
Assert.Equal(new[] { 11 }, target.CoerceFooInvocations);
}
+ [Fact]
+ public void Second_Coerce_Of_Default_Value_Is_Passed_Uncoerced_Value()
+ {
+ var target = new Class1();
+
+ target.MinFoo = 20;
+ target.CoerceFooInvocations.Clear();
+ target.CoerceValue(Class1.FooProperty);
+ target.CoerceValue(Class1.FooProperty);
+
+ Assert.Equal(new[] { 11, 11 }, target.CoerceFooInvocations);
+ }
+
[Fact]
public void ClearValue_Respects_Coerced_Default_Value()
{
diff --git a/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs b/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs
index 60139c2881..c8a5af05a4 100644
--- a/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs
@@ -169,6 +169,25 @@ namespace Avalonia.Controls.UnitTests
new Rect(0, 100, 100, 25));
}
+ [Fact]
+ public void Bounds_On_Transform_Applied_Then_Removed_Are_Correct()
+ {
+ using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
+
+ var control = CreateWithChildAndMeasureAndTransform(
+ 100,
+ 25,
+ new RotateTransform { Angle = 90 });
+
+ Assert.Equal(new Size(25, 100), control.DesiredSize);
+
+ control.LayoutTransform = null;
+ control.Measure(Size.Infinity);
+ control.Arrange(new Rect(control.DesiredSize));
+
+ Assert.Equal(new Size(100, 25), control.DesiredSize);
+ }
+
[Fact]
public void Should_Generate_RotateTransform_90_degrees()
{
diff --git a/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs b/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs
index 08aedceac3..92a565490b 100644
--- a/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/MenuItemTests.cs
@@ -209,13 +209,13 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(0, canExecuteCallCount);
contextMenu.Open();
- Assert.Equal(2, canExecuteCallCount);//2 because popup is changing logical child
+ Assert.Equal(3, canExecuteCallCount);// 3 because popup is changing logical child and moreover we need to invalidate again after the item is attached to the visual tree
command.RaiseCanExecuteChanged();
- Assert.Equal(3, canExecuteCallCount);
+ Assert.Equal(4, canExecuteCallCount);
target.CommandParameter = true;
- Assert.Equal(4, canExecuteCallCount);
+ Assert.Equal(5, canExecuteCallCount);
}
}
@@ -249,13 +249,13 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(0, canExecuteCallCount);
flyout.ShowAt(button);
- Assert.Equal(1, canExecuteCallCount);
+ Assert.Equal(2, canExecuteCallCount); // 2 because we need to invalidate after the item is attached to the visual tree
command.RaiseCanExecuteChanged();
- Assert.Equal(2, canExecuteCallCount);
+ Assert.Equal(3, canExecuteCallCount);
target.CommandParameter = true;
- Assert.Equal(3, canExecuteCallCount);
+ Assert.Equal(4, canExecuteCallCount);
}
}
diff --git a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
index 8ce0b8a984..0d49f78dd9 100644
--- a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
+++ b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
@@ -22,5 +22,4 @@
-