Skip to content

Commit

Permalink
DisplayActionSheet later (#5047)
Browse files Browse the repository at this point in the history
* DisplayActionSheet later

* - update loaded wiring on handler changed

* Clean up/fix old iOS alert code

We were previously creating new UIWindows presumably for some historic use case... This removes that and uses the window that's passed into the manager when created.

* - change to using NavigatedTo

Co-authored-by: redth <jondick@gmail.com>
Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
  • Loading branch information
3 people authored Mar 9, 2022
1 parent 379bc08 commit fffaae1
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ public AlertsPage()
InitializeComponent();
}

protected override async void OnAppearing()
{
base.OnAppearing();
await DisplayAlert("Alert", "Welcome to the Alerts Page", "Hello!");
}

async void OnAlertSimpleClicked(object sender, EventArgs e)
{
await DisplayAlert("Alert", "You have been alerted", "OK");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ private protected override void OnHandlerChangedCore()
base.OnHandlerChangedCore();

IsPlatformEnabled = Handler != null;
UpdatePlatformUnloadedLoadedWiring(Window);
}

Paint? IView.Background
Expand Down
8 changes: 5 additions & 3 deletions src/Controls/src/Core/Page.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public Page()

InternalChildren.CollectionChanged += InternalChildrenOnCollectionChanged;
_platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Page>>(() => new PlatformConfigurationRegistry<Page>(this));
this.NavigatedTo += FlushPendingActions;
}

/// <include file="../../docs/Microsoft.Maui.Controls/Page.xml" path="//Member[@MemberName='BackgroundImageSource']/Docs" />
Expand Down Expand Up @@ -251,16 +252,17 @@ public Task<bool> DisplayAlert(string title, string message, string accept, stri
return args.Result.Task;
}

internal override void OnIsPlatformEnabledChanged()
void FlushPendingActions(object sender, EventArgs e)
{
base.OnIsPlatformEnabledChanged();
if (IsPlatformEnabled && _pendingActions.Count > 0)
if (_pendingActions.Count > 0)
{
var actionsToProcess = _pendingActions.ToList();
_pendingActions.Clear();
foreach (var pendingAction in actionsToProcess)
pendingAction();
}

this.NavigatedTo -= FlushPendingActions;
}

/// <include file="../../docs/Microsoft.Maui.Controls/Page.xml" path="//Member[@MemberName='ForceLayout']/Docs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,15 @@ void OnActionSheetRequested(Page sender, ActionSheetArguments arguments)

if (pageParent != null)
actionSheet.ShowAt(pageParent);
else
arguments.SetResult(null);
}
catch (ArgumentException) // If the page is not in the visual tree
{
if (UI.Xaml.Window.Current.Content is FrameworkElement mainPage)
if (UI.Xaml.Window.Current != null && UI.Xaml.Window.Current.Content is FrameworkElement mainPage)
actionSheet.ShowAt(mainPage);
else
arguments.SetResult(null);
}
}

Expand Down
51 changes: 17 additions & 34 deletions src/Controls/src/Core/Platform/AlertManager/AlertManager.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,31 +88,27 @@ void OnActionSheetRequested(IView sender, ActionSheetArguments arguments)

void PresentAlert(AlertArguments arguments)
{
var window = new UIWindow { BackgroundColor = Colors.Transparent.ToPlatform() };

var alert = UIAlertController.Create(arguments.Title, arguments.Message, UIAlertControllerStyle.Alert);
var oldFrame = alert.View.Frame;
alert.View.Frame = new RectF((float)oldFrame.X, (float)oldFrame.Y, (float)oldFrame.Width, (float)oldFrame.Height - AlertPadding * 2);

if (arguments.Cancel != null)
{
alert.AddAction(CreateActionWithWindowHide(arguments.Cancel, UIAlertActionStyle.Cancel,
() => arguments.SetResult(false), window));
alert.AddAction(UIAlertAction.Create(arguments.Cancel, UIAlertActionStyle.Cancel,
_ => arguments.SetResult(false)));
}

if (arguments.Accept != null)
{
alert.AddAction(CreateActionWithWindowHide(arguments.Accept, UIAlertActionStyle.Default,
() => arguments.SetResult(true), window));
alert.AddAction(UIAlertAction.Create(arguments.Accept, UIAlertActionStyle.Default,
_ => arguments.SetResult(true)));
}

PresentPopUp(window, alert);
PresentPopUp(Window, alert);
}

