Skip to content

Commit

Permalink
Create Flyout.Details inside Fragment (#6023)
Browse files Browse the repository at this point in the history
* Create Flyout.Details inside Fragment

* - add tests

* Update FlyoutPageTests.cs

* Update FlyoutViewHandler.Android.cs

* - fix flyoutpage tests
  • Loading branch information
PureWeen authored Apr 15, 2022
1 parent de09524 commit e9852b3
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System.Threading.Tasks;
using AndroidX.AppCompat.Widget;
using Microsoft.Maui.Handlers;
using Xunit;

namespace Microsoft.Maui.DeviceTests
{
[Collection(HandlerTestBase.RunInNewWindowCollection)]
public partial class EditorTests
{
AppCompatEditText GetPlatformControl(EditorHandler handler) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace Microsoft.Maui.DeviceTests
{
[Collection(HandlerTestBase.RunInNewWindowCollection)]
public partial class FlyoutPageTests
{
DrawerLayout FindPlatformFlyoutView(AView aView) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,26 @@ await CreateHandlerAndAddToWindow<FlyoutViewHandler>(flyoutPage, (handler) =>
});
}

[Fact(DisplayName = "Details View Updates w/NavigationPage")]
public async Task DetailsViewUpdatesWithNavigationPage()
{
SetupBuilder();
var flyoutPage = new FlyoutPage()
{
Detail = new NavigationPage(new ContentPage() { Title = "Detail" }),
Flyout = new ContentPage() { Title = "Flyout" }
};

await CreateHandlerAndAddToWindow<FlyoutViewHandler>(flyoutPage, async (handler) =>
{
var details2 = new NavigationPage(new ContentPage() { Title = "Detail" });

flyoutPage.Detail = details2;
await OnLoadedAsync(details2.CurrentPage);
var detailView2 = (details2.CurrentPage.Handler as IPlatformViewHandler)?.PlatformView;
Assert.NotNull(detailView2);
});
}

[Fact(DisplayName = "Details View Updates")]
public async Task DetailsViewUpdates()
Expand All @@ -72,11 +92,10 @@ await CreateHandlerAndAddToWindow<FlyoutViewHandler>(flyoutPage, async (handler)
Assert.Equal(flyoutView, dl);

flyoutPage.Detail = details2;
var detailView2 = details2.ToPlatform();

await detailView2.OnLoadedAsync();
await OnLoadedAsync(details2);
await detailView.OnUnloadedAsync();
dl = FindPlatformFlyoutView(detailView2);
dl = FindPlatformFlyoutView(details2.ToPlatform());
Assert.Equal(flyoutView, dl);
Assert.Null(FindPlatformFlyoutView(detailView));
});
Expand Down
3 changes: 3 additions & 0 deletions src/Controls/tests/DeviceTests/Elements/Modal/ModalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
namespace Microsoft.Maui.DeviceTests
{
[Category(TestCategory.Modal)]
#if ANDROID
[Collection(HandlerTestBase.RunInNewWindowCollection)]
#endif
public partial class ModalTests : HandlerTestBase
{
void SetupBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace Microsoft.Maui.DeviceTests
{
[Category(TestCategory.NavigationPage)]
[Collection(HandlerTestBase.RunInNewWindowCollection)]
public partial class NavigationPageTests : HandlerTestBase
{
// We only want to fire BackButtonVisible Toolbar events if the user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
namespace Microsoft.Maui.DeviceTests
{
[Category(TestCategory.Behavior)]
#if ANDROID
[Collection(HandlerTestBase.RunInNewWindowCollection)]
#endif
public partial class PlatformBehaviorTests : HandlerTestBase
{
[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace Microsoft.Maui.DeviceTests
{
[Category(TestCategory.Shell)]
[Collection(HandlerTestBase.RunInNewWindowCollection)]
public partial class ShellTests
{
[Fact(DisplayName = "Shell with Flyout Disabled Doesn't Render Flyout")]
Expand Down
3 changes: 3 additions & 0 deletions src/Controls/tests/DeviceTests/Elements/VisualElementTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
namespace Microsoft.Maui.DeviceTests
{
[Category(TestCategory.VisualElement)]
#if ANDROID
[Collection(HandlerTestBase.RunInNewWindowCollection)]
#endif
public partial class VisualElementTests : HandlerTestBase
{
void SetupBuilder()
Expand Down
6 changes: 6 additions & 0 deletions src/Controls/tests/DeviceTests/HandlerTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public partial class HandlerTestBase : TestBase, IDisposable
MauiApp _mauiApp;
IMauiContext _mauiContext;

// In order to run any page level tests android needs to add itself to the decor view inside a new fragment
// that way all the lifecycle events related to being attached to the window will fire
// adding/removing that many fragments in parallel to the decor view was causing the tests to be unreliable
// That being said...
// There's definitely a chance that the code written to manage this process could be improved
public const string RunInNewWindowCollection = "Serialize test because it has to add itself to the main window";
public void EnsureHandlerCreated(Action<MauiAppBuilder> additionalCreationActions = null)
{
if (_isCreated)
Expand Down
31 changes: 20 additions & 11 deletions src/Core/src/Handlers/FlyoutView/FlyoutViewHandler.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ namespace Microsoft.Maui.Handlers
public partial class FlyoutViewHandler : ViewHandler<IFlyoutView, View>
{
View? _flyoutView;
View? _detailView;
const uint DefaultScrimColor = 0x99000000;
View? _navigationRoot;
LinearLayoutCompat? _sideBySideView;
DrawerLayout DrawerLayout => (DrawerLayout)PlatformView;
ScopedFragment? _detailViewFragment;

protected override View CreatePlatformView()
{
Expand Down Expand Up @@ -49,22 +49,32 @@ double FlyoutWidth
void UpdateDetailsFragmentView()
{
_ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class.");
var newDetailsView = VirtualView.Detail?.ToPlatform(MauiContext);

if (_detailView == newDetailsView)
if (_detailViewFragment != null && _detailViewFragment?.DetailView == VirtualView.Detail)
return;

if (newDetailsView != null)
newDetailsView.RemoveFromParent();
if (VirtualView.Detail?.Handler is IPlatformViewHandler pvh)
pvh.DisconnectHandler();

_detailView = newDetailsView;

if (_detailView != null)
if(VirtualView.Detail == null)
{
if (_detailViewFragment != null)
{
MauiContext
.GetFragmentManager()
.BeginTransaction()
.Remove(_detailViewFragment)
.SetReorderingAllowed(true)
.Commit();
}
}
else
{
_detailViewFragment = new ScopedFragment(VirtualView.Detail, MauiContext);
MauiContext
.GetFragmentManager()
.BeginTransaction()
.Replace(Resource.Id.navigationlayout_content, new ViewFragment(_detailView))
.Replace(Resource.Id.navigationlayout_content, _detailViewFragment)
.SetReorderingAllowed(true)
.Commit();
}
Expand Down Expand Up @@ -223,8 +233,7 @@ void UpdateIsPresented()
void UpdateFlyoutBehavior()
{
var behavior = VirtualView.FlyoutBehavior;
var details = _detailView;
if (details == null)
if (_detailViewFragment?.DetailView?.Handler?.PlatformView == null)
return;

switch (behavior)
Expand Down
25 changes: 25 additions & 0 deletions src/Core/src/Platform/Android/Navigation/ScopedFragment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Android.OS;
using Android.Views;
using AndroidX.Fragment.App;

namespace Microsoft.Maui.Platform
{
class ScopedFragment : Fragment
{
readonly IMauiContext _mauiContext;

public IView DetailView { get; private set; }

public ScopedFragment(IView detailView, IMauiContext mauiContext)
{
DetailView = detailView;
_mauiContext = mauiContext;
}

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var pageMauiContext = _mauiContext.MakeScoped(layoutInflater: inflater, fragmentManager: ChildFragmentManager);
return DetailView.ToPlatform(pageMauiContext);
}
}
}
1 change: 0 additions & 1 deletion src/Core/src/Platform/Android/ViewExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,6 @@ public static void RemoveFromParent(this AView view)
{
if (view != null)
PlatformInterop.RemoveFromParent(view);
PlatformInterop.RemoveFromParent(view);
}

internal static Rect GetPlatformViewBounds(this IView view)
Expand Down
7 changes: 1 addition & 6 deletions src/Core/src/Platform/ElementExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,8 @@ internal static PlatformView ToPlatform(this IElement view)
if (view is IReplaceableView replaceableView && replaceableView.ReplacedView != view)
return replaceableView.ReplacedView.ToPlatform();

if (view.Handler == null)
{
var mauiContext = view.Parent?.Handler?.MauiContext ??
throw new InvalidOperationException($"{nameof(MauiContext)} should have been set on parent.");

return view.ToPlatform(mauiContext);
}
_ = view.Handler ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set on parent.");

if (view.Handler is IViewHandler viewHandler)
{
Expand Down

0 comments on commit e9852b3

Please sign in to comment.