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

Snackbar: Allow to attach custom task on close button click #8589

Draft
wants to merge 6 commits into
base: dev
Choose a base branch
from

Conversation

BieleckiLtd
Copy link
Contributor

Allows the attachment of a custom task when a user dismisses the message by clicking the close button.

Description

Closes #7317

How Has This Been Tested?

unit | visually

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist:

  • The PR is submitted to the correct branch (dev).
  • My code follows the code style of this project.
  • I've added relevant tests.

@github-actions github-actions bot added enhancement New feature or request PR: needs review labels Apr 6, 2024
Copy link

codecov bot commented Apr 6, 2024

Codecov Report

Attention: Patch coverage is 69.23077% with 4 lines in your changes are missing coverage. Please review.

Project coverage is 89.89%. Comparing base (28bc599) to head (516d06f).
Report is 119 commits behind head on dev.

❗ Current head 516d06f differs from pull request most recent head e8654e4. Consider uploading reports for the commit e8654e4 to get more accurate results

Files Patch % Lines
...or/Components/Snackbar/MudSnackbarElement.razor.cs 50.00% 0 Missing and 2 partials ⚠️
src/MudBlazor/Components/Snackbar/Snackbar.cs 71.42% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #8589      +/-   ##
==========================================
+ Coverage   89.82%   89.89%   +0.06%     
==========================================
  Files         412      414       +2     
  Lines       11878    11912      +34     
  Branches     2364     2365       +1     
==========================================
+ Hits        10670    10708      +38     
+ Misses        681      675       -6     
- Partials      527      529       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@danielchalmers danielchalmers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the refactors! Interested in seeing how others feel about CodeInline; Makes sense to me.

src/MudBlazor/Components/Snackbar/Snackbar.cs Outdated Show resolved Hide resolved
src/MudBlazor/Components/Snackbar/Snackbar.cs Outdated Show resolved Hide resolved
/// <summary>
/// The asynchronous delegate that is invoked when the Snackbar is clicked.
/// </summary>
public Func<Snackbar, Task> OnClick { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the rename. Needs to be added to the Migration Guide if accepted

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OnClickAsync?


// Click action is executed only if it's not from the close icon
await State.Options.OnClick.Invoke(this);
//await State.Options.OnClick.Invoke(this);
State.Options.OnClick.Invoke(this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, shouldn't Clicked still be async and this call be awaited? I might be totally wrong

ActionClickedAsync and CloseIconClickedAsync could be non-async because they were directly calling another Task

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe someone could have a fresh pair of eyes look at it, but with the code as is, my async actions OnClick and OnCloseButtonClick are being awaited correctly in the use case like this:

private void Show()
{
    Snackbar.Add("Close me using the close button.", Severity.Normal, config =>
    {
        config.RequireInteraction = true;
        config.OnCloseButtonClick = SayGoodbyeAsync;
        config.Action = "Adiós";
        config.OnClick = SayGoodbyeAsync;
    });
}

public async Task SayGoodbyeAsync(Snackbar snackbar)
{
    await Task.Delay(5000); // this is being awaited ok
    Snackbar.Add("Sorry to see you go!");
}

The snackbar will be dismissed immediately upon clicking the close button, with any attached task invoked and awaited in the background. I think that would work alright from a UX perspective. On the other hand, if in the Clicked method I await my custom task to complete before closing the snackbar, this could give the impression that the click did not register or the app has hung.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@henon Thoughts on this behavior? Makes sense to me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exceptions in the OnClick method would be swallowed though. So the best thing to do would be this:

_ = InvokeAndLogException(State.Options.OnClick); where InvokeAndLogException is:

[Inject]
private ILoggerFactory LoggerFactory { get; set; } = null!;
private ILogger? _logger;
protected ILogger Logger => _logger ??= LoggerFactory.CreateLogger(GetType());


private async Task InvokeAndLogException(Func<Snackbar, Task> func) {
  try {
    await func(this)
  }
  catch(Exception e) {
    Logger.LogErrpr("An exception happened in Snackbar.OnClick: {e.Message}\n");
  }
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe @ScarletKuro has a better idea

Copy link
Contributor

@Yomodo Yomodo Apr 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logger.LogError has an overload that accepts Exception? that might provide stack as well.
Edit: Hm, perhaps not always wanted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it's simply not

await State.Options.OnClick.Invoke(this);

?
It's an Func<Snackbar, Task> and if re are renaming, it probably makes sense to name it OnClickAsync
Otherwise I don't get the Clicked change from void to Task
Well, I mean I understand you did it for the ActionClickedAsync / CloseIconClickedAsync, but it makes sense to use await now when it's a Task.

@danielchalmers danielchalmers removed the request for review from ScarletKuro April 24, 2024 05:36
@henon henon requested a review from ScarletKuro April 24, 2024 18:09
@BieleckiLtd BieleckiLtd marked this pull request as draft April 27, 2024 12:11
@henon
Copy link
Collaborator

henon commented May 2, 2024

This is almost done, isn't it?

if (fromCloseIcon)
{
// Invoke user-defined task when close button is clicked
State.Options.OnCloseButtonClick?.Invoke(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be

await State.Options.OnCloseButtonClick.Invoke(this); //with null check

?
since OnCloseButtonClick is Func<Snackbar, Task>. It would probably make sense to add Async suffix.


// Click action is executed only if it's not from the close icon
await State.Options.OnClick.Invoke(this);
//await State.Options.OnClick.Invoke(this);
State.Options.OnClick.Invoke(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it's simply not

await State.Options.OnClick.Invoke(this);

?
It's an Func<Snackbar, Task> and if re are renaming, it probably makes sense to name it OnClickAsync
Otherwise I don't get the Clicked change from void to Task
Well, I mean I understand you did it for the ActionClickedAsync / CloseIconClickedAsync, but it makes sense to use await now when it's a Task.

/// <summary>
/// The asynchronous delegate that is invoked when the close button of the Snackbar is clicked.
/// </summary>
public Func<Snackbar, Task> OnCloseButtonClick { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OnCloseButtonClickAsync?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree, it should be CloseButtonClickFunc.

/// <summary>
/// The asynchronous delegate that is invoked when the Snackbar is clicked.
/// </summary>
public Func<Snackbar, Task> OnClick { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OnClickAsync?

@@ -30,23 +30,35 @@ internal Snackbar(SnackbarMessage message, SnackbarOptions options)

internal void Init() => TransitionTo(SnackbarState.Showing);

internal void Clicked(bool fromCloseIcon)
internal Task Clicked(bool fromCloseIcon)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClickedAsync.

@ScarletKuro
Copy link
Member

This is almost done, isn't it?

I don't think so, the build is failing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow custom actions for close button in MudSnackbar
5 participants