Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
Route Navigation.(Push/Pop)Modal through Shell Navigation Manager (#1…
Browse files Browse the repository at this point in the history
…4080)

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

* - fix SO error

* Update ShellNavigationManager.cs
  • Loading branch information
PureWeen committed Jul 7, 2021
1 parent 89ea384 commit 46d1d9d
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 12 deletions.
49 changes: 49 additions & 0 deletions Xamarin.Forms.Core.UnitTests/ShellModalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,55 @@ public async Task GetCurrentPageInModalNavigation()
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
Expand Down
4 changes: 2 additions & 2 deletions Xamarin.Forms.Core.UnitTests/ShellNavigatingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -889,14 +889,14 @@ protected override Task<Page> OnPopAsync(bool animated)
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;
Expand Down
1 change: 1 addition & 0 deletions Xamarin.Forms.Core/Routing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ internal static bool IsUserDefined(string route)

internal static void Clear()
{
s_implicitPageRoutes.Clear();
s_routes.Clear();
}

Expand Down
2 changes: 2 additions & 0 deletions Xamarin.Forms.Core/Shell/RouteRequestBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public bool AddMatch(ShellUriHandler.NodeLocation nodeLocation)

bool AddNode(BaseShellItem baseShellItem, string nextSegment)
{
_ = baseShellItem ?? throw new ArgumentNullException(nameof(baseShellItem));

if (Routing.IsUserDefined(baseShellItem.Route) && baseShellItem.Route != nextSegment)
{
return false;
Expand Down
6 changes: 3 additions & 3 deletions Xamarin.Forms.Core/Shell/ShellNavigationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ public async Task GoToAsync(ShellNavigationParameters shellNavigationParameters)

public void HandleNavigated(ShellNavigatedEventArgs args)
{
if (_accumulateNavigatedEvents)
if (AccumulateNavigatedEvents)
{
if (_accumulatedEvent == null)
_accumulatedEvent = args;
Expand Down Expand Up @@ -286,7 +286,7 @@ public static void ApplyQueryAttributes(Element element, IDictionary<string, str
bool canCancel,
bool isAnimated)
{
if (_accumulateNavigatedEvents)
if (AccumulateNavigatedEvents)
return true;

var proposedState = GetNavigationState(shellItem, shellSection, shellContent, stack, shellSection.Navigation.ModalStack);
Expand Down Expand Up @@ -319,7 +319,7 @@ public static void ApplyQueryAttributes(Element element, IDictionary<string, str
bool canCancel,
bool isAnimated)
{
if (_accumulateNavigatedEvents)
if (AccumulateNavigatedEvents)
return null;

var navArgs = new ShellNavigatingEventArgs(_shell.CurrentState, proposedState, source, canCancel)
Expand Down
74 changes: 68 additions & 6 deletions Xamarin.Forms.Core/Shell/ShellSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ async Task PrepareCurrentStackForBeingReplaced(NavigationRequest request, IDicti
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)
Expand Down Expand Up @@ -409,7 +409,7 @@ async Task PrepareCurrentStackForBeingReplaced(NavigationRequest request, IDicti
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)
{
Expand Down Expand Up @@ -550,15 +550,15 @@ internal async Task GoToAsync(NavigationRequest request, IDictionary<string, str

if (modalPage is NavigationPage np)
{
await Navigation.PushModalAsync(modalPage, isAnimated);
await PushModalAsync(modalPage, isAnimated);
activeModalNavigationPage = np;
}
else
{
if (activeModalNavigationPage != null)
await activeModalNavigationPage.Navigation.PushAsync(modalPage, animate ?? IsNavigationAnimated(modalPage));
else
await Navigation.PushModalAsync(modalPage, isAnimated);
await PushModalAsync(modalPage, isAnimated);
}
}

Expand All @@ -570,6 +570,22 @@ internal async Task GoToAsync(NavigationRequest request, IDictionary<string, str
}
}

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--)
Expand Down Expand Up @@ -852,7 +868,7 @@ internal async Task PopModalStackToPage(Page page, bool? animated)
}

bool isAnimated = animated ?? (Shell.GetPresentationMode(pageToPop) & PresentationMode.NotAnimated) != PresentationMode.NotAnimated;
await Navigation.PopModalAsync(isAnimated);
await PopModalAsync(isAnimated);
}
}
finally
Expand Down Expand Up @@ -1089,6 +1105,52 @@ protected override Task OnPushAsync(Page page, bool animated)
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)
Expand Down Expand Up @@ -1149,4 +1211,4 @@ ShellNavigationState GetUpdatedStatus(IReadOnlyList<Page> stack)
}
}
}
}
}
6 changes: 5 additions & 1 deletion Xamarin.Forms.Core/Shell/ShellUriHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,12 +284,16 @@ internal static List<RouteRequestBuilder> GenerateRoutePaths(Shell shell, Uri re
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)
Expand Down

0 comments on commit 46d1d9d

Please sign in to comment.