Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Add Popup.CloseAsync() #1222

Closed
8 tasks done
brminnick opened this issue Jun 6, 2023 · 8 comments · Fixed by #1223
Closed
8 tasks done

[Proposal] Add Popup.CloseAsync() #1222

brminnick opened this issue Jun 6, 2023 · 8 comments · Fixed by #1223
Assignees
Labels
approved This Proposal has been approved and is ready to be added to the Toolkit champion A member of the .NET MAUI Toolkit core team has chosen to champion this feature documentation approved proposal A fully fleshed out proposal describing a new feature in syntactic and semantic detail

Comments

@brminnick
Copy link
Collaborator

brminnick commented Jun 6, 2023

Feature name

Add Popup.CloseAsync()

Link to discussion

Discussed in June 2023 Standup:

https://github.com/CommunityToolkit/Maui/wiki/2023-June-Standup

Progress tracker

Summary

This Proposal adds the following API to Popup:

public async Task CloseAsync(object? result = null);

CloseAsync() returns once the operating system has dismissed Popup from the page.

Motivation

Currently, Popup only offers one method to programmatically dismiss it from the screen: public void Close();.

However, on MacCatalyst and iOS, the code required to dismiss the Popup uses async/await to dismiss the UIViewController:

public static async void MapOnClosed(PopupHandler handler, IPopup view, object? result)
{
var vc = handler.PlatformView.ViewController;
if (vc is not null)
{
await vc.DismissViewControllerAsync(true);
}
handler.DisconnectHandler(handler.PlatformView);
}

The existing Close() API is thus acting in a fire-and-forget manner; the method is returning to the caller before the Popup has been dismissed on iOS + MacCatalyst.

Detailed Design

IPopup.shared.cs

This API update requires a TaskCompletionSource in IPopup that can be referenced by both the Handler and the Control.

This is required because the PropertyMappers / CommandMappers that .NET MAUI use for Handlers are not asynchronous (they cannot be awaitd).

We will instead tell the Control to await PopupDismissedTaskCompletionSource.Task after IPopup.Closed() has been called. Then, in PopupHandler.MapOnClosed, we will call PopupDismissedTaskCompletionSource TrySetResult() after the operating system has dismissed the Popup from the page.

public interface IPopup : IElement, IVisualTreeElement
{
    // ...
    // Existing APIs
    //..

    /// <summary>
    /// <see cref="TaskCompletionSource"/> that completes when the operating system has dismissed <see cref="IPopup"/> from the screen
    /// </summary>
    TaskCompletionSource PopupDismissedTaskCompletionSource { get; }
}

Popup.shared.cs

This Proposal also requires a new API public Task Popup.CloseAsync(object? result = null);

/// <summary>
/// Close the current popup.
/// </summary>
/// <remarks>
/// Returns once the operating system has dismissed the <see cref="IPopup"/> from the page
/// </remarks>
/// <param name="result">
/// The result to return.
/// </param>
public async Task CloseAsync(object? result = null)
{
  await OnClosed(result, false);
  taskCompletionSource.TrySetResult(result);
}

Usage Syntax

async void Button_Clicked(object? sender, EventArgs e)
{
    await CloseAsync();
    await Toast.Make("Popup Dismissed By Button").Show();
}

Drawbacks

Only iOS + MacCatalyst defer to a different thread when dismissing the Popup; Android and Windows can dismiss the Popup synchronously. Adding a method that returns Task adds a bit of overhead to our users, however, the overhead should be negligible as users typically only display, and subsequently close, one Popup at a time.

Alternatives

This Proposal can be updated to remove the fire-and-forget method, void Close().

However, removing an existing API is a breaking change.

Unresolved Questions

Should we instead return ValueTask?

public async ValueTask CloseAsync(object? result = null)
@brminnick brminnick added new proposal A fully fleshed out proposal describing a new feature in syntactic and semantic detail labels Jun 6, 2023
@brminnick brminnick self-assigned this Jun 6, 2023
@ghost ghost added champion A member of the .NET MAUI Toolkit core team has chosen to champion this feature and removed new labels Jun 6, 2023
@brminnick brminnick mentioned this issue Jun 6, 2023
6 tasks
@brminnick brminnick added the needs discussion Discuss it on the next Monthly standup label Jun 6, 2023
@VladislavAntonyuk
Copy link
Collaborator

Approve. Can we change only return type from void to Task/ValueTask and keep the name “Close”? The app will behave the same until user fix the warning and await method

@brminnick
Copy link
Collaborator Author

brminnick commented Jun 6, 2023

Thanks Vlad! That was my initial plan, but I decided against replacing the existing void Close() method for two reasons:

  1. Replacing void Close() -> Task Close() would be a breaking change
  2. Some users may not want to await the closure of a Popup (eg using a non-async button handler)

That being said, you know how much I love async/await and I always love to push developers to use the "better" API, so if the other maintainers agree that we should replace void Close() with Task Close(), I'm happy to commit!

@kphillpotts
Copy link
Contributor

Approve. I like the solution you propose @brminnick for the following reasons:

  1. It's a non-breaking change
  2. It's easily understandable and consistent with other api surfaces
  3. It balances out the ShowPopup/Close and the ShowPopupAsync/CloseAsync methods.

@bijington
Copy link
Contributor

I'm happy to approve this also

@ghost ghost added approved This Proposal has been approved and is ready to be added to the Toolkit help wanted This proposal has been approved and is ready to be implemented labels Jun 8, 2023
@brminnick brminnick removed the help wanted This proposal has been approved and is ready to be implemented label Jun 8, 2023
@brminnick
Copy link
Collaborator Author

Great! Approved ✅

@marekm294
Copy link

Hey, quick question. Does it solve #1111 ?

@brminnick
Copy link
Collaborator Author

Does it solve #1111 ?

Yup! Thanks, I've added linked it to the PR.

@ghost
Copy link

ghost commented Jul 10, 2023

Reopening Proposal.

Only Proposals moved to the Closed Project Column and Completed Project Column can be closed.

@github-actions github-actions bot locked and limited conversation to collaborators Nov 22, 2024
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
approved This Proposal has been approved and is ready to be added to the Toolkit champion A member of the .NET MAUI Toolkit core team has chosen to champion this feature documentation approved proposal A fully fleshed out proposal describing a new feature in syntactic and semantic detail
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants