diff --git a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs index be5b66415c..92035c1b02 100644 --- a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs @@ -17,6 +17,15 @@ namespace CommunityToolkit.Maui.Core; [SupportedOSPlatform("Tizen6.5")] public static class AppBuilderExtensions { + static readonly WeakEventManager weakEventManager = new(); + + // This is an internal event used by Unit Tests to confirm when the code enters the `if (Options.ShouldUseStatusBarBehaviorOnAndroidModalPage)` block + internal static event EventHandler ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted + { + add => weakEventManager.AddEventHandler(value); + remove => weakEventManager.RemoveEventHandler(value); + } + /// /// Initializes the .NET MAUI Community Toolkit Core Library /// @@ -27,9 +36,10 @@ public static MauiAppBuilder UseMauiCommunityToolkitCore(this MauiAppBuilder bui { options?.Invoke(new Options()); + if (Options.ShouldUseStatusBarBehaviorOnAndroidModalPage) + { + #if ANDROID - if (Options.ShouldUseStatusBarBehaviorOnAndroidModalPage) - { builder.Services.AddSingleton(); builder.ConfigureLifecycleEvents(static lifecycleBuilder => @@ -58,9 +68,11 @@ public static MauiAppBuilder UseMauiCommunityToolkitCore(this MauiAppBuilder bui }); }); }); - } #endif + weakEventManager.HandleEvent(null, EventArgs.Empty, nameof(ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted)); + } + return builder; } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs index 0aa2635f01..27550e0220 100644 --- a/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs +++ b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs @@ -94,7 +94,7 @@ static bool TryConvertToDialogFragment(Fragment fragment, [NotNullWhen(true)] ou dialogFragment = dialog; return true; } - + static void HandleStatusBarColor(DialogFragment dialogFragment, AppCompatActivity activity) { if (activity.Window is null) diff --git a/src/CommunityToolkit.Maui.UnitTests/BaseTest.cs b/src/CommunityToolkit.Maui.UnitTests/BaseTest.cs index 1ef71b7580..535918ea92 100644 --- a/src/CommunityToolkit.Maui.UnitTests/BaseTest.cs +++ b/src/CommunityToolkit.Maui.UnitTests/BaseTest.cs @@ -57,7 +57,10 @@ protected virtual void Dispose(bool isDisposing) DeviceDisplay.SetCurrent(null); DispatcherProvider.SetCurrent(null); + // Restore default options var options = new Options(); + options.SetShouldUseStatusBarBehaviorOnAndroidModalPage(true); + options.SetShouldEnableSnackbarOnWindows(false); options.SetShouldSuppressExceptionsInAnimations(false); options.SetShouldSuppressExceptionsInBehaviors(false); options.SetShouldSuppressExceptionsInConverters(false); diff --git a/src/CommunityToolkit.Maui.UnitTests/Extensions/AppBuilderExtensionsTests.cs b/src/CommunityToolkit.Maui.UnitTests/Extensions/AppBuilderExtensionsTests.cs new file mode 100644 index 0000000000..4c5a97eeba --- /dev/null +++ b/src/CommunityToolkit.Maui.UnitTests/Extensions/AppBuilderExtensionsTests.cs @@ -0,0 +1,119 @@ +using CommunityToolkit.Maui.Core; +using Xunit; + +namespace CommunityToolkit.Maui.UnitTests.Extensions; + +#pragma warning disable CA1416 +public class AppBuilderExtensionsTests : BaseTest +{ + [Fact] + public void ConfirmOptionsDefaultValue() + { + // Arrange + bool isAndroidDialogFragmentServiceInitialized = false; + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted += HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + + // Assert + Assert.True(Core.Options.ShouldUseStatusBarBehaviorOnAndroidModalPage); + Assert.False(Options.ShouldEnableSnackbarOnWindows); + Assert.False(Options.ShouldSuppressExceptionsInAnimations); + Assert.False(Options.ShouldSuppressExceptionsInBehaviors); + Assert.False(Options.ShouldSuppressExceptionsInConverters); + Assert.False(isAndroidDialogFragmentServiceInitialized); + + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted -= HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + + void HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted(object? sender, EventArgs e) + { + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted -= HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + isAndroidDialogFragmentServiceInitialized = true; + } + } + + [Fact] + public void ConfirmDefaultValueRemainWhenOptionsNull() + { + // Arrange + var builder = MauiApp.CreateBuilder(); + bool isAndroidDialogFragmentServiceInitialized = false; + + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted += HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + + // Act + builder.UseMauiCommunityToolkit(null); + + // Assert + Assert.True(Core.Options.ShouldUseStatusBarBehaviorOnAndroidModalPage); + Assert.False(Options.ShouldEnableSnackbarOnWindows); + Assert.False(Options.ShouldSuppressExceptionsInAnimations); + Assert.False(Options.ShouldSuppressExceptionsInBehaviors); + Assert.False(Options.ShouldSuppressExceptionsInConverters); + Assert.True(isAndroidDialogFragmentServiceInitialized); + + void HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted(object? sender, EventArgs e) + { + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted -= HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + isAndroidDialogFragmentServiceInitialized = true; + } + } + + + [Fact] + public void UseMauiCommunityToolkit_ShouldRegisterServices() + { + // Arrange + var builder = MauiApp.CreateBuilder(); + bool isAndroidDialogFragmentServiceInitialized = false; + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted += HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + + // Act + builder.UseMauiCommunityToolkit(); + + // Assert + var serviceProvider = builder.Services.BuildServiceProvider(); + Assert.NotNull(serviceProvider.GetService()); + Assert.True(isAndroidDialogFragmentServiceInitialized); + + void HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted(object? sender, EventArgs e) + { + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted -= HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + isAndroidDialogFragmentServiceInitialized = true; + } + } + + [Fact] + public void UseMauiCommunityToolkit_ShouldAssignValues() + { + // Arrange + var builder = MauiApp.CreateBuilder(); + bool isAndroidDialogFragmentServiceInitialized = false; + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted += HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + + // Act + builder.UseMauiCommunityToolkit(options => + { + options.SetShouldEnableSnackbarOnWindows(!Options.ShouldEnableSnackbarOnWindows); + options.SetShouldSuppressExceptionsInAnimations(!Options.ShouldSuppressExceptionsInAnimations); + options.SetShouldSuppressExceptionsInBehaviors(!Options.ShouldSuppressExceptionsInBehaviors); + options.SetShouldSuppressExceptionsInConverters(!Options.ShouldSuppressExceptionsInConverters); + options.SetShouldUseStatusBarBehaviorOnAndroidModalPage(!Core.Options.ShouldUseStatusBarBehaviorOnAndroidModalPage); + }); + + // Assert + Assert.False(Core.Options.ShouldUseStatusBarBehaviorOnAndroidModalPage); + Assert.True(Options.ShouldEnableSnackbarOnWindows); + Assert.True(Options.ShouldSuppressExceptionsInAnimations); + Assert.True(Options.ShouldSuppressExceptionsInBehaviors); + Assert.True(Options.ShouldSuppressExceptionsInConverters); + Assert.False(isAndroidDialogFragmentServiceInitialized); + + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted -= HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + + void HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted(object? sender, EventArgs e) + { + Core.AppBuilderExtensions.ShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted -= HandleShouldUseStatusBarBehaviorOnAndroidModalPageOptionCompleted; + isAndroidDialogFragmentServiceInitialized = true; + } + } +} +#pragma warning restore CA1416 \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs index 0b38801ce5..6285403d90 100644 --- a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs @@ -24,12 +24,13 @@ public static class AppBuilderExtensions /// initialized for public static MauiAppBuilder UseMauiCommunityToolkit(this MauiAppBuilder builder, Action? options = null) { - // Pass `null` because `options?.Invoke()` will set options on both `CommunityToolkit.Maui` and `CommunityToolkit.Maui.Core` - builder.UseMauiCommunityToolkitCore(null); - // Invokes options for both `CommunityToolkit.Maui` and `CommunityToolkit.Maui.Core` options?.Invoke(new Options(builder)); + // Pass `null` because `options?.Invoke()` will set options on both `CommunityToolkit.Maui` and `CommunityToolkit.Maui.Core` + // Be sure to call `.UseMauiCommunityToolkitCore(null)` after `options.Invoke(new Options(builder))` to ensure `CommunityToolkit.Maui.Core.Options` have already been set + builder.UseMauiCommunityToolkitCore(null); + builder.Services.AddSingleton(); builder.ConfigureMauiHandlers(static h =>