1using System.Diagnostics.CodeAnalysis;
15 private const int nrTypes = 4;
17 private readonly SortedDictionary<CaseInsensitiveString, List<NotificationEvent>>[] events;
18 private readonly LinkedList<ExpectedEvent> expected;
27 this.events =
new SortedDictionary<CaseInsensitiveString, List<NotificationEvent>>[nrTypes];
28 this.expected =
new LinkedList<ExpectedEvent>();
30 for (i = 0; i < nrTypes; i++)
39 public override async Task
Load(
bool isResuming, CancellationToken cancellationToken)
41 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>>? ByCategory =
null;
42 List<NotificationEvent>? Events =
null;
43 string? PrevCategory =
null;
47 IEnumerable<NotificationEvent> LoadedEvents;
67 if (Type < 0 || Type >= nrTypes)
72 Log.
Debug(
"Notification event of type " +
Event.GetType().FullName +
" lacked Category.");
79 if (ByCategory is
null || Type != PrevType)
81 ByCategory = this.events[Type];
85 if (Events is
null ||
Event.Category != PrevCategory)
87 if (!ByCategory.TryGetValue(
Event.Category, out Events))
90 ByCategory[
Event.Category] = Events;
93 PrevCategory =
Event.Category;
100 await base.Load(isResuming, cancellationToken);
119 for (
int i = 0; i < nrTypes; i++)
121 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> ByCategory = this.events[i];
122 foreach (List<NotificationEvent> EventsList
in ByCategory.Values)
126 if (Evt is T TypedEvent && Predicate(TypedEvent))
133 if (MatchingEvent is not
null)
136 if (MatchingEvent is not
null)
141 if (MatchingEvent is not
null)
147 MainThread.BeginInvokeOnMainThread(async () =>
151 await MatchingEvent.Open();
164 this.expected.AddLast(
new ExpectedEvent(
182 DateTime Now = DateTime.Now;
183 bool IsExpected =
false;
187 LinkedListNode<ExpectedEvent>? Node = this.expected.First;
188 while (Node is not
null)
190 LinkedListNode<ExpectedEvent>? Next = Node.Next;
192 if (Node.Value.Before < Now)
194 this.expected.Remove(Node);
196 else if (Node.Value.EventType ==
Event.GetType() &&
197 (Node.Value.Predicate is
null || Node.Value.Predicate(
Event)))
199 this.expected.Remove(Node);
209 MainThread.BeginInvokeOnMainThread(async () =>
226 if (Type >= 0 && Type < nrTypes)
230 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> ByCategory = this.events[Type];
231 if (!ByCategory.TryGetValue(
Event.Category, out List<NotificationEvent>? Events))
233 Events =
new List<NotificationEvent>();
234 ByCategory[
Event.Category] = Events;
243 Task
_ = Task.Run(async () =>
247 await
Event.Prepare();
265 int TypeIndex = (int)Type;
267 if (TypeIndex >= 0 && TypeIndex < nrTypes)
273 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> ByCategory = this.events[TypeIndex];
275 if (!ByCategory.TryGetValue(Category, out List<NotificationEvent>? Events))
278 ToDelete = [.. Events];
279 ByCategory.Remove(Category);
282 await this.DoDeleteEvents(ToDelete);
299 if (TypeIndex >= 0 && TypeIndex < nrTypes)
303 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> ByCategory = this.events[TypeIndex];
305 if (ByCategory.TryGetValue(
Event.Category, out List<NotificationEvent>? List) &&
306 List.Remove(
Event) &&
309 ByCategory.Remove(
Event.Category);
316 return this.DoDeleteEvents(Events);
333 catch (KeyNotFoundException)
348 ServiceRef.LogService.LogException(ex);
360 if (i < 0 || i >= nrTypes)
365 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> ByCategory = this.events[i];
366 List<NotificationEvent> Result = [];
368 foreach (List<NotificationEvent> Events
in ByCategory.Values)
369 Result.AddRange(Events);
383 if (i < 0 || i >= nrTypes)
388 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> ByCategory = this.events[i];
389 List<CaseInsensitiveString> Result = [.. ByCategory.Keys];
403 if (i < 0 || i >= nrTypes)
408 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> ByCategory = this.events[i];
409 SortedDictionary<CaseInsensitiveString, NotificationEvent[]> Result = [];
412 Result[P.Key] = [.. P.Value];
427 if (i < 0 || i >= nrTypes)
432 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> ByCategory = this.events[i];
433 SortedDictionary<CaseInsensitiveString, T[]> Result = [];
437 List<T>? Items =
null;
441 if (
Event is T TypedItem)
444 Items.Add(TypedItem);
448 if (Items is not
null)
449 Result[P.Key] = [.. Items];
467 if (i < 0 || i >= nrTypes)
475 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> ByCategory = this.events[i];
477 if (!ByCategory.TryGetValue(Category, out List<NotificationEvent>? Events2))
483 Events = [.. Events2];
494 List<NotificationEvent> AllEvents = [];
502 foreach (List<NotificationEvent> EventsList
in ByCategory.Values)
504 AllEvents.AddRange(EventsList);
509 return [.. AllEvents];
543 private int Count(
int Index)
547 SortedDictionary<CaseInsensitiveString, List<NotificationEvent>> Events = this.events[Index];
550 foreach (List<NotificationEvent> List
in Events.Values)
551 Result += List.Count;
563 List<NotificationEvent>? Resolved =
null;
583 if (Resolved is not
null)
SortedDictionary< CaseInsensitiveString, T[]> GetEventsByCategory< T >(NotificationEventType Type)
Gets available notification events for a button, sorted by category.
NotificationEvent[] GetEvents(NotificationEventType Type)
Gets available notification events for a button.
int NrNotificationsThings
Number of notifications but button Things
async Task NewEvent(NotificationEvent Event)
Registers a new event and notifies the user.
NotificationService()
Notification service
int NrNotificationsContracts
Number of notifications but button Contracts
void ExpectEvent< T >(DateTime Before, Predicate< T > Predicate)
Registers a type of notification as expected.
int NrNotificationsWallet
Number of notifications but button Wallet
EventHandlerAsync< NotificationEventsArgs >? OnNotificationsDeleted
Event raised when notifications have been deleted.
int NrNotificationsContacts
Number of notifications but button Contacts
override async Task Load(bool isResuming, CancellationToken cancellationToken)
Loads the specified service.
SortedDictionary< CaseInsensitiveString, NotificationEvent[]> GetEventsByCategory(NotificationEventType Type)
Gets available notification events for a button, sorted by category.
bool TryGetNotificationEvents(NotificationEventType Type, CaseInsensitiveString Category, [NotNullWhen(true)] out NotificationEvent[]? Events)
Tries to get available notification events.
CaseInsensitiveString[] GetCategories(NotificationEventType Type)
Gets available categories for a button.
EventHandlerAsync< NotificationEventArgs >? OnNewNotification
Event raised when a new notification has been logged.
async Task DeleteEvents(NotificationEventType Type, CaseInsensitiveString Category)
Deletes events for a given button and category.
Task DeleteEvents(params NotificationEvent[] Events)
Deletes a specified set of events.
NotificationEvent[] GetAllEvents()
Gets all notification events across all types and categories.
async Task DeleteResolvedEvents(IEventResolver Resolver)
Deletes pending events that have already been resolved.
Base class that references services in the app.
static ILogService LogService
Log service.
Class representing an event.
EventType Type
Type of event.
Static class managing the application event log. Applications and services log events on this static ...
static void Debug(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a debug event.
Represents a case-insensitive string.
static bool IsNullOrEmpty(CaseInsensitiveString value)
Indicates whether the specified string is null or an CaseInsensitiveString.Empty string.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task EndBulk()
Ends bulk-processing of data. Must be called once for every call to StartBulk.
static Task StartBulk()
Starts bulk-proccessing of data. Must be followed by a call to EndBulk.
static async Task Delete(object Object)
Deletes an object in the database.
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
static async Task Clear(string CollectionName)
Clears a collection of all objects.
Interface for event resolvers. Such can be used to resolve multiple pending notifications at once.
bool Resolves(NotificationEvent Event)
If the resolver resolves an event.
Interface for push notification services.
abstract class NotificationEvent()
Abstract base class of notification events.
class NotificationEventsArgs(NotificationEvent[] Events)
Event argument for notification events.
class NotificationEventArgs(NotificationEvent Event)
Event argument for notification events.
NotificationEventType
Button on which event is to be displayed.