Route Navigation.(Push/Pop)Modal through Shell Navigation Manager (#14080)

* Route Navigation.(Push/Pop)Modal through Shell Navigation Mananger

* - fix SO error

* Update ShellNavigationManager.cs
This commit is contained in:
Shane Neuville 2021-07-07 03:06:47 -07:00 коммит произвёл GitHub
Родитель 89ea384f12
Коммит 46d1d9dd1a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 130 добавлений и 12 удалений

Просмотреть файл

@ -381,6 +381,55 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.AreEqual(page.GetType(), typeof(ModalTestPage));
}
[Test]
public async Task PopModalWithDots()
{
Shell shell = new Shell();
shell.Items.Add(CreateShellItem());
await shell.CurrentPage.Navigation.PushModalAsync(new ContentPage());
await shell.CurrentPage.Navigation.PushModalAsync(new ContentPage());
await shell.GoToAsync("..");
Assert.AreEqual(1, shell.Navigation.ModalStack.Count);
await shell.GoToAsync("..");
Assert.AreEqual(0, shell.Navigation.ModalStack.Count);
}
[Test]
public async Task CanCancelGoToModalAsync()
{
TestShell shell = new TestShell();
shell.Items.Add(CreateShellItem());
shell.Navigating += async (_, args) =>
{
var deferral = args.GetDeferral();
await Task.Delay(10);
args.Cancel();
deferral.Complete();
};
await shell.GoToAsync("ModalTestPage");
Assert.AreEqual(0, shell.Navigation.ModalStack.Count);
}
[Test]
public async Task CanCancelPushModalAsync()
{
TestShell shell = new TestShell();
shell.Items.Add(CreateShellItem());
shell.Navigating += async (_, args) =>
{
var deferral = args.GetDeferral();
await Task.Delay(10);
args.Cancel();
deferral.Complete();
};
await shell.CurrentPage.Navigation.PushModalAsync(new ContentPage());
Assert.AreEqual(0, shell.Navigation.ModalStack.Count);
}
[QueryProperty("SomeQueryParameter", "SomeQueryParameter")]
public class ModalTestPageBase : ShellLifeCycleTests.LifeCyclePage

Просмотреть файл

