Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,8 @@ protected override void Dispose(bool disposing)
{
var oldRenderer = renderer.Value;

if (oldRenderer.PlatformView != null)
oldRenderer.PlatformView.RemoveFromSuperview();

if (oldRenderer.ViewController != null)
oldRenderer.ViewController.RemoveFromParentViewController();
oldRenderer.ViewController?.ViewIfLoaded?.RemoveFromSuperview();
oldRenderer.ViewController?.RemoveFromParentViewController();

var element = oldRenderer.VirtualView;
oldRenderer?.DisconnectHandler();
Expand Down Expand Up @@ -218,7 +215,7 @@ protected virtual void LayoutRenderers()
var shellContent = items[i];
if (_renderers.TryGetValue(shellContent, out var renderer))
{
var view = renderer.PlatformView;
var view = renderer.ViewController.View;
if (view != null)
view.Frame = new CGRect(0, 0, View.Bounds.Width, View.Bounds.Height);
}
Expand Down Expand Up @@ -262,7 +259,7 @@ protected virtual void LoadRenderers()

if (item == currentItem)
{
_containerArea.AddSubview(renderer.PlatformView);
_containerArea.AddSubview(renderer.ViewController.View);
_currentContent = currentItem;
_currentIndex = i;
}
Expand Down Expand Up @@ -351,21 +348,21 @@ UIViewPropertyAnimator CreateContentAnimator(
int newIndex,
UIView containerView)
{
containerView.AddSubview(newRenderer.PlatformView);
containerView.AddSubview(newRenderer.ViewController.View);
// -1 == slide left, 1 == slide right
int motionDirection = newIndex > oldIndex ? -1 : 1;

newRenderer.PlatformView.Frame = new CGRect(-motionDirection * View.Bounds.Width, 0, View.Bounds.Width, View.Bounds.Height);
newRenderer.ViewController.View.Frame = new CGRect(-motionDirection * View.Bounds.Width, 0, View.Bounds.Width, View.Bounds.Height);

if (oldRenderer.PlatformView != null)
oldRenderer.PlatformView.Frame = containerView.Bounds;
if (oldRenderer.ViewController.View != null)
oldRenderer.ViewController.View.Frame = containerView.Bounds;

return new UIViewPropertyAnimator(0.25, UIViewAnimationCurve.EaseOut, () =>
{
newRenderer.PlatformView.Frame = containerView.Bounds;
newRenderer.ViewController.View.Frame = containerView.Bounds;

if (oldRenderer.PlatformView != null)
oldRenderer.PlatformView.Frame = new CGRect(motionDirection * View.Bounds.Width, 0, View.Bounds.Width, View.Bounds.Height);
if (oldRenderer.ViewController.View != null)
oldRenderer.ViewController.View.Frame = new CGRect(motionDirection * View.Bounds.Width, 0, View.Bounds.Width, View.Bounds.Height);

});
}
Expand All @@ -388,14 +385,14 @@ void RemoveNonVisibleRenderers()
var oldContent = r.Key;
var oldRenderer = r.Value;

r.Value.PlatformView.RemoveFromSuperview();
r.Value.ViewController?.ViewIfLoaded?.RemoveFromSuperview();

if (!sectionItems.Contains(oldContent) && _renderers.ContainsKey(oldContent))
{
removeMe = removeMe ?? new List<ShellContent>();
removeMe.Add(oldContent);

if (oldRenderer.PlatformView != null)
if (oldRenderer.PlatformView is not null)
{
oldRenderer.ViewController.RemoveFromParentViewController();
oldRenderer.DisconnectHandler();
Expand Down Expand Up @@ -482,7 +479,7 @@ void OnShellSectionItemsChanged(object sender, NotifyCollectionChangedEventArgs
_currentIndex--;

_renderers.Remove(oldItem);
oldRenderer.PlatformView.RemoveFromSuperview();
oldRenderer.ViewController.ViewIfLoaded?.RemoveFromSuperview();
oldRenderer.ViewController.RemoveFromParentViewController();
oldRenderer.DisconnectHandler();
}
Expand Down
75 changes: 41 additions & 34 deletions src/Controls/tests/DeviceTests/ControlsHandlerTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,8 @@ protected override MauiAppBuilder ConfigureBuilder(MauiAppBuilder mauiAppBuilder
return mauiAppBuilder.ConfigureTestBuilder();
}

protected void SetupShellHandlers(IMauiHandlersCollection handlers)
{
handlers.TryAddHandler(typeof(Controls.Shell), typeof(ShellHandler));
handlers.TryAddHandler<Layout, LayoutHandler>();
handlers.TryAddHandler<Image, ImageHandler>();
handlers.TryAddHandler<Label, LabelHandler>();
handlers.TryAddHandler<Page, PageHandler>();
handlers.TryAddHandler(typeof(Toolbar), typeof(ToolbarHandler));
handlers.TryAddHandler(typeof(MenuBar), typeof(MenuBarHandler));
handlers.TryAddHandler(typeof(MenuBarItem), typeof(MenuBarItemHandler));
handlers.TryAddHandler(typeof(MenuFlyoutItem), typeof(MenuFlyoutItemHandler));
handlers.TryAddHandler(typeof(MenuFlyoutSubItem), typeof(MenuFlyoutSubItemHandler));
handlers.TryAddHandler<ScrollView, ScrollViewHandler>();

#if WINDOWS
handlers.TryAddHandler(typeof(ShellItem), typeof(ShellItemHandler));
handlers.TryAddHandler(typeof(ShellSection), typeof(ShellSectionHandler));
handlers.TryAddHandler(typeof(ShellContent), typeof(ShellContentHandler));
#endif
}
protected void SetupShellHandlers(IMauiHandlersCollection handlers) =>
handlers.SetupShellHandlers();

protected THandler CreateHandler<THandler>(IElement view)
where THandler : IElementHandler, new()
Expand Down Expand Up @@ -100,6 +82,39 @@ protected Task<TValue> GetValueAsync<TValue>(IElement view, Func<IPlatformViewHa
});
}

IWindow CreateWindowForContent(IElement view)
{
IWindow window;

if (view is IWindow w)
window = w;
else if (view is Page page)
window = new Controls.Window(page);
else
window = new Controls.Window(new ContentPage() { Content = (View)view });

return window;
}

protected Task CreateHandlerAndAddToWindow(IElement view, Action action)
{
return CreateHandlerAndAddToWindow<IWindowHandler>(CreateWindowForContent(view), handler =>
{
action();
return Task.CompletedTask;
});
}

protected Task CreateHandlerAndAddToWindow<THandler>(IElement view, Action<THandler> action)
where THandler : class, IElementHandler
{
return CreateHandlerAndAddToWindow<THandler>(view, handler =>
{
action(handler);
return Task.CompletedTask;
});
}

static SemaphoreSlim _takeOverMainContentSempahore = new SemaphoreSlim(1);
protected Task CreateHandlerAndAddToWindow<THandler>(IElement view, Func<THandler, Task> action, IMauiContext mauiContext = null, TimeSpan? timeOut = null)
where THandler : class, IElementHandler
Expand All @@ -110,23 +125,10 @@ protected Task CreateHandlerAndAddToWindow<THandler>(IElement view, Func<THandle

return InvokeOnMainThreadAsync(async () =>
{
IWindow window = null;
IWindow window = CreateWindowForContent(view);

var application = mauiContext.Services.GetService<IApplication>();

if (view is IWindow w)
{
window = w;
}
else if (view is Page page)
{
window = new Controls.Window(page);
}
else
{
window = new Controls.Window(new ContentPage() { Content = (View)view });
}

if (application is ApplicationStub appStub)
{
appStub.SetWindow((Window)window);
Expand All @@ -143,6 +145,9 @@ await SetupWindowForTests<THandler>(window, async () =>
{
IView content = window.Content;

if (content is FlyoutPage fp)
content = fp.Detail;

if (window is Window w && w.Navigation.ModalStack.Count > 0)
content = w.Navigation.ModalStack.Last();

Expand Down Expand Up @@ -191,6 +196,8 @@ await SetupWindowForTests<THandler>(window, async () =>
handler = (THandler)window.Content.Handler;
else if (window.Content is ContentPage cp && typeof(THandler).IsAssignableFrom(cp.Content.Handler.GetType()))
handler = (THandler)cp.Content.Handler;
else if (typeof(THandler).IsAssignableFrom(typeof(WindowHandler)))
throw new Exception($"Use IWindowHandler instead of WindowHandler for CreateHandlerAndAddToWindow");
else
throw new Exception($"I can't work with {typeof(THandler)}");

Expand Down
55 changes: 54 additions & 1 deletion src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Handlers.Compatibility;
using Microsoft.Maui.DeviceTests.TestCases;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Platform;
Expand Down Expand Up @@ -153,5 +154,57 @@ await contentViewHandler.PlatformView.AttachAndRun(() =>
});
});
}

[Category(TestCategory.Entry)]
[Collection(ControlsHandlerTestBase.RunInNewWindowCollection)]
public partial class EntryTestsWithWindow : ControlsHandlerTestBase
{
[Theory]
[ClassData(typeof(ControlsPageTypesTestCases))]
public async Task NextMovesToNextEntry(string page)
{
bool isFocused = false;
EnsureHandlerCreated(builder =>
{
ControlsPageTypesTestCases.Setup(builder);
builder.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(Entry), typeof(EntryHandler));
});
});

var entry1 = new Entry
{
Text = "Entry 1",
ReturnType = ReturnType.Next
};

var entry2 = new Entry
{
Text = "Entry 2",
ReturnType = ReturnType.Next
};

ContentPage contentPage = new ContentPage()
{
Content = new VerticalStackLayout()
{
entry1,
entry2
}
};

Page rootPage = ControlsPageTypesTestCases.CreatePageType(page, contentPage);

await CreateHandlerAndAddToWindow(rootPage, async () =>
{
KeyboardAutoManager.GoToNextResponderOrResign(entry1.ToPlatform());
await AssertionExtensions.Wait(() => entry2.IsFocused);
isFocused = entry2.IsFocused;
});

Assert.True(isFocused, $"{page} failed to focus the second entry DANG");
}
}
}
}
}
38 changes: 37 additions & 1 deletion src/Controls/tests/DeviceTests/Elements/Shell/ShellTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Handlers;
using Microsoft.Maui.Controls.Handlers.Compatibility;
using Microsoft.Maui.Devices;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Hosting;
Expand All @@ -32,10 +33,45 @@ void SetupBuilder()
{
SetupShellHandlers(handlers);
handlers.AddHandler(typeof(NavigationPage), typeof(NavigationViewHandler));
handlers.AddHandler(typeof(Button), typeof(ButtonHandler));
});
});
}

