From dcbb2c0f3cb1adcb0d14d8679cf94384edb48434 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Thu, 18 May 2023 08:51:41 -0500 Subject: [PATCH] Wait for root page to load before processing modal (#15037) * Wait for root page to load before processing modal * Update ModalTests.iOS.cs --- .../ModalNavigationManager.cs | 22 ++++++++++--- .../DeviceTests/Elements/Modal/ModalTests.cs | 33 ++++++++++++++++--- .../Elements/Modal/ModalTests.iOS.cs | 5 +-- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.cs b/src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.cs index 01b7acd4667a..05f05721d60c 100644 --- a/src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.cs +++ b/src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.cs @@ -324,7 +324,7 @@ void ClearModalPages(bool xplat = false, bool platform = false) // Windows and Android have basically the same requirement that // we need to wait for the current page to finish loading before - // satsifying Modal requests. + // satisfying Modal requests. // This will most likely change once we switch Android to using dialog fragments #if WINDOWS || ANDROID IDisposable? _platformPageWatchingForLoaded; @@ -338,22 +338,33 @@ async Task SyncModalStackWhenPlatformIsReadyAsync() await SyncPlatformModalStackAsync().ConfigureAwait(false); } else if (_window.IsActivated && - _window?.Page?.Handler is not null) + _window?.Page?.Handler is not null) { if (CurrentPlatformPage.Handler is null) { CurrentPlatformPage.HandlerChanged += OnCurrentPlatformPageHandlerChanged; - ; + _platformPageWatchingForLoaded = new ActionDisposable(() => { CurrentPlatformPage.HandlerChanged -= OnCurrentPlatformPageHandlerChanged; }); } + // This accounts for cases where we swap the root page out + // We want to wait for that to finish loading before processing any modal changes +#if ANDROID + else if (!_window.Page.IsLoadedOnPlatform()) + { + var windowPage = _window.Page; + _platformPageWatchingForLoaded = + windowPage.OnLoaded(() => OnCurrentPlatformPageLoaded(windowPage, EventArgs.Empty)); + } +#endif else if (!CurrentPlatformPage.IsLoadedOnPlatform() && - CurrentPlatformPage.Handler is not null) + CurrentPlatformPage.Handler is not null) { + var currentPlatformPage = CurrentPlatformPage; _platformPageWatchingForLoaded = - CurrentPlatformPage.OnLoaded(() => OnCurrentPlatformPageLoaded(_platformPageWatchingForLoaded, EventArgs.Empty)); + currentPlatformPage.OnLoaded(() => OnCurrentPlatformPageLoaded(currentPlatformPage, EventArgs.Empty)); } } } @@ -382,6 +393,7 @@ bool IsModalPlatformReady bool result = _window?.Page?.Handler is not null && _window.IsActivated + && _window.Page.IsLoadedOnPlatform() && CurrentPlatformPage?.Handler is not null && CurrentPlatformPage.IsLoadedOnPlatform(); diff --git a/src/Controls/tests/DeviceTests/Elements/Modal/ModalTests.cs b/src/Controls/tests/DeviceTests/Elements/Modal/ModalTests.cs index f2efdfc8f52e..6ec4a3ab78c7 100644 --- a/src/Controls/tests/DeviceTests/Elements/Modal/ModalTests.cs +++ b/src/Controls/tests/DeviceTests/Elements/Modal/ModalTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.Controls.Handlers; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.DeviceTests.Stubs; using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; @@ -447,6 +448,23 @@ await CreateHandlerAndAddToWindow(window, async (handler) => } + [Theory] + [ClassData(typeof(PageTypes))] + public async Task SwappingRootPageWhileModalPageIsOpenDoesntCrash(Page rootPage, Page newRootPage) + { + SetupBuilder(); + + await CreateHandlerAndAddToWindow(rootPage, + async (_) => + { + var modalPage = new NavigationPage(new ContentPage()); + await rootPage.Navigation.PushModalAsync(modalPage); + await OnLoadedAsync(modalPage); + rootPage.Window.Page = newRootPage; + await OnLoadedAsync(newRootPage); + }); + } + [Theory] [ClassData(typeof(PageTypes))] public async Task BasicPushAndPop(Page rootPage, Page modalPage) @@ -456,7 +474,8 @@ public async Task BasicPushAndPop(Page rootPage, Page modalPage) await CreateHandlerAndAddToWindow(rootPage, async (_) => { - var currentPage = (rootPage as IPageContainer).CurrentPage; + var currentPage = rootPage.GetCurrentPage(); + await currentPage.Navigation.PushModalAsync(modalPage); await OnLoadedAsync(modalPage); Assert.Equal(1, currentPage.Navigation.ModalStack.Count); @@ -465,21 +484,27 @@ await CreateHandlerAndAddToWindow(rootPage, }); - Assert.Equal(0, (rootPage as IPageContainer).CurrentPage.Navigation.ModalStack.Count); + Assert.Equal(0, rootPage.GetCurrentPage().Navigation.ModalStack.Count); } class PageTypes : IEnumerable { public IEnumerator GetEnumerator() { - for (int i = 0; i < 2; i++) + for (int i = 0; i < 3; i++) { Func rootPage; if (i == 0) rootPage = () => new NavigationPage(new ContentPage()); - else + else if (i == 1) rootPage = () => new Shell() { CurrentItem = new ContentPage() }; + else + rootPage = () => new FlyoutPage() + { + Flyout = new ContentPage() { Title = "Flyout" }, + Detail = new NavigationPage(new ContentPage()) { Title = "Detail" }, + }; yield return new object[] { rootPage(), new NavigationPage(new ContentPage()) diff --git a/src/Controls/tests/DeviceTests/Elements/Modal/ModalTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/Modal/ModalTests.iOS.cs index cbce8e60a94b..94eebec53075 100644 --- a/src/Controls/tests/DeviceTests/Elements/Modal/ModalTests.iOS.cs +++ b/src/Controls/tests/DeviceTests/Elements/Modal/ModalTests.iOS.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Graphics; using Microsoft.Maui.Handlers; using UIKit; @@ -23,7 +24,7 @@ public async Task PushModalUsingTransparencies(Page rootPage, Page modalPage) await CreateHandlerAndAddToWindow(rootPage, async (handler) => { - var currentPage = (rootPage as IPageContainer).CurrentPage; + var currentPage = rootPage.GetCurrentPage(); await currentPage.Navigation.PushModalAsync(modalPage); await OnLoadedAsync(modalPage); Assert.Equal(1, currentPage.Navigation.ModalStack.Count); @@ -37,4 +38,4 @@ await CreateHandlerAndAddToWindow(rootPage, }); } } -} \ No newline at end of file +}