Skip to content

Commit

Permalink
Squash all the iOS Keyboard Improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
tj-devel709 committed Sep 27, 2023
1 parent 651de61 commit 930833e
Show file tree
Hide file tree
Showing 17 changed files with 685 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public override string ToString()
new GalleryPageFactory(() => new EditorCoreGalleryPage(), "Editor Gallery"),
new GalleryPageFactory(() => new RadioButtonCoreGalleryPage(), "RadioButton Core Gallery"),
new GalleryPageFactory(() => new DragAndDropGallery(), "Drag and Drop Gallery"),
new GalleryPageFactory(() => new KeyboardScrollingScrollingPageSmallTitlesGallery(), "Keyboard Scrolling Gallery - Scrolling Page / Small Titles"),
new GalleryPageFactory(() => new KeyboardScrollingScrollingPageLargeTitlesGallery(), "Keyboard Scrolling Gallery - Scrolling Page / Large Titles"),
new GalleryPageFactory(() => new KeyboardScrollingNonScrollingPageSmallTitlesGallery(), "Keyboard Scrolling Gallery - NonScrolling Page / Small Titles"),
new GalleryPageFactory(() => new KeyboardScrollingNonScrollingPageLargeTitlesGallery(), "Keyboard Scrolling Gallery - NonScrolling Page / Large Titles"),
new GalleryPageFactory(() => new LabelCoreGalleryPage(), "Label Gallery"),
new GalleryPageFactory(() => new GestureRecognizerGallery(), "Gesture Recognizer Gallery"),
new GalleryPageFactory(() => new ScrollViewCoreGalleryPage(), "ScrollView Gallery"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
AutomationId="KeyboardScrollingEditorsPage"
x:Class="Maui.Controls.Sample.KeyboardScrollingEditorsPage">
<Grid RowDefinitions="*,*">
<Grid Grid.Row="0">
<VerticalStackLayout>
<Editor Placeholder="Editor1" AutomationId="Editor1" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor2" AutomationId="Editor2" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor3" AutomationId="Editor3" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor4" AutomationId="Editor4" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor5" AutomationId="Editor5" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor6" AutomationId="Editor6" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor7" AutomationId="Editor7" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor8" AutomationId="Editor8" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor9" AutomationId="Editor9" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor10" AutomationId="Editor10" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor11" AutomationId="Editor11" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor12" AutomationId="Editor12" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor13" AutomationId="Editor13" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor14" AutomationId="Editor14" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor15" AutomationId="Editor15" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor16" AutomationId="Editor16" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor17" AutomationId="Editor17" Background="lightgray" HeightRequest="50"/>
<Editor Placeholder="Editor18" AutomationId="Editor17" Background="lightgray" HeightRequest="65"/>
</VerticalStackLayout>
</Grid>
</Grid>
</ContentView>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;

namespace Maui.Controls.Sample;

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class KeyboardScrollingEditorsPage : ContentView
{
public KeyboardScrollingEditorsPage()
{
InitializeComponent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
AutomationId="KeyboardScrollingEntriesPage"
x:Class="Maui.Controls.Sample.KeyboardScrollingEntriesPage"
xmlns:ios="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;assembly=Microsoft.Maui.Controls">
<Grid RowDefinitions="*,*">
<Grid Grid.Row="0">
<VerticalStackLayout>
<Entry Placeholder="Entry1" AutomationId="Entry1" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry2" AutomationId="Entry2" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry3" AutomationId="Entry3" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry4" AutomationId="Entry4" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry5" AutomationId="Entry5" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry6" AutomationId="Entry6" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry7" AutomationId="Entry7" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry8" AutomationId="Entry8" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry9" AutomationId="Entry9" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry10" AutomationId="Entry10" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry11" AutomationId="Entry11" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry12" AutomationId="Entry12" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry13" AutomationId="Entry13" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry14" AutomationId="Entry14" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry15" AutomationId="Entry15" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry16" AutomationId="Entry16" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry17" AutomationId="Entry17" Background="lightgray" HeightRequest="50"/>
<Entry Placeholder="Entry18" AutomationId="Entry18" Background="lightgray" HeightRequest="50"/>
</VerticalStackLayout>
</Grid>
</Grid>
</ContentView>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.PlatformConfiguration;
using Microsoft.Maui.Controls.Xaml;

namespace Maui.Controls.Sample;

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class KeyboardScrollingEntriesPage : ContentView
{
public KeyboardScrollingEntriesPage()
{
InitializeComponent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
AutomationId="KeyboardScrollingEntryNextEditorPage"
x:Class="Maui.Controls.Sample.KeyboardScrollingEntryNextEditorPage">
<Grid RowDefinitions="100,100,100,100" RowSpacing="25">
<Entry Placeholder="First Entry" AutomationId="Entry1" Background="lightgray" ReturnType="Next" Grid.Row="0"/>
<Entry Placeholder="Second Entry" AutomationId="Entry2" Background="lightgray" ReturnType="Next" Grid.Row="1"/>
<Entry Placeholder="Third Entry" AutomationId="Entry3" Background="lightgray" ReturnType="Next" Grid.Row="2"/>
<Editor Placeholder="Editor" AutomationId="Editor" Background="lightgray" Grid.Row="3"/>
</Grid>
</ContentView>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;

namespace Maui.Controls.Sample;

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class KeyboardScrollingEntryNextEditorPage : ContentView
{
public KeyboardScrollingEntryNextEditorPage()
{
InitializeComponent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.PlatformConfiguration;
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;

namespace Maui.Controls.Sample
{
[Preserve(AllMembers = true)]
public class KeyboardScrollingNonScrollingPageLargeTitlesGallery : ContentViewGalleryPage
{
public KeyboardScrollingNonScrollingPageLargeTitlesGallery()
{
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Always);
Add(new KeyboardScrollingEntriesPage());
Add(new KeyboardScrollingEditorsPage());
Add(new KeyboardScrollingEntryNextEditorPage());
}

protected override bool SupportsScroll
{
get { return false; }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.PlatformConfiguration;
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;

namespace Maui.Controls.Sample
{
[Preserve(AllMembers = true)]
public class KeyboardScrollingNonScrollingPageSmallTitlesGallery : ContentViewGalleryPage
{
public KeyboardScrollingNonScrollingPageSmallTitlesGallery()
{
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Never);
Add(new KeyboardScrollingEntriesPage());
Add(new KeyboardScrollingEditorsPage());
Add(new KeyboardScrollingEntryNextEditorPage());
}

protected override bool SupportsScroll
{
get { return false; }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.PlatformConfiguration;
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;

namespace Maui.Controls.Sample
{
[Preserve(AllMembers = true)]
public class KeyboardScrollingScrollingPageLargeTitlesGallery : ContentViewGalleryPage
{
public KeyboardScrollingScrollingPageLargeTitlesGallery()
{
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Always);
Add(new KeyboardScrollingEntriesPage());
Add(new KeyboardScrollingEditorsPage());
Add(new KeyboardScrollingEntryNextEditorPage());
}

protected override bool SupportsScroll
{
get { return true; }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.PlatformConfiguration;
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;

namespace Maui.Controls.Sample
{
[Preserve(AllMembers = true)]
public class KeyboardScrollingScrollingPageSmallTitlesGallery : ContentViewGalleryPage
{
public KeyboardScrollingScrollingPageSmallTitlesGallery()
{
On<iOS>().SetLargeTitleDisplay(LargeTitleDisplayMode.Never);
Add(new KeyboardScrollingEntriesPage());
Add(new KeyboardScrollingEditorsPage());
Add(new KeyboardScrollingEntryNextEditorPage());
}

protected override bool SupportsScroll
{
get { return true; }
}
}
}
149 changes: 149 additions & 0 deletions src/Controls/tests/UITests/Tests/KeyboardScrolling.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using Maui.Controls.Sample;
using Microsoft.Maui.Appium;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Graphics;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Enums;
using TestUtils.Appium.UITests;
using VisualTestUtils;
using Xamarin.UITest;
using Xamarin.UITest.Queries;

namespace Microsoft.Maui.AppiumTests
{
internal static class KeyboardScrolling
{
internal static void EntriesScrollingTest(IApp app, IUITestContext? testContext, string galleryName)
{
BeginScrollingTest(app, testContext, galleryName, false);
}

internal static void EditorsScrollingTest(IApp app, IUITestContext? testContext, string galleryName)
{
BeginScrollingTest(app, testContext, galleryName, true);
}

static void BeginScrollingTest(IApp app, IUITestContext? testContext, string galleryName, bool isEditor)
{
testContext.IgnoreIfPlatforms(new TestDevice[] { TestDevice.Android, TestDevice.Mac, TestDevice.Windows },
"These tests take a while and we are more interested in iOS Scrolling Behavior since it is not out-of-the-box.");

// Entries 6 - 14 hit a group of interesting areas on scrolling
// depending on the type of iOS device.
for (int i = 6; i <= 14; i++)
{
var shouldContinue = false;
if (isEditor)
shouldContinue = NavigateTest(app, $"Editor{i}", "KeyboardScrollingEditorsPage", isEditor);
else
shouldContinue = NavigateTest(app, $"Entry{i}", "KeyboardScrollingEntriesPage", isEditor);

app.NavigateToGallery(galleryName);

if (!shouldContinue)
break;
}
}

static bool NavigateTest(IApp app, string marked, string pageName, bool isEditor)
{
app.WaitForElement("TargetView");
app.EnterText("TargetView", pageName);
app.Tap("GoButton");
app.Tap(marked);
var shouldContinue = CheckIfViewAboveKeyboard(app, marked, isEditor);
if (shouldContinue)
HideKeyboard(app, (app as AppiumUITestApp)?.Driver, isEditor);
app.NavigateBack();
return shouldContinue;
}

// will return a bool showing if the view is visible
static bool CheckIfViewAboveKeyboard(IApp app, string marked, bool isEditor)
{
var views = app.WaitForElement(marked);

// if this view is not on the screen, the keyboard will not be
// showing and we can skip this view
if (!app.IsKeyboardShown())
return false;

Assert.IsNotEmpty(views);
var rect = views[0].Rect;

var testApp = app as AppiumUITestApp;
var keyboardPositionNullable = FindiOSKeyboardLocation(testApp?.Driver);
Assert.NotNull(keyboardPositionNullable);

var keyboardPosition = (System.Drawing.Point)keyboardPositionNullable!;
if (isEditor)
{
// Until we can get the default Maui accessory view added on the editors,
// let's just use the default height added for the accessory view
var defaultSizeAccessoryView = 44;
keyboardPosition.Y -= defaultSizeAccessoryView;

}
Assert.Less(rect.CenterY, keyboardPosition.Y);

return true;
}

internal static void HideKeyboard(IApp app, AppiumDriver? driver, bool isEditor)
{
if (isEditor)
CloseiOSEditorKeyboard(driver);
else
app.DismissKeyboard();
}

internal static System.Drawing.Point? FindiOSKeyboardLocation(AppiumDriver? driver)
{
if (driver?.IsKeyboardShown() == true)
{
var keyboard = driver.FindElement(MobileBy.ClassName("UIAKeyboard"));
return keyboard.Location;
}
return null;
}

internal static void CloseiOSEditorKeyboard(AppiumDriver? driver)
{
var keyboardDoneButton = driver?.FindElement(MobileBy.Name("Done"));
keyboardDoneButton?.Click();
}

internal static void EntryNextEditorScrollingTest(IApp app, IUITestContext? testContext, string galleryName)
{
testContext.IgnoreIfPlatforms(new TestDevice[] { TestDevice.Android, TestDevice.Mac, TestDevice.Windows },
"These tests take a while and we are more interested in iOS Scrolling Behavior since it is not out-of-the-box.");

app.WaitForElement("TargetView");
app.EnterText("TargetView", "KeyboardScrollingEntryNextEditorPage");
app.Tap("GoButton");

app.WaitForElement("Entry1");
app.Tap("Entry1");
CheckIfViewAboveKeyboard(app, "Entry1", false);
NextiOSKeyboardPress((app as AppiumUITestApp)?.Driver);

CheckIfViewAboveKeyboard(app, "Entry2", false);
NextiOSKeyboardPress((app as AppiumUITestApp)?.Driver);

CheckIfViewAboveKeyboard(app, "Entry3", false);
NextiOSKeyboardPress((app as AppiumUITestApp)?.Driver);

CheckIfViewAboveKeyboard(app, "Editor", true);
}

// Unintentionally types a 'V' but also presses the next keyboard key
internal static void NextiOSKeyboardPress(AppiumDriver? driver)
{
var keyboard = driver?.FindElement(MobileBy.ClassName("UIAKeyboard"));
keyboard?.SendKeys("\n");
}
}
}

Loading

0 comments on commit 930833e

Please sign in to comment.