mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-29 07:16:33 +08:00
205 lines
6.7 KiB
C#
205 lines
6.7 KiB
C#
using AtomUI.Desktop.Controls.DesignTokens;
|
|
using AtomUI.Theme;
|
|
using AtomUI.Theme.Algorithms;
|
|
using AtomUI.Theme.Configuration;
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Media;
|
|
using Avalonia.Styling;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using AtomUIWindow = AtomUI.Desktop.Controls.Window;
|
|
using AvaloniaWindow = Avalonia.Controls.Window;
|
|
|
|
namespace AtomUI.Desktop.Controls.Tests.Window;
|
|
|
|
public class WindowThemeContextLeaseTests
|
|
{
|
|
static WindowThemeContextLeaseTests()
|
|
{
|
|
AvaloniaTestApp.EnsureInitialized();
|
|
}
|
|
|
|
[Fact]
|
|
public void Show_Attaches_Theme_Context_Lease_Before_The_Window_Opened_Event()
|
|
{
|
|
var window = new AtomUIWindow();
|
|
ThemeContext? contextAtOpening = null;
|
|
ThemeVariant? variantAtOpening = null;
|
|
ThemeVariant? actualVariantAtOpening = null;
|
|
var bridgeCountAtOpening = 0;
|
|
window.AddHandler(
|
|
AvaloniaWindow.WindowOpenedEvent,
|
|
(_, _) =>
|
|
{
|
|
contextAtOpening = window.GetValue(ThemeScope.ContextProperty);
|
|
variantAtOpening = window.RequestedThemeVariant;
|
|
actualVariantAtOpening = window.ActualThemeVariant;
|
|
bridgeCountAtOpening = window.Resources.MergedDictionaries
|
|
.OfType<ThemeContextResourceBridge>()
|
|
.Count();
|
|
});
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
|
|
contextAtOpening.ShouldNotBeNull();
|
|
variantAtOpening.ShouldBe(
|
|
contextAtOpening.Appearance == ThemeAppearance.Dark
|
|
? ThemeVariant.Dark
|
|
: ThemeVariant.Light);
|
|
actualVariantAtOpening.ShouldBe(variantAtOpening);
|
|
bridgeCountAtOpening.ShouldBe(1);
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
}
|
|
|
|
window.Resources.MergedDictionaries
|
|
.OfType<ThemeContextResourceBridge>()
|
|
.ShouldBeEmpty();
|
|
window.GetValue(ThemeScope.ContextProperty).ShouldBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Show_Primes_The_Window_Surface_With_The_Dark_Theme_Before_Styling()
|
|
{
|
|
var application = Application.Current.ShouldNotBeNull();
|
|
var manager = AvaloniaLocator.Current.GetService(typeof(ThemeManager))
|
|
.ShouldBeOfType<ThemeManager>();
|
|
var darkConfig = new ThemeConfigBuilder().WithAlgorithms(ThemeAlgorithm.Dark).Build();
|
|
var darkResult = await manager.ApplyThemeAsync(
|
|
new ThemeRequest(
|
|
IThemeManager.DEFAULT_THEME_ID,
|
|
darkConfig,
|
|
ThemeTransitionReason.UserRequest),
|
|
TestContext.Current.CancellationToken);
|
|
darkResult.Status.ShouldBeOneOf(ThemeTransitionStatus.Committed, ThemeTransitionStatus.NoOp);
|
|
|
|
application.TryFindResource(
|
|
WindowTokenKind.DefaultBackground,
|
|
ThemeVariant.Dark,
|
|
out var expectedBackground)
|
|
.ShouldBeTrue();
|
|
var expectedColor = GetColor(expectedBackground);
|
|
var window = new AtomUIWindow();
|
|
Color? backgroundAtOpening = null;
|
|
Color? fallbackAtOpening = null;
|
|
window.AddHandler(
|
|
AvaloniaWindow.WindowOpenedEvent,
|
|
(_, _) =>
|
|
{
|
|
backgroundAtOpening = GetColor(window.Background);
|
|
fallbackAtOpening = GetColor(window.TransparencyBackgroundFallback);
|
|
});
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
|
|
backgroundAtOpening.ShouldBe(expectedColor);
|
|
fallbackAtOpening.ShouldBe(expectedColor);
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
await manager.ApplyThemeAsync(
|
|
new ThemeRequest(
|
|
IThemeManager.DEFAULT_THEME_ID,
|
|
null,
|
|
ThemeTransitionReason.UserRequest),
|
|
TestContext.Current.CancellationToken);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Show_Preserves_Explicit_Window_Surface_Backgrounds()
|
|
{
|
|
var expectedBackground = Colors.Magenta;
|
|
var expectedFallback = Colors.Cyan;
|
|
var window = new AtomUIWindow
|
|
{
|
|
Background = new SolidColorBrush(expectedBackground),
|
|
TransparencyBackgroundFallback = new SolidColorBrush(expectedFallback)
|
|
};
|
|
Color? backgroundAtOpening = null;
|
|
Color? fallbackAtOpening = null;
|
|
window.AddHandler(
|
|
AvaloniaWindow.WindowOpenedEvent,
|
|
(_, _) =>
|
|
{
|
|
backgroundAtOpening = GetColor(window.Background);
|
|
fallbackAtOpening = GetColor(window.TransparencyBackgroundFallback);
|
|
});
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
|
|
backgroundAtOpening.ShouldBe(expectedBackground);
|
|
fallbackAtOpening.ShouldBe(expectedFallback);
|
|
GetColor(window.Background).ShouldBe(expectedBackground);
|
|
GetColor(window.TransparencyBackgroundFallback).ShouldBe(expectedFallback);
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Owned_Window_Uses_The_Owner_Context_Before_The_Window_Opened_Event()
|
|
{
|
|
var owner = new AtomUIWindow();
|
|
var child = new AtomUIWindow();
|
|
ThemeContext? contextAtOpening = null;
|
|
child.AddHandler(
|
|
AvaloniaWindow.WindowOpenedEvent,
|
|
(_, _) => contextAtOpening = child.GetValue(ThemeScope.ContextProperty));
|
|
|
|
try
|
|
{
|
|
owner.Show();
|
|
child.Show(owner);
|
|
|
|
contextAtOpening.ShouldBeSameAs(owner.GetValue(ThemeScope.ContextProperty));
|
|
child.Resources.MergedDictionaries
|
|
.OfType<ThemeContextResourceBridge>()
|
|
.ShouldHaveSingleItem()
|
|
.OwnerContext.ShouldBeSameAs(contextAtOpening);
|
|
}
|
|
finally
|
|
{
|
|
child.Close();
|
|
owner.Close();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Failed_Show_Releases_The_New_Context_Lease()
|
|
{
|
|
var window = new AtomUIWindow();
|
|
window.Close();
|
|
|
|
Should.Throw<InvalidOperationException>(() => window.Show());
|
|
|
|
window.Resources.MergedDictionaries
|
|
.OfType<ThemeContextResourceBridge>()
|
|
.ShouldBeEmpty();
|
|
window.GetValue(ThemeScope.ContextProperty).ShouldBeNull();
|
|
}
|
|
|
|
private static Color GetColor(object? value)
|
|
{
|
|
return value switch
|
|
{
|
|
Color color => color,
|
|
ISolidColorBrush brush => brush.Color,
|
|
_ => throw new InvalidOperationException(
|
|
$"Expected a color resource, but found '{value?.GetType().FullName ?? "null"}'.")
|
|
};
|
|
}
|
|
}
|