66 lines
2.6 KiB
C#
66 lines
2.6 KiB
C#
namespace Duempelkas.App.Services;
|
|
|
|
public enum ToastKind { Info, Success, Error }
|
|
public sealed record ToastMessage(Guid Id, string Message, ToastKind Kind, string? Details,
|
|
string? ActionLabel, Func<Task>? Action);
|
|
|
|
public sealed class ToastService : IDisposable
|
|
{
|
|
private readonly object sync = new();
|
|
private readonly Dictionary<Guid, (ToastMessage Message, Timer? Timer, TimeSpan? Remaining, DateTimeOffset Started)> items = [];
|
|
public event Action? Changed;
|
|
public IReadOnlyList<ToastMessage> Messages { get { lock (sync) return items.Values.Select(x => x.Message).ToArray(); } }
|
|
|
|
public Guid Show(string message, ToastKind kind = ToastKind.Info, string? details = null,
|
|
string? actionLabel = null, Func<Task>? action = null, TimeSpan? duration = null, bool persistent = false)
|
|
{
|
|
var id = Guid.NewGuid();
|
|
var lifetime = persistent ? (TimeSpan?)null : duration ?? TimeSpan.FromSeconds(kind == ToastKind.Error ? 15 : 9);
|
|
var toast = new ToastMessage(id, message, kind, details, actionLabel, action);
|
|
lock (sync)
|
|
{
|
|
Timer? timer = lifetime.HasValue ? new Timer(_ => Dismiss(id), null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan) : null;
|
|
items[id] = (toast, timer, lifetime, DateTimeOffset.UtcNow);
|
|
if (lifetime.HasValue) timer!.Change(lifetime.Value, Timeout.InfiniteTimeSpan);
|
|
}
|
|
Changed?.Invoke();
|
|
return id;
|
|
}
|
|
|
|
public void Pause(Guid id)
|
|
{
|
|
lock (sync)
|
|
{
|
|
if (!items.TryGetValue(id, out var item) || item.Remaining == null || item.Started == default) return;
|
|
item.Timer?.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
|
|
var left = item.Remaining.Value - (DateTimeOffset.UtcNow - item.Started);
|
|
items[id] = (item.Message, item.Timer, left > TimeSpan.Zero ? left : TimeSpan.FromMilliseconds(1), default);
|
|
}
|
|
}
|
|
|
|
public void Resume(Guid id)
|
|
{
|
|
lock (sync)
|
|
{
|
|
if (!items.TryGetValue(id, out var item) || item.Remaining == null || item.Started != default) return;
|
|
items[id] = (item.Message, item.Timer, item.Remaining, DateTimeOffset.UtcNow);
|
|
item.Timer?.Change(item.Remaining.Value, Timeout.InfiniteTimeSpan);
|
|
}
|
|
}
|
|
|
|
public void Dismiss(Guid id)
|
|
{
|
|
lock (sync)
|
|
{
|
|
if (!items.Remove(id, out var item)) return;
|
|
item.Timer?.Dispose();
|
|
}
|
|
Changed?.Invoke();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
lock (sync) { foreach (var item in items.Values) item.Timer?.Dispose(); items.Clear(); }
|
|
}
|
|
}
|