From e97fe47c27376b6768bf4fc413301e6d6488dbd9 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Mon, 25 Mar 2024 18:43:11 -0600 Subject: [PATCH 1/5] fix: PrismWindow IsRoot logic for additional scenarios --- src/Maui/Prism.Maui/Navigation/PrismWindow.cs | 213 +++++++++++------- .../Fixtures/Navigation/PrismWindowTests.cs | 104 +++++++++ .../Fixtures/TestBase.cs | 2 +- 3 files changed, 233 insertions(+), 86 deletions(-) create mode 100644 tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/Navigation/PrismWindowTests.cs diff --git a/src/Maui/Prism.Maui/Navigation/PrismWindow.cs b/src/Maui/Prism.Maui/Navigation/PrismWindow.cs index 2b8e19eccf..83a81fed8a 100644 --- a/src/Maui/Prism.Maui/Navigation/PrismWindow.cs +++ b/src/Maui/Prism.Maui/Navigation/PrismWindow.cs @@ -6,112 +6,155 @@ using Prism.Navigation.Xaml; using TabbedPage = Microsoft.Maui.Controls.TabbedPage; -namespace Prism.Navigation; - -internal class PrismWindow : Window +namespace Prism.Navigation { - public const string DefaultWindowName = "__PrismRootWindow"; - - public PrismWindow(string name = DefaultWindowName) + /// + /// Represents a window used for Prism navigation in a Maui application. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class PrismWindow : Window { - Name = name; - ModalPopping += PrismWindow_ModalPopping; - } + /// + /// The default name for the Prism window. + /// + public const string DefaultWindowName = "__PrismRootWindow"; + + /// + /// Initializes a new instance of the class with the specified name. + /// + /// The name of the window. + public PrismWindow(string name = DefaultWindowName) + { + Name = name; + ModalPopping += PrismWindow_ModalPopping; + } - public string Name { get; } + /// + /// Gets the name of the window. + /// + public string Name { get; } - public bool IsActive { get; internal set; } + /// + /// Gets or sets a value indicating whether the window is active. + /// + public bool IsActive { get; internal set; } - internal Page CurrentPage => Page is null ? null : MvvmHelpers.GetCurrentPage(Page); + /// + /// Gets the current page displayed in the window. + /// + internal Page CurrentPage => Page is null ? null : MvvmHelpers.GetCurrentPage(Page); - internal bool IsRootPage => Page switch - { - TabbedPage tabbed => tabbed.CurrentPage, - NavigationPage nav => nav.RootPage, - _ => Page - } == CurrentPage; + /// + /// Gets a value indicating whether the current page is the root page. + /// + internal bool IsRootPage => GetRootPage(Page) == CurrentPage; - [EditorBrowsable(EditorBrowsableState.Never)] - public void OnSystemBack() - { - var currentPage = CurrentPage; - if(currentPage?.Parent is NavigationPage navPage) + private Page GetRootPage(Page page) => + page switch + { + TabbedPage tabbed => GetRootPage(tabbed.CurrentPage), + NavigationPage nav => GetRootPage(nav.RootPage), + FlyoutPage flyout => GetRootPage(flyout.Detail), + _ => page + }; + + /// + /// Handles the system back button press. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void OnSystemBack() { - // The NavigationPage has already taken care of the GoBack - return; - } + var currentPage = CurrentPage; + if (currentPage?.Parent is NavigationPage navPage) + { + // The NavigationPage has already taken care of the GoBack + return; + } - var container = currentPage.GetContainerProvider(); + var container = currentPage.GetContainerProvider(); - if (IsRoot(currentPage)) - { - var app = container.Resolve() as Application; - app.Quit(); - return; - } - else if (currentPage is IDialogContainer dialogContainer) - { - if (dialogContainer.Dismiss.CanExecute(null)) - dialogContainer.Dismiss.Execute(null); - } - else - { - var navigation = container.Resolve(); - navigation.GoBackAsync(); + if (IsRoot(currentPage)) + { + var app = container.Resolve() as Application; + app.Quit(); + return; + } + else if (currentPage is IDialogContainer dialogContainer) + { + if (dialogContainer.Dismiss.CanExecute(null)) + dialogContainer.Dismiss.Execute(null); + } + else + { + var navigation = container.Resolve(); + navigation.GoBackAsync(); + } } - } - private bool IsRoot(Page page) - { - if (page == Page) return true; - - return page.Parent switch + private bool IsRoot(Page page) { - FlyoutPage flyout => IsRoot(flyout), - TabbedPage tabbed => IsRoot(tabbed), - NavigationPage navigation => IsRoot(navigation), - _ => false - }; - } + if (page == Page) return true; - private async void PrismWindow_ModalPopping(object sender, ModalPoppingEventArgs e) - { - if (PageNavigationService.NavigationSource == PageNavigationSource.Device) - { - e.Cancel = true; - var dialogModal = IDialogContainer.DialogStack.LastOrDefault(); - if (dialogModal is not null) + return page.Parent switch { - if (dialogModal.Dismiss.CanExecute(null)) - dialogModal.Dismiss.Execute(null); - } - else + FlyoutPage flyout => IsRoot(flyout), + TabbedPage tabbed => IsRoot(tabbed), + NavigationPage navigation => IsRoot(navigation), + _ => false + }; + } + + private async void PrismWindow_ModalPopping(object sender, ModalPoppingEventArgs e) + { + if (PageNavigationService.NavigationSource == PageNavigationSource.Device) { - var navService = Xaml.Navigation.GetNavigationService(e.Modal); - await navService.GoBackAsync(); + e.Cancel = true; + var dialogModal = IDialogContainer.DialogStack.LastOrDefault(); + if (dialogModal is not null) + { + if (dialogModal.Dismiss.CanExecute(null)) + dialogModal.Dismiss.Execute(null); + } + else + { + var navService = Xaml.Navigation.GetNavigationService(e.Modal); + await navService.GoBackAsync(); + } } } - } - protected override void OnActivated() - { - IsActive = true; - MvvmHelpers.InvokeViewAndViewModelAction(CurrentPage, x => x.IsActive = true); - } + /// + /// Called when the window is activated. + /// + protected override void OnActivated() + { + IsActive = true; + MvvmHelpers.InvokeViewAndViewModelAction(CurrentPage, x => x.IsActive = true); + } - protected override void OnDeactivated() - { - IsActive = false; - MvvmHelpers.InvokeViewAndViewModelAction(CurrentPage, x => x.IsActive = true); - } + /// + /// Called when the window is deactivated. + /// + protected override void OnDeactivated() + { + IsActive = false; + MvvmHelpers.InvokeViewAndViewModelAction(CurrentPage, x => x.IsActive = true); + } - protected override void OnResumed() - { - MvvmHelpers.InvokeViewAndViewModelAction(CurrentPage, x => x.OnResume()); - } + /// + /// Called when the window is resumed. + /// + protected override void OnResumed() + { + MvvmHelpers.InvokeViewAndViewModelAction(CurrentPage, x => x.OnResume()); + } - protected override void OnStopped() - { - MvvmHelpers.InvokeViewAndViewModelAction(CurrentPage, x => x.OnSleep()); + /// + /// Called when the window is stopped. + /// + protected override void OnStopped() + { + MvvmHelpers.InvokeViewAndViewModelAction(CurrentPage, x => x.OnSleep()); + } } } diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/Navigation/PrismWindowTests.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/Navigation/PrismWindowTests.cs new file mode 100644 index 0000000000..4736527bf5 --- /dev/null +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/Navigation/PrismWindowTests.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Prism.Controls; +using Prism.DryIoc.Maui.Tests.Mocks.Views; + +namespace Prism.DryIoc.Maui.Tests.Fixtures.Navigation; + +public class PrismWindowTests : TestBase +{ + public PrismWindowTests(ITestOutputHelper testOutputHelper) + : base(testOutputHelper) + { + } + + [Fact] + public void CurrentPageEqualsRootPage() + { + var mauiApp = CreateBuilder(prism => prism.CreateWindow("MockViewA")) + .Build(); + var window = GetWindow(mauiApp); + + Assert.IsType(window.CurrentPage); + Assert.IsType(window.Page); + Assert.True(window.IsRootPage); + } + + [Fact] + public void CurrentPage_FromNavigationPage_EqualsRootPage() + { + var mauiApp = CreateBuilder(prism => prism.CreateWindow("NavigationPage/MockViewA")) + .Build(); + var window = GetWindow(mauiApp); + + Assert.IsType(window.CurrentPage); + Assert.IsType(window.Page); + Assert.True(window.IsRootPage); + } + + [Fact] + public void CurrentPage_FromNavigationPage_IsNotRootPage() + { + var mauiApp = CreateBuilder(prism => prism.CreateWindow("NavigationPage/MockViewA/MockViewB")) + .Build(); + var window = GetWindow(mauiApp); + + Assert.IsType(window.CurrentPage); + Assert.IsType(window.Page); + Assert.False(window.IsRootPage); + } + + [Fact] + public void CurrentPage_IsRoot_FromTabbedPage_WithNavigationPageTab() + { + var mauiApp = CreateBuilder(prism => prism.CreateWindow(n => + n.CreateBuilder() + .AddTabbedSegment(b => b.CreateTab(t => t.AddNavigationPage().AddSegment("MockViewA")) + .CreateTab("MockViewB")).NavigateAsync())) + .Build(); + var window = GetWindow(mauiApp); + + Assert.IsType(window.CurrentPage); + Assert.IsType(window.Page); + Assert.True(window.IsRootPage); + } + + [Fact] + public void CurrentPage_IsNotRoot_FromTabbedPage_WithDeepLinkedNavigationPageTab() + { + var mauiApp = CreateBuilder(prism => prism.CreateWindow(n => + n.CreateBuilder() + .AddTabbedSegment(b => b.CreateTab(t => + t.AddNavigationPage() + .AddSegment("MockViewA") + .AddSegment("MockViewC")) + .CreateTab("MockViewB")).NavigateAsync())) + .Build(); + var window = GetWindow(mauiApp); + + Assert.IsType(window.CurrentPage); + Assert.IsType(window.Page); + Assert.False(window.IsRootPage); + } + + [Fact] + public void CurrentPage_IsRoot_WithFlyoutPage() + { + var mauiApp = CreateBuilder(prism => prism.CreateWindow(n => + n.CreateBuilder() + .AddSegment("MockHome") + .AddNavigationPage() + .AddSegment("MockViewA") + .NavigateAsync())) + .Build(); + + var window = GetWindow(mauiApp); + + Assert.IsType(window.CurrentPage); + Assert.IsType(window.Page); + Assert.True(window.IsRootPage); + } +} diff --git a/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/TestBase.cs b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/TestBase.cs index 1f699e5958..5506cf9422 100644 --- a/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/TestBase.cs +++ b/tests/Maui/Prism.DryIoc.Maui.Tests/Fixtures/TestBase.cs @@ -66,7 +66,7 @@ protected MauiAppBuilder CreateBuilder(Action configurePrism) }); } - protected static Window GetWindow(MauiApp mauiApp) + protected static PrismWindow GetWindow(MauiApp mauiApp) { var app = mauiApp.Services.GetService(); Assert.NotNull(app); From 1532dfc0f1f269dc4fd4238d7320671ae0cbd9b4 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Mon, 25 Mar 2024 19:04:58 -0600 Subject: [PATCH 2/5] chore: remove unused namespaces --- .../Tests/RegionNavigationServiceFixture.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Forms/Prism.Forms.Regions.Tests/Tests/RegionNavigationServiceFixture.cs b/tests/Forms/Prism.Forms.Regions.Tests/Tests/RegionNavigationServiceFixture.cs index b866b0bfff..0757169cc4 100644 --- a/tests/Forms/Prism.Forms.Regions.Tests/Tests/RegionNavigationServiceFixture.cs +++ b/tests/Forms/Prism.Forms.Regions.Tests/Tests/RegionNavigationServiceFixture.cs @@ -2,12 +2,10 @@ using System.Collections.Generic; using System.Linq; using Moq; -using NuGet.Frameworks; using Prism.Ioc; using Prism.Navigation; using Prism.Navigation.Regions; using Prism.Navigation.Regions.Navigation; -using Prism.Navigation.Regions.Navigation; using Xamarin.Forms; using Xunit; using Region = Prism.Navigation.Regions.Region; From 030844bc3bd46396866b919926a2790d63f7a8ff Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Tue, 26 Mar 2024 14:51:01 -0600 Subject: [PATCH 3/5] chore: remove net472 from tests --- tests/Prism.Core.Tests/Prism.Core.Tests.csproj | 2 +- tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj | 2 +- .../Prism.IocContainer.Wpf.Tests.Support.csproj | 2 +- tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj | 2 +- tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Prism.Core.Tests/Prism.Core.Tests.csproj b/tests/Prism.Core.Tests/Prism.Core.Tests.csproj index 810520b29d..0be9112c9f 100644 --- a/tests/Prism.Core.Tests/Prism.Core.Tests.csproj +++ b/tests/Prism.Core.Tests/Prism.Core.Tests.csproj @@ -1,7 +1,7 @@  - net472;net6.0 + net6.0 false diff --git a/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj b/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj index da17ee6127..a6ab86bb5c 100644 --- a/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj +++ b/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj @@ -2,7 +2,7 @@ - net472 + net6.0 false diff --git a/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj b/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj index 0152221328..0c4b56712d 100644 --- a/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj +++ b/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj @@ -2,7 +2,7 @@ - net472 + net6.0 diff --git a/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj b/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj index b3c47ff7e3..3bd083c270 100644 --- a/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj +++ b/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj @@ -2,7 +2,7 @@ - net472 + net6.0 false diff --git a/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj b/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj index 209f213d9a..84450322c6 100644 --- a/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj +++ b/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj @@ -1,7 +1,7 @@  - net472 + net6.0 false From 28e2c0b5fc67b7f6e154fd88a3cc16852ff102e4 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 27 Mar 2024 14:25:32 -0600 Subject: [PATCH 4/5] chore: set WPF tests to use net6.0-windows --- tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj | 2 +- .../Prism.IocContainer.Wpf.Tests.Support.csproj | 2 +- tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj | 2 +- tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj b/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj index a6ab86bb5c..0ffa016e7c 100644 --- a/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj +++ b/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj @@ -2,7 +2,7 @@ - net6.0 + net6.0-windows false diff --git a/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj b/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj index 0c4b56712d..32174f4a16 100644 --- a/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj +++ b/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj @@ -2,7 +2,7 @@ - net6.0 + net6.0-windows diff --git a/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj b/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj index 3bd083c270..afc1f20b89 100644 --- a/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj +++ b/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj @@ -2,7 +2,7 @@ - net6.0 + net6.0-windows false diff --git a/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj b/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj index 84450322c6..e14cf4ceb6 100644 --- a/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj +++ b/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net6.0-windows false From d06685acdcc41ef3a0d5aba1f33b09afa34af700 Mon Sep 17 00:00:00 2001 From: Dan Siegel Date: Wed, 27 Mar 2024 17:00:22 -0600 Subject: [PATCH 5/5] chore: revert target framework update --- tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj | 2 +- .../Prism.IocContainer.Wpf.Tests.Support.csproj | 2 +- tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj | 2 +- tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj b/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj index 0ffa016e7c..da17ee6127 100644 --- a/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj +++ b/tests/Wpf/Prism.DryIoc.Wpf.Tests/Prism.DryIoc.Wpf.Tests.csproj @@ -2,7 +2,7 @@ - net6.0-windows + net472 false diff --git a/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj b/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj index 32174f4a16..0152221328 100644 --- a/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj +++ b/tests/Wpf/Prism.IocContainer.Wpf.Tests.Support/Prism.IocContainer.Wpf.Tests.Support.csproj @@ -2,7 +2,7 @@ - net6.0-windows + net472 diff --git a/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj b/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj index afc1f20b89..b3c47ff7e3 100644 --- a/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj +++ b/tests/Wpf/Prism.Unity.Wpf.Tests/Prism.Unity.Wpf.Tests.csproj @@ -2,7 +2,7 @@ - net6.0-windows + net472 false diff --git a/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj b/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj index e14cf4ceb6..209f213d9a 100644 --- a/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj +++ b/tests/Wpf/Prism.Wpf.Tests/Prism.Wpf.Tests.csproj @@ -1,7 +1,7 @@  - net6.0-windows + net472 false