-
-
Notifications
You must be signed in to change notification settings - Fork 264
Expand file tree
/
Copy pathBitFcCalendarToast.razor.cs
More file actions
90 lines (82 loc) · 2.56 KB
/
Copy pathBitFcCalendarToast.razor.cs
File metadata and controls
90 lines (82 loc) · 2.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
namespace Bit.BlazorUI;
public partial class BitFcCalendarToast : IAsyncDisposable
{
private readonly List<ToastItem> _toasts = [];
private readonly List<CancellationTokenSource> _removalTokens = [];
private readonly object _removalTokensLock = new();
private int _nextId;
public void Show(string message, bool isError = false)
{
var item = new ToastItem { Id = _nextId++, Message = message, IsError = isError };
_toasts.Add(item);
StateHasChanged();
var cts = new CancellationTokenSource();
lock (_removalTokensLock)
{
_removalTokens.Add(cts);
}
_ = RemoveAfterDelay(item.Id, cts);
}
private async Task RemoveAfterDelay(int id, CancellationTokenSource cts)
{
try
{
try
{
await Task.Delay(3000, cts.Token);
}
catch (OperationCanceledException)
{
return;
}
// Mutate the toast list on the renderer's dispatcher to avoid racing the template's foreach.
await InvokeAsync(() =>
{
_toasts.RemoveAll(t => t.Id == id);
StateHasChanged();
});
}
finally
{
// Drop the token as soon as its timer finishes (or is cancelled) so _removalTokens
// doesn't grow unbounded on long-lived pages that show many toasts.
bool removed;
lock (_removalTokensLock)
{
removed = _removalTokens.Remove(cts);
}
if (removed)
cts.Dispose();
}
}
public ValueTask DisposeAsync()
{
// Snapshot under the lock: RemoveAfterDelay also removes/disposes tokens as their timers
// complete, so reading the live list here could race with that cleanup.
CancellationTokenSource[] tokens;
lock (_removalTokensLock)
{
tokens = _removalTokens.ToArray();
_removalTokens.Clear();
}
foreach (var cts in tokens)
{
try
{
cts.Cancel();
cts.Dispose();
}
catch (ObjectDisposedException)
{
// Already disposed by RemoveAfterDelay's cleanup; nothing to do.
}
}
return ValueTask.CompletedTask;
}
private class ToastItem
{
public int Id { get; set; }
public string Message { get; set; } = "";
public bool IsError { get; set; }
}
}