Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Android Back Button #2889

Merged
merged 2 commits into from
Jun 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion e2e/Maui/PrismMauiDemo.sln
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Prism.Maui.Tests", "..\..\t
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Prism.Core.Tests", "..\..\tests\Prism.Core.Tests\Prism.Core.Tests.csproj", "{E0F13AA9-8083-47CA-B10D-93C5285D1505}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prism.Events", "..\..\src\Prism.Events\Prism.Events.csproj", "{5623CB62-59C1-49BC-BB16-4C5D63D82DAC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Prism.Events", "..\..\src\Prism.Events\Prism.Events.csproj", "{5623CB62-59C1-49BC-BB16-4C5D63D82DAC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -95,6 +95,7 @@ Global
{EE6F0C99-61D1-4E2E-8185-FBA0D246D5C7} = {E91F80AA-3D61-4C28-B876-3EDFB5921E7D}
{F3D2DFDB-95FB-4CBB-A624-35EB6550854D} = {E91F80AA-3D61-4C28-B876-3EDFB5921E7D}
{E0F13AA9-8083-47CA-B10D-93C5285D1505} = {E91F80AA-3D61-4C28-B876-3EDFB5921E7D}
{5623CB62-59C1-49BC-BB16-4C5D63D82DAC} = {8202B92A-A573-4365-8A15-E246504A7CBD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {50B0D1F3-D832-4C6C-858E-24F5F3B33632}
Expand Down
33 changes: 31 additions & 2 deletions src/Maui/Prism.Maui/Common/MvvmHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,42 @@ public static void SetCurrentPageDelegate(Func<Page, Page> getCurrentPageDelegat
if (lastModal != null)
page = lastModal;

return GetOnNavigatedToTargetFromChild(page);
return EvaluateCurrentPage(page);
};

private static Page EvaluateCurrentPage(Page target)
{
Page child = null;

if (target is FlyoutPage flyout)
child = flyout.Detail;
else if (target is TabbedPage tabbed)
child = tabbed.CurrentPage;
else if (target is NavigationPage np)
child = np.Navigation.NavigationStack.Last();

if (child != null)
target = GetOnNavigatedToTargetFromChild(child);

if (target is Page page)
return page.Parent switch
{
TabbedPage tab when tab.CurrentPage != target => EvaluateCurrentPage(tab.CurrentPage),
NavigationPage nav when nav.CurrentPage != target => EvaluateCurrentPage(nav.CurrentPage),
_ => target
};

return null;
}

public static async Task HandleNavigationPageGoBack(NavigationPage navigationPage)
{
var navigationService = Navigation.Xaml.Navigation.GetNavigationService(navigationPage.CurrentPage);
await navigationService.GoBackAsync();
var result = await navigationService.GoBackAsync();
if(result.Exception is NavigationException navEx && navEx.Message == NavigationException.CannotPopApplicationMainPage)
{
Application.Current.Quit();
}
}

public static void HandleSystemGoBack(IView previousPage, IView currentPage)
Expand Down
14 changes: 13 additions & 1 deletion src/Maui/Prism.Maui/Controls/PrismNavigationPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,33 @@

namespace Prism.Controls;

/// <summary>
/// Provides a wrapper for the NavigationPage to better handle the OnBackButtonPressed event with Prism Navigation
/// </summary>
public class PrismNavigationPage : NavigationPage
{
/// <summary>
/// Creates a new instance of the <see cref="PrismNavigationPage"/>
/// </summary>
public PrismNavigationPage()
{
BackButtonPressed += HandleBackButtonPressed;
}

/// <summary>
/// Creates a new instance of the <see cref="PrismNavigationPage"/> with a specified <see cref="Page"/> at the Root
/// </summary>
/// <param name="page"></param>
public PrismNavigationPage(Page page)
: base(page)
{
BackButtonPressed += HandleBackButtonPressed;
}

/// <inheritdoc/>
public event EventHandler BackButtonPressed;

/// <inheritdoc/>
protected override bool OnBackButtonPressed()
{
BackButtonPressed.Invoke(this, EventArgs.Empty);
Expand All @@ -27,4 +39,4 @@ private async void HandleBackButtonPressed(object sender, EventArgs args)
{
await MvvmHelpers.HandleNavigationPageGoBack(this);
}
}
}
58 changes: 57 additions & 1 deletion src/Maui/Prism.Maui/Navigation/PrismWindow.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
using Prism.AppModel;
using System.ComponentModel;
using Prism.AppModel;
using Prism.Common;
using Prism.Ioc;
using Prism.Navigation.Xaml;
using Prism.Services;
using Prism.Xaml;
using TabbedPage = Microsoft.Maui.Controls.TabbedPage;

namespace Prism.Navigation;

Expand All @@ -19,6 +25,56 @@ public PrismWindow(string name = DefaultWindowName)

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;

[EditorBrowsable(EditorBrowsableState.Never)]
public void OnSystemBack()
{
var currentPage = CurrentPage;
if(currentPage?.Parent is NavigationPage navPage)
{
// The NavigationPage has already taken care of the GoBack
return;
}

var container = currentPage.GetContainerProvider();

if (IsRoot(currentPage))
{
var app = container.Resolve<IApplication>() 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<INavigationService>();
navigation.GoBackAsync();
}
}

private bool IsRoot(Page page)
{
if (page == Page) return true;

return page.Parent switch
{
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)
Expand Down
21 changes: 8 additions & 13 deletions src/Maui/Prism.Maui/PrismAppBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,23 @@ internal PrismAppBuilder(IContainerExtension containerExtension, MauiAppBuilder
{
var root = ContainerLocator.Container;
if (root is null)
return true;
return false;

var app = root.Resolve<IApplication>();
var windows = app.Windows.OfType<PrismWindow>();
if (!windows.Any(x => x.IsActive))
return true;
return false;

var window = windows.First(x => x.IsActive);
var currentPage = window.CurrentPage;
var container = currentPage.GetContainerProvider();
if(currentPage is IDialogContainer dialogContainer)
if(window.IsRootPage && app is Application application)
{
if (dialogContainer.Dismiss.CanExecute(null))
dialogContainer.Dismiss.Execute(null);
}
else
{
var navigation = container.Resolve<INavigationService>();
navigation.GoBackAsync();
application.Quit();
return false;
}

return false;
window.OnSystemBack();

return true;
});
});
#endif
Expand Down