Skip to content

Commit

Permalink
Merge pull request #2889 from PrismLibrary/fix-android-back
Browse files Browse the repository at this point in the history
Fix Android Back Button
  • Loading branch information
dansiegel committed Jun 13, 2023
2 parents 8f217dd + 73a0453 commit d8d47b8
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 18 deletions.
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 int GetCurrentPageIndex(Page currentPage, System.Collections.Gener
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 @@ -53,28 +53,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

0 comments on commit d8d47b8

Please sign in to comment.