@ -889,14 +889,14 @@ namespace Xamarin.Forms.Core.UnitTests
public class NavigationImpl : NavigationProxy
{
readonly NavigationMonitoringTab _navigationMonitoringTab;
readonly INavigation _navigation;
readonly NavigationProxy _navigation;
public NavigationImpl(
NavigationMonitoringTab navigationMonitoringTab,
INavigation navigation)
{
_navigationMonitoringTab = navigationMonitoringTab;
_navigation = navigation;
_navigation = (NavigationProxy)navigation;
}
protected override IReadOnlyList<Page> GetModalStack() => _navigation.ModalStack;

Просмотреть файл

@ -105,6 +105,7 @@ namespace Xamarin.Forms
internal static void Clear()
{
s_implicitPageRoutes.Clear();
s_routes.Clear();
}

Просмотреть файл

@ -74,6 +74,8 @@ namespace Xamarin.Forms
bool AddNode(BaseShellItem baseShellItem, string nextSegment)
{
_ = baseShellItem ?? throw new ArgumentNullException(nameof(baseShellItem));
if (Routing.IsUserDefined(baseShellItem.Route) && baseShellItem.Route != nextSegment)
{
return false;

Просмотреть файл

@ -176,7 +176,7 @@ namespace Xamarin.Forms
public void HandleNavigated(ShellNavigatedEventArgs args)
{
if (_accumulateNavigatedEvents)
if (AccumulateNavigatedEvents)
{
if (_accumulatedEvent == null)
_accumulatedEvent = args;
@ -286,7 +286,7 @@ namespace Xamarin.Forms
bool canCancel,
bool isAnimated)
{
if (_accumulateNavigatedEvents)
if (AccumulateNavigatedEvents)
return true;
var proposedState = GetNavigationState(shellItem, shellSection, shellContent, stack, shellSection.Navigation.ModalStack);
@ -319,7 +319,7 @@ namespace Xamarin.Forms
bool canCancel,
bool isAnimated)
{
if (_accumulateNavigatedEvents)
if (AccumulateNavigatedEvents)
return null;
var navArgs = new ShellNavigatingEventArgs(_shell.CurrentState, proposedState, source, canCancel)

Просмотреть файл

@ -354,7 +354,7 @@ namespace Xamarin.Forms
var page = GetOrCreateFromRoute(globalRoutes[i], queryData, i == globalRoutes.Count - 1, false);
if (IsModal(page))
{
await Navigation.PushModalAsync(page, IsNavigationAnimated(page));
await PushModalAsync(page, IsNavigationAnimated(page));
break;
}
else if (!isLast && navIndex < _navStack.Count)
@ -409,7 +409,7 @@ namespace Xamarin.Forms
bool isAnimated = animate ?? IsNavigationAnimated(navStack[navStack.Count - 1]);
if (Navigation.ModalStack.Contains(navStack[navStack.Count - 1]))
{
await Navigation.PopModalAsync(isAnimated);
await PopModalAsync(isAnimated);
}
else if (Navigation.ModalStack.Count > 0)
{
@ -550,7 +550,7 @@ namespace Xamarin.Forms
if (modalPage is NavigationPage np)
{
await Navigation.PushModalAsync(modalPage, isAnimated);
await PushModalAsync(modalPage, isAnimated);
activeModalNavigationPage = np;
}
else
@ -558,7 +558,7 @@ namespace Xamarin.Forms
if (activeModalNavigationPage != null)
await activeModalNavigationPage.Navigation.PushAsync(modalPage, animate ?? IsNavigationAnimated(modalPage));
else
await Navigation.PushModalAsync(modalPage, isAnimated);
await PushModalAsync(modalPage, isAnimated);
}
}
@ -570,6 +570,22 @@ namespace Xamarin.Forms
}
}
Task PopModalAsync(bool isAnimated)
{
if (Navigation is NavigationImpl shellSectionProxy)
return shellSectionProxy.PopModalInnerAsync(isAnimated);
return Navigation.PopModalAsync(isAnimated);
}
Task PushModalAsync(Page page, bool isAnimated)
{
if (Navigation is NavigationImpl shellSectionProxy)
return shellSectionProxy.PushModalInnerAsync(page, isAnimated);
return Navigation.PushModalAsync(page, isAnimated);
}
async Task PushStackOfPages(List<Page> pages, bool? animate)
{
for (int i = pages.Count - 1; i >= 0; i--)
@ -852,7 +868,7 @@ namespace Xamarin.Forms
}
bool isAnimated = animated ?? (Shell.GetPresentationMode(pageToPop) & PresentationMode.NotAnimated) != PresentationMode.NotAnimated;
await Navigation.PopModalAsync(isAnimated);
await PopModalAsync(isAnimated);
}
}
finally
@ -1089,6 +1105,52 @@ namespace Xamarin.Forms
return _owner.Shell.NavigationManager.GoToAsync(navigationParameters);
}
// This is used when we just want to process the modal operation and we don't need
// it to process through the internal shell navigation bits
internal Task PushModalInnerAsync(Page modal, bool animated)
{
return Inner?.PushModalAsync(modal, animated);
}
// This is used when we just want to process the modal operation and we don't need
// it to process through the internal shell navigation bits
internal Task<Page> PopModalInnerAsync(bool animated)
{
return Inner?.PopModalAsync(animated);
}
protected override async Task OnPushModal(Page modal, bool animated)
{
if (_owner.Shell.NavigationManager.AccumulateNavigatedEvents)
{
await base.OnPushModal(modal, animated);
return;
}
if (animated)
Shell.SetPresentationMode(modal, PresentationMode.ModalAnimated);
else
Shell.SetPresentationMode(modal, PresentationMode.ModalNotAnimated);
var navigationParameters = new ShellNavigationParameters()
{
Animated = animated,
PagePushing = modal
};
await _owner.Shell.NavigationManager.GoToAsync(navigationParameters);
}
protected async override Task<Page> OnPopModal(bool animated)
{
if (_owner.Shell.NavigationManager.AccumulateNavigatedEvents)
return await base.OnPopModal(animated);
var page = ModalStack[ModalStack.Count - 1];
await _owner.Shell.GoToAsync("..", animated);
return page;
}
protected override void OnRemovePage(Page page)
{
if (!_owner.IsVisibleSection || _owner.Shell.NavigationManager.AccumulateNavigatedEvents)
@ -1149,4 +1211,4 @@ namespace Xamarin.Forms
}
}
}
}
}

Просмотреть файл

@ -284,12 +284,16 @@ namespace Xamarin.Forms
continue;
var url = possibleRoutePath.PathFull;
var currentLocation = possibleRoutePath.GetNodeLocation();
if (currentLocation.Content == null)
continue;
var globalRouteMatches =
SearchForGlobalRoutes(
possibleRoutePath.RemainingSegments,
new ShellNavigationState(url, false).FullLocation,
possibleRoutePath.GetNodeLocation(),
currentLocation,
routeKeys);
if (globalRouteMatches.Count != 1)