Files
duempelkas/src/Duempelkas.App/Services/ToastService.cs
T

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(); }
}
}