[Fact]
public async Task PageLayoutDoesNotExceedWindowBounds()
{
SetupBuilder();

var button = new Button()
{
Text = "Test me"
};

var contentPage = new ContentPage()
{
Content = button
};

var shell = new Shell()
{
CurrentItem = contentPage,
FlyoutBehavior = FlyoutBehavior.Disabled
};

await CreateHandlerAndAddToWindow<WindowHandlerStub>(shell, async (handler) =>
{
await OnFrameSetToNotEmpty(contentPage);
var pageBounds = contentPage.GetBoundingBox();
var window = contentPage.Window;

Assert.True(pageBounds.X >= 0);
Assert.True(pageBounds.Y >= 0);
Assert.True(pageBounds.Width <= window.Width);
Assert.True(pageBounds.Height <= window.Height);
});
}

#if ANDROID || IOS || MACCATALYST
[Fact]
public async Task SearchHandlerRendersCorrectly()
Expand Down Expand Up @@ -981,4 +1017,4 @@ protected Task<Shell> CreateShellAsync(Action<Shell> action) =>
return value;
});
}
}
}
38 changes: 38 additions & 0 deletions src/Controls/tests/DeviceTests/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,51 @@
using System;
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Handlers;
using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Devices;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Platform;
using Xunit;
#if ANDROID || IOS || MACCATALYST
using ShellHandler = Microsoft.Maui.Controls.Handlers.Compatibility.ShellRenderer;
#endif