void PresentPrompt(PromptArguments arguments)
{
var window = new UIWindow { BackgroundColor = Colors.Transparent.ToPlatform() };

var alert = UIAlertController.Create(arguments.Title, arguments.Message, UIAlertControllerStyle.Alert);
alert.AddTextField(uiTextField =>
{
Expand All @@ -125,27 +121,26 @@ void PresentPrompt(PromptArguments arguments)
var oldFrame = alert.View.Frame;
alert.View.Frame = new RectF((float)oldFrame.X, (float)oldFrame.Y, (float)oldFrame.Width, (float)oldFrame.Height - AlertPadding * 2);

alert.AddAction(CreateActionWithWindowHide(arguments.Cancel, UIAlertActionStyle.Cancel, () => arguments.SetResult(null), window));
alert.AddAction(CreateActionWithWindowHide(arguments.Accept, UIAlertActionStyle.Default, () => arguments.SetResult(alert.TextFields[0].Text), window));
alert.AddAction(UIAlertAction.Create(arguments.Cancel, UIAlertActionStyle.Cancel, _ => arguments.SetResult(null)));
alert.AddAction(UIAlertAction.Create(arguments.Accept, UIAlertActionStyle.Default, _ => arguments.SetResult(alert.TextFields[0].Text)));

PresentPopUp(window, alert);
PresentPopUp(Window, alert);
}


void PresentActionSheet(ActionSheetArguments arguments)
{
var alert = UIAlertController.Create(arguments.Title, null, UIAlertControllerStyle.ActionSheet);
var window = new UIWindow { BackgroundColor = Colors.Transparent.ToPlatform() };

// Clicking outside of an ActionSheet is an implicit cancel on iPads. If we don't handle it, it freezes the app.
if (arguments.Cancel != null || UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
{
alert.AddAction(CreateActionWithWindowHide(arguments.Cancel ?? "", UIAlertActionStyle.Cancel, () => arguments.SetResult(arguments.Cancel), window));
alert.AddAction(UIAlertAction.Create(arguments.Cancel ?? "", UIAlertActionStyle.Cancel, _ => arguments.SetResult(arguments.Cancel)));
}

if (arguments.Destruction != null)
{
alert.AddAction(CreateActionWithWindowHide(arguments.Destruction, UIAlertActionStyle.Destructive, () => arguments.SetResult(arguments.Destruction), window));
alert.AddAction(UIAlertAction.Create(arguments.Destruction, UIAlertActionStyle.Destructive, _ => arguments.SetResult(arguments.Destruction)));
}

foreach (var label in arguments.Buttons)
Expand All @@ -155,18 +150,13 @@ void PresentActionSheet(ActionSheetArguments arguments)

var blabel = label;

alert.AddAction(CreateActionWithWindowHide(blabel, UIAlertActionStyle.Default, () => arguments.SetResult(blabel), window));
alert.AddAction(UIAlertAction.Create(blabel, UIAlertActionStyle.Default, _ => arguments.SetResult(blabel)));
}

PresentPopUp(window, alert, arguments);
PresentPopUp(Window, alert, arguments);
}
static void PresentPopUp(UIWindow window, UIAlertController alert, ActionSheetArguments arguments = null)
{
window.RootViewController = new UIViewController();
window.RootViewController.View.BackgroundColor = Colors.Transparent.ToPlatform();
window.WindowLevel = UIWindowLevel.Alert + 1;
window.MakeKeyAndVisible();

if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad && arguments != null)
{
UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications();
Expand All @@ -184,18 +174,11 @@ static void PresentPopUp(UIWindow window, UIAlertController alert, ActionSheetAr
alert.PopoverPresentationController.PermittedArrowDirections = 0; // No arrow
}

window.RootViewController.PresentViewController(alert, true, null);
}

// Creates a UIAlertAction which includes a call to hide the presenting UIWindow at the end
UIAlertAction CreateActionWithWindowHide(string text, UIAlertActionStyle style, Action setResult, UIWindow window)
{
return UIAlertAction.Create(text, style,
action =>
{
window.Hidden = true;
setResult();
});
window.BeginInvokeOnMainThread(() =>
{
_ = window.RootViewController.PresentViewControllerAsync(alert, true);
});

}
}
}
Expand Down
47 changes: 47 additions & 0 deletions src/Controls/tests/DeviceTests/Elements/VisualElementTests.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Hosting;
using Xunit;

namespace Microsoft.Maui.DeviceTests
{
[Category(TestCategory.VisualElement)]
public partial class VisualElementTests : HandlerTestBase
{
void SetupBuilder()
{
EnsureHandlerCreated(builder =>
{
builder.ConfigureMauiHandlers(handlers =>
{
#if WINDOWS || ANDROID
handlers.AddHandler<NavigationPage, NavigationViewHandler>();
handlers.AddHandler<Toolbar, ToolbarHandler>();
#else
handlers.AddHandler<NavigationPage, Controls.Handlers.Compatibility.NavigationRenderer>();
#endif
});
});
}

[Fact]
public async Task CanCreateHandler()
{
Expand Down Expand Up @@ -87,5 +104,35 @@ await CreateHandlerAndAddToWindow<LayoutHandler>(parentLayout, async (handler) =
Assert.Equal(2, loaded);
Assert.Equal(2, unloaded);
}

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

var navPage = new NavigationPage(new ContentPage());
var page = new ContentPage();

int unloaded = 0;
int loaded = 0;
page.Loaded += (_, __) => loaded++;
page.Unloaded += (_, __) => unloaded++;

await CreateHandlerAndAddToWindow<NavigationViewHandler>(navPage, async (handler) =>
{
Assert.Equal(0, loaded);
Assert.Equal(0, unloaded);
await navPage.PushAsync(page);
Assert.Equal(1, loaded);
Assert.Equal(0, unloaded);
await navPage.PopAsync();
Assert.Equal(1, loaded);
Assert.Equal(1, unloaded);
});
}
}
}

0 comments on commit fffaae1

Please sign in to comment.