using Blazored.LocalStorage; using decePubClient.Models; namespace decePubClient.Services { /// /// Asks a persona, once, before its first reaction or poll vote, and once before it first joins an event, to accept /// that these are public and visible as that persona (an owner decision); and this device, once, before its first Web /// Push subscription, to accept that the browser's push service learns when notifications arrive (PublicAct.Push, told /// once for the device whichever persona asks). PublicNoticeHost shows the question; Confirm returns true at once for /// what was accepted already, and false when the reader declines. /// public class PublicNoticeService(ILocalStorageService localStorage) { TaskCompletionSource pending; public event Action Changed; public bool IsAsking => pending is not null; /// What the persona is being told about. public PublicAct Act { get; private set; } = PublicAct.Reaction; public async Task Confirm(string personaId, PublicAct act = PublicAct.Reaction, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(personaId) && act != PublicAct.Push) return false; var seen = await localStorage.GetItemAsync(nameof(PublicActionNotices), cancellationToken) ?? new(); var told = act == PublicAct.Participation ? seen.EventPersonaIds : seen.PersonaIds; if (act == PublicAct.Push ? seen.PushTold : told.Contains(personaId)) return true; Act = act; pending = new TaskCompletionSource(); Changed?.Invoke(); var accepted = await pending.Task; pending = null; Changed?.Invoke(); if (!accepted) return false; if (act == PublicAct.Push) seen.PushTold = true; else told.Add(personaId); await localStorage.SetItemAsync(nameof(PublicActionNotices), seen, cancellationToken); return true; } public void Answer(bool accepted) => pending?.TrySetResult(accepted); } }