namespace Microsoft.Maui.DeviceTests
{
public static class Extensions
{
public static Task Wait(this Image image, int timeout = 1000) =>
AssertionExtensions.Wait(() => !image.IsLoading, timeout);

public static void SetupShellHandlers(this MauiAppBuilder builder)
{
builder.ConfigureMauiHandlers(SetupShellHandlers);
}

public static void SetupShellHandlers(this IMauiHandlersCollection handlers)
{
handlers.TryAddHandler(typeof(Controls.Shell), typeof(ShellHandler));
handlers.TryAddHandler<Layout, LayoutHandler>();
handlers.TryAddHandler<Image, ImageHandler>();
handlers.TryAddHandler<Label, LabelHandler>();
handlers.TryAddHandler<Page, PageHandler>();
handlers.TryAddHandler(typeof(Toolbar), typeof(ToolbarHandler));
handlers.TryAddHandler(typeof(MenuBar), typeof(MenuBarHandler));
handlers.TryAddHandler(typeof(MenuBarItem), typeof(MenuBarItemHandler));
handlers.TryAddHandler(typeof(MenuFlyoutItem), typeof(MenuFlyoutItemHandler));
handlers.TryAddHandler(typeof(MenuFlyoutSubItem), typeof(MenuFlyoutSubItemHandler));
handlers.TryAddHandler<ScrollView, ScrollViewHandler>();

#if WINDOWS
handlers.TryAddHandler(typeof(ShellItem), typeof(ShellItemHandler));
handlers.TryAddHandler(typeof(ShellSection), typeof(ShellSectionHandler));
handlers.TryAddHandler(typeof(ShellContent), typeof(ShellContentHandler));
#endif
}
}
}

Loading