From 0630c5c58bcc0cad0f9eac3396b5be061e29a030 Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Wed, 25 Dec 2024 23:24:15 -0300 Subject: [PATCH 01/14] create services for DialogFragment --- .../Services/DialogFragmentService.android.cs | 192 ++++++++++++++++++ .../IDialogFragmentService.android.cs | 21 ++ .../Services/MCTFragmentLifecycle.android.cs | 99 +++++++++ 3 files changed, 312 insertions(+) create mode 100644 src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs create mode 100644 src/CommunityToolkit.Maui.Core/Services/IDialogFragmentService.android.cs create mode 100644 src/CommunityToolkit.Maui.Core/Services/MCTFragmentLifecycle.android.cs diff --git a/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs new file mode 100644 index 000000000..a12893e72 --- /dev/null +++ b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs @@ -0,0 +1,192 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Android.Content; +using Android.Views; +using AndroidX.AppCompat.App; +using DialogFragment = AndroidX.Fragment.App.DialogFragment; +using Fragment = AndroidX.Fragment.App.Fragment; +using FragmentManager = AndroidX.Fragment.App.FragmentManager; + +namespace CommunityToolkit.Maui.Core.Services; + +sealed class DialogFragmentService : IDialogFragmentService +{ + public void OnFragmentAttached(FragmentManager fm, Fragment f, Context context) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentCreated(FragmentManager fm, Fragment f, Bundle? savedInstanceState) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentDestroyed(FragmentManager fm, Fragment f) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentDetached(FragmentManager fm, Fragment f) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentPaused(FragmentManager fm, Fragment f) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentPreAttached(FragmentManager fm, Fragment f, Context context) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentPreCreated(FragmentManager fm, Fragment f, Bundle? savedInstanceState) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentResumed(FragmentManager fm, Fragment f) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentStarted(FragmentManager fm, Fragment f) + { + if (!IsDialogFragment(f, out var dialogFragment) || Microsoft.Maui.ApplicationModel.Platform.CurrentActivity is not AppCompatActivity activity) + { + return; + } + + HandleStatusBarColor(dialogFragment, activity); + } + + static void HandleStatusBarColor(DialogFragment dialogFragment, AppCompatActivity activity) + { + if (activity.Window is null) + { + return; + } + + var statusBarColor = activity.Window.StatusBarColor; + var platformColor = new Android.Graphics.Color(statusBarColor); + var dialog = dialogFragment.Dialog; + + Debug.Assert(dialog is not null); + Debug.Assert(dialog.Window is not null); + + var window = dialog.Window; + + bool isColorTransparent = platformColor == Android.Graphics.Color.Transparent; + + if (OperatingSystem.IsAndroidVersionAtLeast(30)) + { + var windowInsetsController = window.InsetsController; + var appearance = activity.Window.InsetsController?.SystemBarsAppearance; + + Debug.Assert(windowInsetsController is not null); + + if (appearance.HasValue) + { + windowInsetsController.SetSystemBarsAppearance(appearance.Value, appearance.Value); + } + else + { + windowInsetsController.SetSystemBarsAppearance( + isColorTransparent ? 0 : (int)WindowInsetsControllerAppearance.LightStatusBars, + (int)WindowInsetsControllerAppearance.LightStatusBars); + } + window.SetStatusBarColor(platformColor); + if (!OperatingSystem.IsAndroidVersionAtLeast(35)) + { + window.SetDecorFitsSystemWindows(!isColorTransparent); + } + else + { + AndroidX.Core.View.WindowCompat.SetDecorFitsSystemWindows(window, !isColorTransparent); + } + } + else + { + dialog.Window.SetStatusBarColor(platformColor); + + if (isColorTransparent) + { + window.ClearFlags(WindowManagerFlags.DrawsSystemBarBackgrounds); + window.SetFlags(WindowManagerFlags.LayoutNoLimits, WindowManagerFlags.LayoutNoLimits); + } + else + { + window.ClearFlags(WindowManagerFlags.LayoutNoLimits); + window.SetFlags(WindowManagerFlags.DrawsSystemBarBackgrounds, WindowManagerFlags.DrawsSystemBarBackgrounds); + } + } + } + + public void OnFragmentStopped(FragmentManager fm, Fragment f) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle? savedInstanceState) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + public void OnFragmentViewDestroyed(FragmentManager fm, Fragment f) + { + if (!IsDialogFragment(f, out var dialogFragment)) + { + return; + } + } + + static bool IsDialogFragment(Fragment fragment, [NotNullWhen(true)] out DialogFragment? dialogFragment) + { + dialogFragment = null; + if (fragment is DialogFragment dialog) + { + dialogFragment = dialog; + return true; + } + return false; + } +} diff --git a/src/CommunityToolkit.Maui.Core/Services/IDialogFragmentService.android.cs b/src/CommunityToolkit.Maui.Core/Services/IDialogFragmentService.android.cs new file mode 100644 index 000000000..ab7f7a9a8 --- /dev/null +++ b/src/CommunityToolkit.Maui.Core/Services/IDialogFragmentService.android.cs @@ -0,0 +1,21 @@ +using Android.Content; +using Android.Views; + +namespace CommunityToolkit.Maui.Core.Services; + +interface IDialogFragmentService +{ + void OnFragmentAttached(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f, Context context); + void OnFragmentCreated(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f, Bundle? savedInstanceState); + void OnFragmentDestroyed(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f); + void OnFragmentDetached(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f); + void OnFragmentPaused(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f); + void OnFragmentPreAttached(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f, Context context); + void OnFragmentPreCreated(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f, Bundle? savedInstanceState); + void OnFragmentResumed(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f); + void OnFragmentSaveInstanceState(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f, Bundle outState); + void OnFragmentStarted(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f); + void OnFragmentStopped(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f); + void OnFragmentViewCreated(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f, View v, Bundle? savedInstanceState); + void OnFragmentViewDestroyed(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f); +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Core/Services/MCTFragmentLifecycle.android.cs b/src/CommunityToolkit.Maui.Core/Services/MCTFragmentLifecycle.android.cs new file mode 100644 index 000000000..dd7b323e8 --- /dev/null +++ b/src/CommunityToolkit.Maui.Core/Services/MCTFragmentLifecycle.android.cs @@ -0,0 +1,99 @@ +using Android.Content; +using Android.Views; +using FragmentManager = AndroidX.Fragment.App.FragmentManager; + +namespace CommunityToolkit.Maui.Core.Services; + +sealed class MCTFragmentLifecycle : FragmentManager.FragmentLifecycleCallbacks +{ + readonly IDialogFragmentService dialogFragmentService; + + public MCTFragmentLifecycle() + { + if (IPlatformApplication.Current is null) + { + throw new InvalidOperationException("IPlatformApplication.Current is null."); + } + + dialogFragmentService = (IDialogFragmentService?)IPlatformApplication.Current.Services.GetService(typeof(IDialogFragmentService)) + ?? throw new NullReferenceException($"{nameof(IDialogFragmentService)} is not registered, make sure to call UseMauiCommunityToolkit method on during the app builder or register the service manually."); + } + + public override void OnFragmentAttached(FragmentManager fm, AndroidX.Fragment.App.Fragment f, Context context) + { + base.OnFragmentAttached(fm, f, context); + dialogFragmentService.OnFragmentAttached(fm, f, context); + } + + public override void OnFragmentCreated(FragmentManager fm, AndroidX.Fragment.App.Fragment f, Bundle? savedInstanceState) + { + base.OnFragmentCreated(fm, f, savedInstanceState); + dialogFragmentService.OnFragmentCreated(fm, f, savedInstanceState); + } + + public override void OnFragmentDestroyed(FragmentManager fm, AndroidX.Fragment.App.Fragment f) + { + base.OnFragmentDestroyed(fm, f); + dialogFragmentService.OnFragmentDestroyed(fm, f); + } + + public override void OnFragmentDetached(FragmentManager fm, AndroidX.Fragment.App.Fragment f) + { + base.OnFragmentDetached(fm, f); + dialogFragmentService.OnFragmentDetached(fm, f); + } + + public override void OnFragmentPaused(FragmentManager fm, AndroidX.Fragment.App.Fragment f) + { + base.OnFragmentPaused(fm, f); + dialogFragmentService.OnFragmentPaused(fm, f); + } + + public override void OnFragmentPreAttached(FragmentManager fm, AndroidX.Fragment.App.Fragment f, Context context) + { + base.OnFragmentPreAttached(fm, f, context); + dialogFragmentService.OnFragmentPreAttached(fm, f, context); + } + + public override void OnFragmentPreCreated(FragmentManager fm, AndroidX.Fragment.App.Fragment f, Bundle? savedInstanceState) + { + base.OnFragmentPreCreated(fm, f, savedInstanceState); + dialogFragmentService.OnFragmentPreCreated(fm, f, savedInstanceState); + } + + public override void OnFragmentResumed(FragmentManager fm, AndroidX.Fragment.App.Fragment f) + { + base.OnFragmentResumed(fm, f); + dialogFragmentService.OnFragmentResumed(fm, f); + } + + public override void OnFragmentSaveInstanceState(FragmentManager fm, AndroidX.Fragment.App.Fragment f, Bundle outState) + { + base.OnFragmentSaveInstanceState(fm, f, outState); + dialogFragmentService.OnFragmentSaveInstanceState(fm, f, outState); + } + + public override void OnFragmentStarted(FragmentManager fm, AndroidX.Fragment.App.Fragment f) + { + base.OnFragmentStarted(fm, f); + dialogFragmentService.OnFragmentStarted(fm, f); + } + + public override void OnFragmentStopped(FragmentManager fm, AndroidX.Fragment.App.Fragment f) + { + base.OnFragmentStopped(fm, f); + dialogFragmentService.OnFragmentStopped(fm, f); + } + + public override void OnFragmentViewCreated(FragmentManager fm, AndroidX.Fragment.App.Fragment f, View v, Bundle? savedInstanceState) + { + base.OnFragmentViewCreated(fm, f, v, savedInstanceState); + dialogFragmentService.OnFragmentViewCreated(fm, f, v, savedInstanceState); + } + + public override void OnFragmentViewDestroyed(FragmentManager fm, AndroidX.Fragment.App.Fragment f) + { + base.OnFragmentViewDestroyed(fm, f); + dialogFragmentService.OnFragmentViewDestroyed(fm, f); + } +} From 0a7d0c88ab7f4795fdfcc19ed10543562b181563 Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Wed, 25 Dec 2024 23:24:32 -0300 Subject: [PATCH 02/14] register the service on android during the builder phase --- .../AppBuilderExtensions.shared.cs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs index 92de26908..1e7f785fb 100644 --- a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs @@ -1,4 +1,11 @@ -namespace CommunityToolkit.Maui.Core; +#if ANDROID +using CommunityToolkit.Maui.Core.Services; +#endif +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui.LifecycleEvents; +using Microsoft.Maui.Platform; + +namespace CommunityToolkit.Maui.Core; /// /// Extensions @@ -14,6 +21,25 @@ public static class AppBuilderExtensions public static MauiAppBuilder UseMauiCommunityToolkitCore(this MauiAppBuilder builder, Action? options = default) { options?.Invoke(new Options()); +#if ANDROID + builder.Services.AddSingleton(); + + builder.ConfigureLifecycleEvents(builder => + { + builder.AddAndroid(androidBuilder => + { + androidBuilder.OnCreate((activity, bundle) => + { + if (activity is not AndroidX.AppCompat.App.AppCompatActivity componentActivity) + { + return; + } + + componentActivity.GetFragmentManager()?.RegisterFragmentLifecycleCallbacks(new MCTFragmentLifecycle(), false); + }); + }); + }); +#endif return builder; } } \ No newline at end of file From 410fe317842f02f66bbf3e6a1f11b8e8578d6b69 Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Wed, 25 Dec 2024 23:47:15 -0300 Subject: [PATCH 03/14] move interface to Interfaces folder --- .../IDialogFragmentService.android.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/CommunityToolkit.Maui.Core/{Services => Interfaces}/IDialogFragmentService.android.cs (95%) diff --git a/src/CommunityToolkit.Maui.Core/Services/IDialogFragmentService.android.cs b/src/CommunityToolkit.Maui.Core/Interfaces/IDialogFragmentService.android.cs similarity index 95% rename from src/CommunityToolkit.Maui.Core/Services/IDialogFragmentService.android.cs rename to src/CommunityToolkit.Maui.Core/Interfaces/IDialogFragmentService.android.cs index ab7f7a9a8..ccd3d4d6f 100644 --- a/src/CommunityToolkit.Maui.Core/Services/IDialogFragmentService.android.cs +++ b/src/CommunityToolkit.Maui.Core/Interfaces/IDialogFragmentService.android.cs @@ -1,9 +1,9 @@ using Android.Content; using Android.Views; -namespace CommunityToolkit.Maui.Core.Services; +namespace CommunityToolkit.Maui.Core; -interface IDialogFragmentService +public interface IDialogFragmentService { void OnFragmentAttached(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f, Context context); void OnFragmentCreated(AndroidX.Fragment.App.FragmentManager fm, AndroidX.Fragment.App.Fragment f, Bundle? savedInstanceState); From 2364d1027e8930f59c7c6c64beff490657718506 Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Wed, 25 Dec 2024 23:47:30 -0300 Subject: [PATCH 04/14] move services to CommunityToolkit.Maui --- .../Services/DialogFragmentService.android.cs | 7 +++++-- .../Services/MCTFragmentLifecycle.android.cs | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) rename src/{CommunityToolkit.Maui.Core => CommunityToolkit.Maui}/Services/DialogFragmentService.android.cs (96%) rename src/{CommunityToolkit.Maui.Core => CommunityToolkit.Maui}/Services/MCTFragmentLifecycle.android.cs (95%) diff --git a/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs b/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs similarity index 96% rename from src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs rename to src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs index a12893e72..6076cb42c 100644 --- a/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs +++ b/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs @@ -1,13 +1,16 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Android.Content; +using Android.OS; using Android.Views; using AndroidX.AppCompat.App; +using CommunityToolkit.Maui.Core; +using Debug = System.Diagnostics.Debug; using DialogFragment = AndroidX.Fragment.App.DialogFragment; using Fragment = AndroidX.Fragment.App.Fragment; using FragmentManager = AndroidX.Fragment.App.FragmentManager; -namespace CommunityToolkit.Maui.Core.Services; +namespace CommunityToolkit.Maui.Services; sealed class DialogFragmentService : IDialogFragmentService { @@ -163,7 +166,7 @@ public void OnFragmentStopped(FragmentManager fm, Fragment f) } } - public void OnFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle? savedInstanceState) + public void OnFragmentViewCreated(FragmentManager fm, Fragment f, Android.Views.View v, Bundle? savedInstanceState) { if (!IsDialogFragment(f, out var dialogFragment)) { diff --git a/src/CommunityToolkit.Maui.Core/Services/MCTFragmentLifecycle.android.cs b/src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs similarity index 95% rename from src/CommunityToolkit.Maui.Core/Services/MCTFragmentLifecycle.android.cs rename to src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs index dd7b323e8..a94909a32 100644 --- a/src/CommunityToolkit.Maui.Core/Services/MCTFragmentLifecycle.android.cs +++ b/src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs @@ -1,8 +1,9 @@ using Android.Content; -using Android.Views; +using Android.OS; +using CommunityToolkit.Maui.Core; using FragmentManager = AndroidX.Fragment.App.FragmentManager; -namespace CommunityToolkit.Maui.Core.Services; +namespace CommunityToolkit.Maui.Services; sealed class MCTFragmentLifecycle : FragmentManager.FragmentLifecycleCallbacks { @@ -85,7 +86,7 @@ public override void OnFragmentStopped(FragmentManager fm, AndroidX.Fragment.App dialogFragmentService.OnFragmentStopped(fm, f); } - public override void OnFragmentViewCreated(FragmentManager fm, AndroidX.Fragment.App.Fragment f, View v, Bundle? savedInstanceState) + public override void OnFragmentViewCreated(FragmentManager fm, AndroidX.Fragment.App.Fragment f, Android.Views.View v, Bundle? savedInstanceState) { base.OnFragmentViewCreated(fm, f, v, savedInstanceState); dialogFragmentService.OnFragmentViewCreated(fm, f, v, savedInstanceState); From 29aac74b5fd81f1521737a36c7f1f85c5251e1da Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Wed, 25 Dec 2024 23:47:58 -0300 Subject: [PATCH 05/14] add option to not use the default MCT impl --- src/CommunityToolkit.Maui/Options.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/CommunityToolkit.Maui/Options.cs b/src/CommunityToolkit.Maui/Options.cs index 64275c397..fb1f31ef9 100644 --- a/src/CommunityToolkit.Maui/Options.cs +++ b/src/CommunityToolkit.Maui/Options.cs @@ -22,6 +22,7 @@ internal Options(in MauiAppBuilder builder) : this() internal static bool ShouldSuppressExceptionsInConverters { get; private set; } internal static bool ShouldSuppressExceptionsInBehaviors { get; private set; } internal static bool ShouldEnableSnackbarOnWindows { get; private set; } + internal static bool ShouldUseMCTDialogFragment { get; private set; } = true; /// /// Will return the default value instead of throwing an exception when using . @@ -47,6 +48,15 @@ internal Options(in MauiAppBuilder builder) : this() /// public void SetShouldSuppressExceptionsInBehaviors(bool value) => ShouldSuppressExceptionsInBehaviors = value; + /// + /// Enables the use of the DialogFragment Lifecycle service for Android. + /// + /// true if yes or false if you want to implement your own. + /// + /// Default value is true. + /// + public void SetShouldUseMCTDialogFragment(bool value) => ShouldUseMCTDialogFragment = value; + /// /// Enables for Windows /// From 1e2142f807fb66a9c07d20655bc1373a7a6b21fa Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Wed, 25 Dec 2024 23:48:22 -0300 Subject: [PATCH 06/14] move the registration bits into to CommunityToolkit.Maui project --- .../AppBuilderExtensions.shared.cs | 18 +---------- .../AppBuilderExtensions.shared.cs | 30 ++++++++++++++++++- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs index 1e7f785fb..7beaf280b 100644 --- a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs @@ -22,23 +22,7 @@ public static MauiAppBuilder UseMauiCommunityToolkitCore(this MauiAppBuilder bui { options?.Invoke(new Options()); #if ANDROID - builder.Services.AddSingleton(); - - builder.ConfigureLifecycleEvents(builder => - { - builder.AddAndroid(androidBuilder => - { - androidBuilder.OnCreate((activity, bundle) => - { - if (activity is not AndroidX.AppCompat.App.AppCompatActivity componentActivity) - { - return; - } - - componentActivity.GetFragmentManager()?.RegisterFragmentLifecycleCallbacks(new MCTFragmentLifecycle(), false); - }); - }); - }); + #endif return builder; } diff --git a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs index 404f8719c..31bb697b4 100644 --- a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs @@ -1,7 +1,12 @@ -using CommunityToolkit.Maui.Core; +#if ANDROID +using CommunityToolkit.Maui.Services; +#endif +using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Core.Handlers; using CommunityToolkit.Maui.PlatformConfiguration.AndroidSpecific; using CommunityToolkit.Maui.Views; +using Microsoft.Maui.LifecycleEvents; +using Microsoft.Maui.Platform; namespace CommunityToolkit.Maui; @@ -26,6 +31,29 @@ public static MauiAppBuilder UseMauiCommunityToolkit(this MauiAppBuilder builder // Invokes options for both `CommunityToolkit.Maui` and `CommunityToolkit.Maui.Core` options?.Invoke(new Options(builder)); +#if ANDROID + if (Options.ShouldUseMCTDialogFragment) + { + builder.Services.AddSingleton(); + } + + builder.ConfigureLifecycleEvents(builder => + { + builder.AddAndroid(androidBuilder => + { + androidBuilder.OnCreate((activity, bundle) => + { + if (activity is not AndroidX.AppCompat.App.AppCompatActivity componentActivity) + { + return; + } + + componentActivity.GetFragmentManager()?.RegisterFragmentLifecycleCallbacks(new MCTFragmentLifecycle(), false); + }); + }); + }); +#endif + builder.ConfigureMauiHandlers(h => { h.AddHandler(); From 0e38c751454c2ca8c4857fd1583e233e7818a39e Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Wed, 25 Dec 2024 23:49:05 -0300 Subject: [PATCH 07/14] removed files --- .../AppBuilderExtensions.shared.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs index 7beaf280b..92de26908 100644 --- a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs @@ -1,11 +1,4 @@ -#if ANDROID -using CommunityToolkit.Maui.Core.Services; -#endif -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Maui.LifecycleEvents; -using Microsoft.Maui.Platform; - -namespace CommunityToolkit.Maui.Core; +namespace CommunityToolkit.Maui.Core; /// /// Extensions @@ -21,9 +14,6 @@ public static class AppBuilderExtensions public static MauiAppBuilder UseMauiCommunityToolkitCore(this MauiAppBuilder builder, Action? options = default) { options?.Invoke(new Options()); -#if ANDROID - -#endif return builder; } } \ No newline at end of file From b2fa42ff39863334f0b7b94f7757f9a5d127b7e4 Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Wed, 25 Dec 2024 23:51:11 -0300 Subject: [PATCH 08/14] code cleanup --- .../Services/DialogFragmentService.android.cs | 53 +------------------ 1 file changed, 2 insertions(+), 51 deletions(-) diff --git a/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs b/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs index 6076cb42c..fa17c3853 100644 --- a/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs +++ b/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs @@ -1,5 +1,4 @@ -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using Android.Content; using Android.OS; using Android.Views; @@ -16,79 +15,43 @@ sealed class DialogFragmentService : IDialogFragmentService { public void OnFragmentAttached(FragmentManager fm, Fragment f, Context context) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentCreated(FragmentManager fm, Fragment f, Bundle? savedInstanceState) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentDestroyed(FragmentManager fm, Fragment f) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentDetached(FragmentManager fm, Fragment f) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentPaused(FragmentManager fm, Fragment f) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentPreAttached(FragmentManager fm, Fragment f, Context context) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentPreCreated(FragmentManager fm, Fragment f, Bundle? savedInstanceState) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentResumed(FragmentManager fm, Fragment f) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentStarted(FragmentManager fm, Fragment f) { - if (!IsDialogFragment(f, out var dialogFragment) || Microsoft.Maui.ApplicationModel.Platform.CurrentActivity is not AppCompatActivity activity) + if (!IsDialogFragment(f, out var dialogFragment) || Platform.CurrentActivity is not AppCompatActivity activity) { return; } @@ -160,26 +123,14 @@ static void HandleStatusBarColor(DialogFragment dialogFragment, AppCompatActivit public void OnFragmentStopped(FragmentManager fm, Fragment f) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentViewCreated(FragmentManager fm, Fragment f, Android.Views.View v, Bundle? savedInstanceState) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } public void OnFragmentViewDestroyed(FragmentManager fm, Fragment f) { - if (!IsDialogFragment(f, out var dialogFragment)) - { - return; - } } static bool IsDialogFragment(Fragment fragment, [NotNullWhen(true)] out DialogFragment? dialogFragment) From 03eb3cfb92bcd2f26ed8701f314bf4a4d51c669d Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Thu, 26 Dec 2024 13:59:46 -0300 Subject: [PATCH 09/14] add trace --- src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs index 31bb697b4..b6936c326 100644 --- a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs @@ -7,6 +7,7 @@ using CommunityToolkit.Maui.Views; using Microsoft.Maui.LifecycleEvents; using Microsoft.Maui.Platform; +using System.Diagnostics; namespace CommunityToolkit.Maui; @@ -45,6 +46,7 @@ public static MauiAppBuilder UseMauiCommunityToolkit(this MauiAppBuilder builder { if (activity is not AndroidX.AppCompat.App.AppCompatActivity componentActivity) { + Trace.WriteLine("Activity is not an AppCompatActivity, cannot register fragment lifecycle callbacks."); return; } From d7a53c7a7c91020775e172a2b9312902f9fd9341 Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Thu, 26 Dec 2024 14:01:25 -0300 Subject: [PATCH 10/14] remove debug assert --- .../Services/DialogFragmentService.android.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs b/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs index fa17c3853..4cfab6964 100644 --- a/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs +++ b/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs @@ -82,7 +82,11 @@ static void HandleStatusBarColor(DialogFragment dialogFragment, AppCompatActivit var windowInsetsController = window.InsetsController; var appearance = activity.Window.InsetsController?.SystemBarsAppearance; - Debug.Assert(windowInsetsController is not null); + if (windowInsetsController is null) + { + System.Diagnostics.Trace.WriteLine("WindowInsetsController is null, cannot set system bars appearance."); + return; + } if (appearance.HasValue) { From 048a02423755cc2899f13e962d28bcc3b5d75129 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Fri, 27 Dec 2024 12:35:06 -0800 Subject: [PATCH 11/14] Update Naming --- .../AppBuilderExtensions.shared.cs | 92 ++++++++++--------- src/CommunityToolkit.Maui/Options.cs | 4 +- .../Services/DialogFragmentService.android.cs | 2 +- .../Services/DialogFragmentService.shared.cs | 6 ++ .../Services/MCTFragmentLifecycle.android.cs | 15 +-- 5 files changed, 61 insertions(+), 58 deletions(-) create mode 100644 src/CommunityToolkit.Maui/Services/DialogFragmentService.shared.cs diff --git a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs index b6936c326..6c7da920b 100644 --- a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs @@ -1,13 +1,11 @@ -#if ANDROID -using CommunityToolkit.Maui.Services; -#endif +using System.Diagnostics; using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Core.Handlers; using CommunityToolkit.Maui.PlatformConfiguration.AndroidSpecific; +using CommunityToolkit.Maui.Services; using CommunityToolkit.Maui.Views; using Microsoft.Maui.LifecycleEvents; using Microsoft.Maui.Platform; -using System.Diagnostics; namespace CommunityToolkit.Maui; @@ -16,55 +14,65 @@ namespace CommunityToolkit.Maui; /// public static class AppBuilderExtensions { - /// - /// Initializes the .NET MAUI Community Toolkit Library - /// - /// generated by - /// - /// initialized for - public static MauiAppBuilder UseMauiCommunityToolkit(this MauiAppBuilder builder, Action? options = default) - { - // Pass `null` because `options?.Invoke()` will set options on both `CommunityToolkit.Maui` and `CommunityToolkit.Maui.Core` - builder.UseMauiCommunityToolkitCore(null); - - builder.Services.AddSingleton(); + /// + /// Initializes the .NET MAUI Community Toolkit Library + /// + /// generated by + /// + /// 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)); + // Invokes options for both `CommunityToolkit.Maui` and `CommunityToolkit.Maui.Core` + options?.Invoke(new Options(builder)); #if ANDROID - if (Options.ShouldUseMCTDialogFragment) - { - builder.Services.AddSingleton(); - } + if (Options.ShouldUseStatusBarBehaviorOnAndroidModalPage) + { + builder.Services.AddSingleton(); - builder.ConfigureLifecycleEvents(builder => - { - builder.AddAndroid(androidBuilder => + builder.ConfigureLifecycleEvents(static lifecycleBuilder => { - androidBuilder.OnCreate((activity, bundle) => + lifecycleBuilder.AddAndroid(static androidBuilder => { - if (activity is not AndroidX.AppCompat.App.AppCompatActivity componentActivity) + androidBuilder.OnCreate(static (activity, _) => { - Trace.WriteLine("Activity is not an AppCompatActivity, cannot register fragment lifecycle callbacks."); - return; - } + if (activity is not AndroidX.AppCompat.App.AppCompatActivity componentActivity) + { + Trace.WriteLine($"Unable to Modify Android StatusBar On ModalPage: Activity {activity.LocalClassName} must be an {nameof(AndroidX.AppCompat.App.AppCompatActivity)}"); + return; + } - componentActivity.GetFragmentManager()?.RegisterFragmentLifecycleCallbacks(new MCTFragmentLifecycle(), false); + if (componentActivity.GetFragmentManager() is not AndroidX.Fragment.App.FragmentManager fragmentManager) + { + Trace.WriteLine($"Unable to Modify Android StatusBar On ModalPage: Unable to retrieve fragment manager from {nameof(AndroidX.AppCompat.App.AppCompatActivity)}"); + return; + } + + var dialogFragmentService = IPlatformApplication.Current?.Services.GetRequiredService() + ?? throw new InvalidOperationException($"Unable to retrieve {nameof(IDialogFragmentService)}"); + + + fragmentManager.RegisterFragmentLifecycleCallbacks(new FragmentLifecycleManager(dialogFragmentService), false); + }); }); }); - }); + } #endif - builder.ConfigureMauiHandlers(h => - { - h.AddHandler(); - h.AddHandler(); - h.AddHandler(); - }); + builder.Services.AddSingleton(); + + builder.ConfigureMauiHandlers(static h => + { + h.AddHandler(); + h.AddHandler(); + h.AddHandler(); + }); - Popup.RemapForControls(); - NavigationBar.RemapForControls(); - return builder; - } + Popup.RemapForControls(); + NavigationBar.RemapForControls(); + return builder; + } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/Options.cs b/src/CommunityToolkit.Maui/Options.cs index fb1f31ef9..12cfb759b 100644 --- a/src/CommunityToolkit.Maui/Options.cs +++ b/src/CommunityToolkit.Maui/Options.cs @@ -18,11 +18,11 @@ internal Options(in MauiAppBuilder builder) : this() this.builder = builder; } + internal static bool ShouldUseStatusBarBehaviorOnAndroidModalPage { get; private set; } = true; internal static bool ShouldSuppressExceptionsInAnimations { get; private set; } internal static bool ShouldSuppressExceptionsInConverters { get; private set; } internal static bool ShouldSuppressExceptionsInBehaviors { get; private set; } internal static bool ShouldEnableSnackbarOnWindows { get; private set; } - internal static bool ShouldUseMCTDialogFragment { get; private set; } = true; /// /// Will return the default value instead of throwing an exception when using . @@ -55,7 +55,7 @@ internal Options(in MauiAppBuilder builder) : this() /// /// Default value is true. /// - public void SetShouldUseMCTDialogFragment(bool value) => ShouldUseMCTDialogFragment = value; + public void SetShouldUseStatusBarBehaviorOnAndroidModalPage(bool value) => ShouldUseStatusBarBehaviorOnAndroidModalPage = value; /// /// Enables for Windows diff --git a/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs b/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs index 4cfab6964..42126c0b7 100644 --- a/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs +++ b/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs @@ -11,7 +11,7 @@ namespace CommunityToolkit.Maui.Services; -sealed class DialogFragmentService : IDialogFragmentService +sealed partial class DialogFragmentService : IDialogFragmentService { public void OnFragmentAttached(FragmentManager fm, Fragment f, Context context) { diff --git a/src/CommunityToolkit.Maui/Services/DialogFragmentService.shared.cs b/src/CommunityToolkit.Maui/Services/DialogFragmentService.shared.cs new file mode 100644 index 000000000..5585512e3 --- /dev/null +++ b/src/CommunityToolkit.Maui/Services/DialogFragmentService.shared.cs @@ -0,0 +1,6 @@ +namespace CommunityToolkit.Maui.Services; + +sealed partial class DialogFragmentService +{ + +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs b/src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs index a94909a32..7c72de93d 100644 --- a/src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs +++ b/src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs @@ -5,20 +5,9 @@ namespace CommunityToolkit.Maui.Services; -sealed class MCTFragmentLifecycle : FragmentManager.FragmentLifecycleCallbacks +sealed class FragmentLifecycleManager(IDialogFragmentService dialogFragmentService) : FragmentManager.FragmentLifecycleCallbacks { - readonly IDialogFragmentService dialogFragmentService; - - public MCTFragmentLifecycle() - { - if (IPlatformApplication.Current is null) - { - throw new InvalidOperationException("IPlatformApplication.Current is null."); - } - - dialogFragmentService = (IDialogFragmentService?)IPlatformApplication.Current.Services.GetService(typeof(IDialogFragmentService)) - ?? throw new NullReferenceException($"{nameof(IDialogFragmentService)} is not registered, make sure to call UseMauiCommunityToolkit method on during the app builder or register the service manually."); - } + readonly IDialogFragmentService dialogFragmentService = dialogFragmentService; public override void OnFragmentAttached(FragmentManager fm, AndroidX.Fragment.App.Fragment f, Context context) { From 6704cd750eb4dbd1c869f2ba025fb3384afc0015 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Fri, 27 Dec 2024 12:44:41 -0800 Subject: [PATCH 12/14] Move to `CommunityToolkit.Maui.Core` --- .../AppBuilderExtensions.shared.cs | 45 +++++++++++++++- src/CommunityToolkit.Maui.Core/Options.cs | 10 ++++ .../Services/DialogFragmentService.android.cs | 51 +++++++++---------- .../Services/DialogFragmentService.shared.cs | 2 +- .../FragmentLifecycleManager.android.cs} | 4 +- .../AppBuilderExtensions.shared.cs | 35 ------------- src/CommunityToolkit.Maui/Options.cs | 12 +---- 7 files changed, 81 insertions(+), 78 deletions(-) rename src/{CommunityToolkit.Maui => CommunityToolkit.Maui.Core}/Services/DialogFragmentService.android.cs (66%) rename src/{CommunityToolkit.Maui => CommunityToolkit.Maui.Core}/Services/DialogFragmentService.shared.cs (52%) rename src/{CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs => CommunityToolkit.Maui.Core/Services/FragmentLifecycleManager.android.cs} (97%) diff --git a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs index 92de26908..e61f5c1d1 100644 --- a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs @@ -1,4 +1,10 @@ -namespace CommunityToolkit.Maui.Core; +using System.Diagnostics; +using CommunityToolkit.Maui.Core.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui.LifecycleEvents; +using Microsoft.Maui.Platform; + +namespace CommunityToolkit.Maui.Core; /// /// Extensions @@ -11,9 +17,44 @@ public static class AppBuilderExtensions /// generated by /// /// initialized for - public static MauiAppBuilder UseMauiCommunityToolkitCore(this MauiAppBuilder builder, Action? options = default) + public static MauiAppBuilder UseMauiCommunityToolkitCore(this MauiAppBuilder builder, Action? options = null) { options?.Invoke(new Options()); + +#if ANDROID + if (Options.ShouldUseStatusBarBehaviorOnAndroidModalPage) + { + builder.Services.AddSingleton(); + + builder.ConfigureLifecycleEvents(static lifecycleBuilder => + { + lifecycleBuilder.AddAndroid(static androidBuilder => + { + androidBuilder.OnCreate(static (activity, _) => + { + if (activity is not AndroidX.AppCompat.App.AppCompatActivity componentActivity) + { + Trace.WriteLine($"Unable to Modify Android StatusBar On ModalPage: Activity {activity.LocalClassName} must be an {nameof(AndroidX.AppCompat.App.AppCompatActivity)}"); + return; + } + + if (componentActivity.GetFragmentManager() is not AndroidX.Fragment.App.FragmentManager fragmentManager) + { + Trace.WriteLine($"Unable to Modify Android StatusBar On ModalPage: Unable to retrieve fragment manager from {nameof(AndroidX.AppCompat.App.AppCompatActivity)}"); + return; + } + + var dialogFragmentService = IPlatformApplication.Current?.Services.GetRequiredService() + ?? throw new InvalidOperationException($"Unable to retrieve {nameof(IDialogFragmentService)}"); + + + fragmentManager.RegisterFragmentLifecycleCallbacks(new FragmentLifecycleManager(dialogFragmentService), false); + }); + }); + }); + } +#endif + return builder; } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Core/Options.cs b/src/CommunityToolkit.Maui.Core/Options.cs index 7acaf4680..887114830 100644 --- a/src/CommunityToolkit.Maui.Core/Options.cs +++ b/src/CommunityToolkit.Maui.Core/Options.cs @@ -5,4 +5,14 @@ namespace CommunityToolkit.Maui.Core; /// public class Options { + internal static bool ShouldUseStatusBarBehaviorOnAndroidModalPage { get; private set; } = true; + + /// + /// Enables the use of the DialogFragment Lifecycle service for Android. + /// + /// true if yes or false if you want to implement your own. + /// + /// Default value is true. + /// + public void SetShouldUseStatusBarBehaviorOnAndroidModalPage(bool value) => ShouldUseStatusBarBehaviorOnAndroidModalPage = value; } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs similarity index 66% rename from src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs rename to src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs index 42126c0b7..42eb8ef05 100644 --- a/src/CommunityToolkit.Maui/Services/DialogFragmentService.android.cs +++ b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs @@ -1,15 +1,12 @@ using System.Diagnostics.CodeAnalysis; using Android.Content; -using Android.OS; using Android.Views; using AndroidX.AppCompat.App; -using CommunityToolkit.Maui.Core; -using Debug = System.Diagnostics.Debug; using DialogFragment = AndroidX.Fragment.App.DialogFragment; using Fragment = AndroidX.Fragment.App.Fragment; using FragmentManager = AndroidX.Fragment.App.FragmentManager; -namespace CommunityToolkit.Maui.Services; +namespace CommunityToolkit.Maui.Core.Services; sealed partial class DialogFragmentService : IDialogFragmentService { @@ -51,7 +48,7 @@ public void OnFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle o public void OnFragmentStarted(FragmentManager fm, Fragment f) { - if (!IsDialogFragment(f, out var dialogFragment) || Platform.CurrentActivity is not AppCompatActivity activity) + if (!TryConvertToDialogFragment(f, out var dialogFragment) || Microsoft.Maui.ApplicationModel.Platform.CurrentActivity is not AppCompatActivity activity) { return; } @@ -68,18 +65,16 @@ static void HandleStatusBarColor(DialogFragment dialogFragment, AppCompatActivit var statusBarColor = activity.Window.StatusBarColor; var platformColor = new Android.Graphics.Color(statusBarColor); - var dialog = dialogFragment.Dialog; - - Debug.Assert(dialog is not null); - Debug.Assert(dialog.Window is not null); - - var window = dialog.Window; + if (dialogFragment.Dialog?.Window is not Window dialogWindow) + { + throw new InvalidOperationException("Dialog window cannot be null"); + } - bool isColorTransparent = platformColor == Android.Graphics.Color.Transparent; + var isColorTransparent = platformColor == Android.Graphics.Color.Transparent; if (OperatingSystem.IsAndroidVersionAtLeast(30)) { - var windowInsetsController = window.InsetsController; + var windowInsetsController = dialogWindow.InsetsController; var appearance = activity.Window.InsetsController?.SystemBarsAppearance; if (windowInsetsController is null) @@ -98,29 +93,31 @@ static void HandleStatusBarColor(DialogFragment dialogFragment, AppCompatActivit isColorTransparent ? 0 : (int)WindowInsetsControllerAppearance.LightStatusBars, (int)WindowInsetsControllerAppearance.LightStatusBars); } - window.SetStatusBarColor(platformColor); + + dialogWindow.SetStatusBarColor(platformColor); + if (!OperatingSystem.IsAndroidVersionAtLeast(35)) { - window.SetDecorFitsSystemWindows(!isColorTransparent); + dialogWindow.SetDecorFitsSystemWindows(!isColorTransparent); } else { - AndroidX.Core.View.WindowCompat.SetDecorFitsSystemWindows(window, !isColorTransparent); + AndroidX.Core.View.WindowCompat.SetDecorFitsSystemWindows(dialogWindow, !isColorTransparent); } } else { - dialog.Window.SetStatusBarColor(platformColor); + dialogWindow.SetStatusBarColor(platformColor); if (isColorTransparent) { - window.ClearFlags(WindowManagerFlags.DrawsSystemBarBackgrounds); - window.SetFlags(WindowManagerFlags.LayoutNoLimits, WindowManagerFlags.LayoutNoLimits); + dialogWindow.ClearFlags(WindowManagerFlags.DrawsSystemBarBackgrounds); + dialogWindow.SetFlags(WindowManagerFlags.LayoutNoLimits, WindowManagerFlags.LayoutNoLimits); } else { - window.ClearFlags(WindowManagerFlags.LayoutNoLimits); - window.SetFlags(WindowManagerFlags.DrawsSystemBarBackgrounds, WindowManagerFlags.DrawsSystemBarBackgrounds); + dialogWindow.ClearFlags(WindowManagerFlags.LayoutNoLimits); + dialogWindow.SetFlags(WindowManagerFlags.DrawsSystemBarBackgrounds, WindowManagerFlags.DrawsSystemBarBackgrounds); } } } @@ -137,14 +134,16 @@ public void OnFragmentViewDestroyed(FragmentManager fm, Fragment f) { } - static bool IsDialogFragment(Fragment fragment, [NotNullWhen(true)] out DialogFragment? dialogFragment) + static bool TryConvertToDialogFragment(Fragment fragment, [NotNullWhen(true)] out DialogFragment? dialogFragment) { dialogFragment = null; - if (fragment is DialogFragment dialog) + + if (fragment is not DialogFragment dialog) { - dialogFragment = dialog; - return true; + return false; } - return false; + + dialogFragment = dialog; + return true; } } diff --git a/src/CommunityToolkit.Maui/Services/DialogFragmentService.shared.cs b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.shared.cs similarity index 52% rename from src/CommunityToolkit.Maui/Services/DialogFragmentService.shared.cs rename to src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.shared.cs index 5585512e3..45ded5a1d 100644 --- a/src/CommunityToolkit.Maui/Services/DialogFragmentService.shared.cs +++ b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.shared.cs @@ -1,4 +1,4 @@ -namespace CommunityToolkit.Maui.Services; +namespace CommunityToolkit.Maui.Core.Services; sealed partial class DialogFragmentService { diff --git a/src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs b/src/CommunityToolkit.Maui.Core/Services/FragmentLifecycleManager.android.cs similarity index 97% rename from src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs rename to src/CommunityToolkit.Maui.Core/Services/FragmentLifecycleManager.android.cs index 7c72de93d..6164bbfc8 100644 --- a/src/CommunityToolkit.Maui/Services/MCTFragmentLifecycle.android.cs +++ b/src/CommunityToolkit.Maui.Core/Services/FragmentLifecycleManager.android.cs @@ -1,9 +1,7 @@ using Android.Content; -using Android.OS; -using CommunityToolkit.Maui.Core; using FragmentManager = AndroidX.Fragment.App.FragmentManager; -namespace CommunityToolkit.Maui.Services; +namespace CommunityToolkit.Maui.Core.Services; sealed class FragmentLifecycleManager(IDialogFragmentService dialogFragmentService) : FragmentManager.FragmentLifecycleCallbacks { diff --git a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs index 6c7da920b..ee69f9c49 100644 --- a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs @@ -2,7 +2,6 @@ using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Core.Handlers; using CommunityToolkit.Maui.PlatformConfiguration.AndroidSpecific; -using CommunityToolkit.Maui.Services; using CommunityToolkit.Maui.Views; using Microsoft.Maui.LifecycleEvents; using Microsoft.Maui.Platform; @@ -28,40 +27,6 @@ public static MauiAppBuilder UseMauiCommunityToolkit(this MauiAppBuilder builder // Invokes options for both `CommunityToolkit.Maui` and `CommunityToolkit.Maui.Core` options?.Invoke(new Options(builder)); -#if ANDROID - if (Options.ShouldUseStatusBarBehaviorOnAndroidModalPage) - { - builder.Services.AddSingleton(); - - builder.ConfigureLifecycleEvents(static lifecycleBuilder => - { - lifecycleBuilder.AddAndroid(static androidBuilder => - { - androidBuilder.OnCreate(static (activity, _) => - { - if (activity is not AndroidX.AppCompat.App.AppCompatActivity componentActivity) - { - Trace.WriteLine($"Unable to Modify Android StatusBar On ModalPage: Activity {activity.LocalClassName} must be an {nameof(AndroidX.AppCompat.App.AppCompatActivity)}"); - return; - } - - if (componentActivity.GetFragmentManager() is not AndroidX.Fragment.App.FragmentManager fragmentManager) - { - Trace.WriteLine($"Unable to Modify Android StatusBar On ModalPage: Unable to retrieve fragment manager from {nameof(AndroidX.AppCompat.App.AppCompatActivity)}"); - return; - } - - var dialogFragmentService = IPlatformApplication.Current?.Services.GetRequiredService() - ?? throw new InvalidOperationException($"Unable to retrieve {nameof(IDialogFragmentService)}"); - - - fragmentManager.RegisterFragmentLifecycleCallbacks(new FragmentLifecycleManager(dialogFragmentService), false); - }); - }); - }); - } -#endif - builder.Services.AddSingleton(); builder.ConfigureMauiHandlers(static h => diff --git a/src/CommunityToolkit.Maui/Options.cs b/src/CommunityToolkit.Maui/Options.cs index 12cfb759b..7f14ba575 100644 --- a/src/CommunityToolkit.Maui/Options.cs +++ b/src/CommunityToolkit.Maui/Options.cs @@ -17,8 +17,7 @@ internal Options(in MauiAppBuilder builder) : this() { this.builder = builder; } - - internal static bool ShouldUseStatusBarBehaviorOnAndroidModalPage { get; private set; } = true; + internal static bool ShouldSuppressExceptionsInAnimations { get; private set; } internal static bool ShouldSuppressExceptionsInConverters { get; private set; } internal static bool ShouldSuppressExceptionsInBehaviors { get; private set; } @@ -48,15 +47,6 @@ internal Options(in MauiAppBuilder builder) : this() /// public void SetShouldSuppressExceptionsInBehaviors(bool value) => ShouldSuppressExceptionsInBehaviors = value; - /// - /// Enables the use of the DialogFragment Lifecycle service for Android. - /// - /// true if yes or false if you want to implement your own. - /// - /// Default value is true. - /// - public void SetShouldUseStatusBarBehaviorOnAndroidModalPage(bool value) => ShouldUseStatusBarBehaviorOnAndroidModalPage = value; - /// /// Enables for Windows /// From 5753c2d2f8ffe3c2a3d603c2c24b5e70e8d96f35 Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Fri, 27 Dec 2024 12:53:37 -0800 Subject: [PATCH 13/14] `dotnet format` --- src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs | 5 +---- src/CommunityToolkit.Maui/Options.cs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs index ee69f9c49..1e5ae387f 100644 --- a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs @@ -1,10 +1,7 @@ -using System.Diagnostics; -using CommunityToolkit.Maui.Core; +using CommunityToolkit.Maui.Core; using CommunityToolkit.Maui.Core.Handlers; using CommunityToolkit.Maui.PlatformConfiguration.AndroidSpecific; using CommunityToolkit.Maui.Views; -using Microsoft.Maui.LifecycleEvents; -using Microsoft.Maui.Platform; namespace CommunityToolkit.Maui; diff --git a/src/CommunityToolkit.Maui/Options.cs b/src/CommunityToolkit.Maui/Options.cs index 7f14ba575..64275c397 100644 --- a/src/CommunityToolkit.Maui/Options.cs +++ b/src/CommunityToolkit.Maui/Options.cs @@ -17,7 +17,7 @@ internal Options(in MauiAppBuilder builder) : this() { this.builder = builder; } - + internal static bool ShouldSuppressExceptionsInAnimations { get; private set; } internal static bool ShouldSuppressExceptionsInConverters { get; private set; } internal static bool ShouldSuppressExceptionsInBehaviors { get; private set; } From 6e45f207f17973d3287e7fc09cf804fb231c01df Mon Sep 17 00:00:00 2001 From: Brandon Minnick <13558917+brminnick@users.noreply.github.com> Date: Fri, 27 Dec 2024 12:54:42 -0800 Subject: [PATCH 14/14] `dotnet format` --- .../AppBuilderExtensions.shared.cs | 4 +- src/CommunityToolkit.Maui.Core/Options.cs | 20 ++++---- .../Services/DialogFragmentService.android.cs | 10 ++-- .../Services/DialogFragmentService.shared.cs | 2 +- .../FragmentLifecycleManager.android.cs | 2 +- .../AppBuilderExtensions.shared.cs | 46 +++++++++---------- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs index e61f5c1d1..8b9c3464e 100644 --- a/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui.Core/AppBuilderExtensions.shared.cs @@ -20,7 +20,7 @@ public static class AppBuilderExtensions public static MauiAppBuilder UseMauiCommunityToolkitCore(this MauiAppBuilder builder, Action? options = null) { options?.Invoke(new Options()); - + #if ANDROID if (Options.ShouldUseStatusBarBehaviorOnAndroidModalPage) { @@ -54,7 +54,7 @@ public static MauiAppBuilder UseMauiCommunityToolkitCore(this MauiAppBuilder bui }); } #endif - + return builder; } } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Core/Options.cs b/src/CommunityToolkit.Maui.Core/Options.cs index 887114830..4f6e400f4 100644 --- a/src/CommunityToolkit.Maui.Core/Options.cs +++ b/src/CommunityToolkit.Maui.Core/Options.cs @@ -5,14 +5,14 @@ namespace CommunityToolkit.Maui.Core; /// public class Options { - internal static bool ShouldUseStatusBarBehaviorOnAndroidModalPage { get; private set; } = true; - - /// - /// Enables the use of the DialogFragment Lifecycle service for Android. - /// - /// true if yes or false if you want to implement your own. - /// - /// Default value is true. - /// - public void SetShouldUseStatusBarBehaviorOnAndroidModalPage(bool value) => ShouldUseStatusBarBehaviorOnAndroidModalPage = value; + internal static bool ShouldUseStatusBarBehaviorOnAndroidModalPage { get; private set; } = true; + + /// + /// Enables the use of the DialogFragment Lifecycle service for Android. + /// + /// true if yes or false if you want to implement your own. + /// + /// Default value is true. + /// + public void SetShouldUseStatusBarBehaviorOnAndroidModalPage(bool value) => ShouldUseStatusBarBehaviorOnAndroidModalPage = value; } \ 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 42eb8ef05..af4d21924 100644 --- a/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs +++ b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.android.cs @@ -93,9 +93,9 @@ static void HandleStatusBarColor(DialogFragment dialogFragment, AppCompatActivit isColorTransparent ? 0 : (int)WindowInsetsControllerAppearance.LightStatusBars, (int)WindowInsetsControllerAppearance.LightStatusBars); } - + dialogWindow.SetStatusBarColor(platformColor); - + if (!OperatingSystem.IsAndroidVersionAtLeast(35)) { dialogWindow.SetDecorFitsSystemWindows(!isColorTransparent); @@ -137,13 +137,13 @@ public void OnFragmentViewDestroyed(FragmentManager fm, Fragment f) static bool TryConvertToDialogFragment(Fragment fragment, [NotNullWhen(true)] out DialogFragment? dialogFragment) { dialogFragment = null; - + if (fragment is not DialogFragment dialog) { return false; } - + dialogFragment = dialog; return true; } -} +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.shared.cs b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.shared.cs index 45ded5a1d..366ba38cc 100644 --- a/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.shared.cs +++ b/src/CommunityToolkit.Maui.Core/Services/DialogFragmentService.shared.cs @@ -2,5 +2,5 @@ namespace CommunityToolkit.Maui.Core.Services; sealed partial class DialogFragmentService { - + } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Core/Services/FragmentLifecycleManager.android.cs b/src/CommunityToolkit.Maui.Core/Services/FragmentLifecycleManager.android.cs index 6164bbfc8..20accbe20 100644 --- a/src/CommunityToolkit.Maui.Core/Services/FragmentLifecycleManager.android.cs +++ b/src/CommunityToolkit.Maui.Core/Services/FragmentLifecycleManager.android.cs @@ -84,4 +84,4 @@ public override void OnFragmentViewDestroyed(FragmentManager fm, AndroidX.Fragme base.OnFragmentViewDestroyed(fm, f); dialogFragmentService.OnFragmentViewDestroyed(fm, f); } -} +} \ No newline at end of file diff --git a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs index 1e5ae387f..5e45d440e 100644 --- a/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs +++ b/src/CommunityToolkit.Maui/AppBuilderExtensions.shared.cs @@ -10,31 +10,31 @@ namespace CommunityToolkit.Maui; /// public static class AppBuilderExtensions { - /// - /// Initializes the .NET MAUI Community Toolkit Library - /// - /// generated by - /// - /// 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); + /// + /// Initializes the .NET MAUI Community Toolkit Library + /// + /// generated by + /// + /// 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)); + // Invokes options for both `CommunityToolkit.Maui` and `CommunityToolkit.Maui.Core` + options?.Invoke(new Options(builder)); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); - builder.ConfigureMauiHandlers(static h => - { - h.AddHandler(); - h.AddHandler(); - h.AddHandler(); - }); + builder.ConfigureMauiHandlers(static h => + { + h.AddHandler(); + h.AddHandler(); + h.AddHandler(); + }); - Popup.RemapForControls(); - NavigationBar.RemapForControls(); - return builder; - } + Popup.RemapForControls(); + NavigationBar.RemapForControls(); + return builder; + } } \ No newline at end of file