Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
MyContractsViewModel.cs
12using System.Collections.ObjectModel;
13using CommunityToolkit.Mvvm.ComponentModel;
15using Microsoft.Maui.Controls.Shapes;
17
19{
23 public partial class MyContractsViewModel : BaseViewModel
24 {
25 private readonly Dictionary<string, Contract> contractsMap = [];
26 private readonly ContractsListMode contractsListMode;
27 private readonly TaskCompletionSource<Contract?>? selection;
28 private Contract? selectedContract = null;
29
35 {
36 this.IsBusy = true;
37 this.Action = SelectContractAction.ViewContract;
38
39 if (Args is not null)
40 {
41 this.contractsListMode = Args.Mode;
42 this.Action = Args.Action;
43 this.selection = Args.Selection;
44
45 switch (this.contractsListMode)
46 {
47 case ContractsListMode.Contracts:
48 this.Title = ServiceRef.Localizer[nameof(AppResources.Contracts)];
49 this.Description = ServiceRef.Localizer[nameof(AppResources.ContractsInfoText)];
50 break;
51
52 case ContractsListMode.ContractTemplates:
53 this.Title = ServiceRef.Localizer[nameof(AppResources.ContractTemplates)];
54 this.Description = ServiceRef.Localizer[nameof(AppResources.ContractTemplatesInfoText)];
55 break;
56
57 case ContractsListMode.TokenCreationTemplates:
58 this.Title = ServiceRef.Localizer[nameof(AppResources.TokenCreationTemplates)];
59 this.Description = ServiceRef.Localizer[nameof(AppResources.TokenCreationTemplatesInfoText)];
60 break;
61 }
62 }
63 }
64
66 protected override async Task OnInitialize()
67 {
68 await base.OnInitialize();
69
70 this.IsBusy = true;
71 this.ShowContractsMissing = false;
72
73 await this.LoadContracts();
74
75 ServiceRef.NotificationService.OnNewNotification += this.NotificationService_OnNewNotification;
76 ServiceRef.NotificationService.OnNotificationsDeleted += this.NotificationService_OnNotificationsDeleted;
77 }
78
80 protected override async Task OnAppearing()
81 {
82 await base.OnAppearing();
83
84 if (this.selection is not null && this.selection.Task.IsCompleted)
85 {
86 await this.GoBack();
87 return;
88 }
89 }
90
92 protected override async Task OnDispose()
93 {
94 ServiceRef.NotificationService.OnNewNotification -= this.NotificationService_OnNewNotification;
95 ServiceRef.NotificationService.OnNotificationsDeleted -= this.NotificationService_OnNotificationsDeleted;
96
97 if (this.Action != SelectContractAction.Select)
98 {
99 this.ShowContractsMissing = false;
100 this.contractsMap.Clear();
101 }
102
103 this.selection?.TrySetResult(this.selectedContract);
104
105 await base.OnDispose();
106 }
107
111 [ObservableProperty]
112 private string? title;
113
117 [ObservableProperty]
118 private string? description;
119
123 [ObservableProperty]
124 private SelectContractAction action;
125
129 [ObservableProperty]
130 private bool showContractsMissing;
131
135 public ObservableCollection<IUniqueItem> Categories { get; } = [];
136
140 public void AddOrRemoveContracts(HeaderModel Category, bool Expanded)
141 {
142 MainThread.BeginInvokeOnMainThread(() =>
143 {
144 if (Expanded)
145 {
146 int Index = this.Categories.IndexOf(Category);
147
148 foreach (ContractModel Contract in Category.Contracts)
149 this.Categories.Insert(++Index, Contract);
150 }
151 else
152 {
153 foreach (ContractModel Contract in Category.Contracts)
154 this.Categories.Remove(Contract);
155 }
156 });
157 }
161 public void ContractSelected(string ContractId)
162 {
163 MainThread.BeginInvokeOnMainThread(async () =>
164 {
165 if (this.contractsMap.TryGetValue(ContractId, out Contract? Contract))
166 {
167 switch (this.Action)
168 {
169 case SelectContractAction.ViewContract:
170 if (this.contractsListMode == ContractsListMode.Contracts)
171 {
172 try
173 {
174 Contract updatedContract = await ServiceRef.XmppService.GetContract(ContractId);
175 ViewContractNavigationArgs Args = new(updatedContract, false);
176 await ServiceRef.UiService.GoToAsync(nameof(ViewContractPage), Args, BackMethod.Pop);
177 }
178 catch (ItemNotFoundException)
179 {
180 if(await ServiceRef.UiService.DisplayAlert(
181 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)], ServiceRef.Localizer[nameof(AppResources.ContractCouldNotBeFound)],
182 ServiceRef.Localizer[nameof(AppResources.Yes)],
183 ServiceRef.Localizer[nameof(AppResources.No)]))
184 {
185 await Database.FindDelete<ContractReference>(new FilterFieldEqualTo("ContractId", ContractId));
186 await this.LoadContracts();
187 }
188 }
189 catch (Exception ex)
190 {
191 ServiceRef.LogService.LogException(ex);
192 await ServiceRef.UiService.DisplayAlert(
193 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)], ex.Message,
194 ServiceRef.Localizer[nameof(AppResources.Ok)]);
195 }
196 }
197 else
198 {
199 await ServiceRef.ContractOrchestratorService.OpenContract(ContractId, ServiceRef.Localizer[nameof(AppResources.ReferencedID)], null);
200 //NewContractNavigationArgs Args = new(Contract, null);
201 //await ServiceRef.UiService.GoToAsync(nameof(NewContractPage), Args, BackMethod.CurrentPage);
202 }
203 break;
204
205 case SelectContractAction.Select:
206 this.selectedContract = Contract;
207 await this.GoBack();
208 this.selection?.TrySetResult(Contract);
209 break;
210 }
211 }
212 });
213 }
214
215 private async Task LoadContracts()
216 {
217 try
218 {
219 IEnumerable<ContractReference> ContractReferences;
220 bool ShowAdditionalEvents;
222
223 switch (this.contractsListMode)
224 {
225 case ContractsListMode.Contracts:
226 ContractReferences = await Database.Find<ContractReference>(new FilterAnd(
227 new FilterFieldEqualTo("IsTemplate", false),
228 new FilterFieldEqualTo("ContractLoaded", true)));
229
230 ShowAdditionalEvents = true;
231 break;
232
233 case ContractsListMode.ContractTemplates:
234 ContractReferences = await Database.Find<ContractReference>(new FilterAnd(
235 new FilterFieldEqualTo("IsTemplate", true),
236 new FilterFieldEqualTo("ContractLoaded", true)));
237
238 ShowAdditionalEvents = false;
239 break;
240
241 case ContractsListMode.TokenCreationTemplates:
242 ContractReferences = await Database.Find<ContractReference>(new FilterAnd(
243 new FilterFieldEqualTo("IsTemplate", true),
244 new FilterFieldEqualTo("ContractLoaded", true)));
245
246 Dictionary<CaseInsensitiveString, bool> ContractIds = [];
247 LinkedList<ContractReference> TokenCreationTemplates = [];
248
249 foreach (ContractReference Ref in ContractReferences)
250 {
251 if (Ref.IsTokenCreationTemplate && Ref.ContractId is not null)
252 {
253 ContractIds[Ref.ContractId] = true;
254 TokenCreationTemplates.AddLast(Ref);
255 }
256 }
257
258 foreach (string TokenTemplateId in Constants.ContractTemplates.TokenCreationTemplates)
259 {
260 if (!ContractIds.ContainsKey(TokenTemplateId))
261 {
262 Contract = await ServiceRef.XmppService.GetContract(TokenTemplateId);
263 if (Contract is not null)
264 {
265 ContractReference Ref = new()
266 {
267 ContractId = Contract.ContractId
268 };
269
270 await Ref.SetContract(Contract);
271 await Database.Insert(Ref);
272
273 ServiceRef.TagProfile.CheckContractReference(Ref);
274
276 {
277 ContractIds[Ref.ContractId] = true;
278 TokenCreationTemplates.AddLast(Ref);
279 }
280 }
281 }
282 }
283
284 ContractReferences = TokenCreationTemplates;
285 ShowAdditionalEvents = false;
286 break;
287
288 default:
289 return;
290 }
291
292 SortedDictionary<string, List<ContractModel>> ContractsByCategory = new(StringComparer.CurrentCultureIgnoreCase);
293 SortedDictionary<CaseInsensitiveString, NotificationEvent[]> EventsByCategory = ServiceRef.NotificationService.GetEventsByCategory(NotificationEventType.Contracts);
294 bool Found = false;
295
296 foreach (ContractReference Ref in ContractReferences)
297 {
298 if (Ref.ContractId is null)
299 continue;
300
301 Found = true;
302
303 try
304 {
305 Contract = await Ref.GetContract();
306 if (Contract is null)
307 continue;
308 }
309 catch (Exception ex)
310 {
311 ServiceRef.LogService.LogException(ex);
312 continue;
313 }
314
315 this.contractsMap[Ref.ContractId] = Contract;
316
317 if (EventsByCategory.TryGetValue(Ref.ContractId, out NotificationEvent[]? Events))
318 {
319 EventsByCategory.Remove(Ref.ContractId);
320
321 List<NotificationEvent> Events2 = [];
322 List<NotificationEvent>? Petitions = null;
323
324 foreach (NotificationEvent Event in Events)
325 {
326 if (Event is ContractPetitionNotificationEvent Petition)
327 {
328 Petitions ??= [];
329 Petitions.Add(Petition);
330 }
331 else
332 Events2.Add(Event);
333 }
334
335 if (Petitions is not null)
336 EventsByCategory[Ref.ContractId] = [.. Petitions];
337
338 Events = [.. Events2];
339 }
340 else
341 Events = [];
342
343 ContractModel Item = await ContractModel.Create(Ref.ContractId, Ref.Created, Contract, Events);
344 string Category = Item.Category;
345
346 if (!ContractsByCategory.TryGetValue(Category, out List<ContractModel>? Contracts2))
347 {
348 Contracts2 = [];
349 ContractsByCategory[Category] = Contracts2;
350 }
351
352 Contracts2.Add(Item);
353 }
354
355 List<IUniqueItem> NewCategories = [];
356
357 if (ShowAdditionalEvents)
358 {
359 foreach (KeyValuePair<CaseInsensitiveString, NotificationEvent[]> P in EventsByCategory)
360 {
361 foreach (NotificationEvent Event in P.Value)
362 {
363 Geometry Icon = await Event.GetCategoryIcon();
364 string Description = await Event.GetDescription();
365
366 NewCategories.Add(new EventModel(Event.Received, Icon, Description, Event));
367 }
368 }
369 }
370
371 foreach (KeyValuePair<string, List<ContractModel>> P in ContractsByCategory)
372 {
373 int Nr = 0;
374
375 foreach (ContractModel Model in P.Value)
376 Nr += Model.NrEvents;
377
378 P.Value.Sort(new DateTimeDesc());
379 NewCategories.Add(new HeaderModel(P.Key, P.Value.ToArray(), Nr));
380 }
381
382 MainThread.BeginInvokeOnMainThread(() =>
383 {
384 this.Categories.Clear();
385
386 foreach (IUniqueItem Item in NewCategories)
387 this.Categories.Add(Item);
388
389 this.ShowContractsMissing = !Found;
390 });
391 }
392 finally
393 {
394 this.IsBusy = false;
395 }
396 }
397
398 private class DateTimeDesc : IComparer<ContractModel>
399 {
400 public int Compare(ContractModel? x, ContractModel? y)
401 {
402 if (x is null)
403 {
404 if (y is null)
405 return 0;
406 else
407 return -1;
408 }
409 else if (y is null)
410 return 1;
411 else
412 return y.Timestamp.CompareTo(x.Timestamp);
413 }
414 }
415
416 private void NotificationService_OnNotificationsDeleted(object? Sender, NotificationEventsArgs e)
417 {
418 MainThread.BeginInvokeOnMainThread(() =>
419 {
420 foreach (NotificationEvent Event in e.Events)
421 {
422 if (Event.Type != NotificationEventType.Contracts)
423 continue;
424
425 HeaderModel? LastHeader = null;
426
427 foreach (IUniqueItem Group in this.Categories)
428 {
429 if (Group is HeaderModel Header)
430 LastHeader = Header;
431 else if (Group is ContractModel Contract && Contract.ContractId == Event.Category)
432 {
433 if (Contract.RemoveEvent(Event) && LastHeader is not null)
434 LastHeader.NrEvents--;
435
436 break;
437 }
438 }
439 }
440 });
441 }
442
443 private void NotificationService_OnNewNotification(object? Sender, NotificationEventArgs e)
444 {
445 if (e.Event.Type != NotificationEventType.Contracts)
446 return;
447
448 MainThread.BeginInvokeOnMainThread(() =>
449 {
450 HeaderModel? LastHeader = null;
451
452 foreach (IUniqueItem Group in this.Categories)
453 {
454 if (Group is HeaderModel Header)
455 LastHeader = Header;
456 else if (Group is ContractModel Contract && Contract.ContractId == e.Event.Category)
457 {
458 if (Contract.AddEvent(e.Event) && LastHeader is not null)
459 LastHeader.NrEvents++;
460
461 break;
462 }
463 }
464 });
465 }
466 }
467}
static readonly string[] TokenCreationTemplates
Array of contract templates for creating tokens.
Definition: Constants.cs:826
A set of never changing property constants and helpful values.
Definition: Constants.cs:7
Contains a local reference to a contract that the user has created or signed.
async Task< Contract?> GetContract()
Gets a parsed contract.
async Task SetContract(Contract Contract)
Sets a parsed contract.
bool IsTokenCreationTemplate
If the contract represents a token creation template
CaseInsensitiveString? ContractId
Contract reference
Base class that references services in the app.
Definition: ServiceRef.cs:31
static ILogService LogService
Log service.
Definition: ServiceRef.cs:91
static INotificationService NotificationService
Service for managing notifications for the user.
Definition: ServiceRef.cs:211
static ITagProfile TagProfile
TAG Profile service.
Definition: ServiceRef.cs:79
static IStringLocalizer Localizer
Localization service
Definition: ServiceRef.cs:235
static IXmppService XmppService
The XMPP service for XMPP communication.
Definition: ServiceRef.cs:67
A base class for all view models, inheriting from the BindableObject. NOTE: using this class requir...
virtual async Task GoBack()
Method called when user wants to navigate to the previous screen.
Holds navigation parameters specific to views displaying a list of contacts.
SelectContractAction Action
Action to take when a contact has been selected.
TaskCompletionSource< Contract?>? Selection
Selection source, if selecting identity.
The view model to bind to when displaying 'my' contracts.
ObservableCollection< IUniqueItem > Categories
Holds the list of contracts to display, ordered by category.
override async Task OnDispose()
Method called when the view is disposed, and will not be used more. Use this method to unregister eve...
MyContractsViewModel(MyContractsNavigationArgs? Args)
Creates an instance of the MyContractsViewModel class.
override async Task OnAppearing()
Method called when view is appearing on the screen.
void ContractSelected(string ContractId)
Add or remove the contracts from the collection
override async Task OnInitialize()
Method called when view is initialized for the first time. Use this method to implement registration ...
void AddOrRemoveContracts(HeaderModel Category, bool Expanded)
Add or remove the contracts from the collection
static async Task< ContractModel > Create(string ContractId, DateTime Timestamp, Contract Contract, NotificationEvent[] Events)
Creates an instance of the ContractModel class.
int NrEvents
Number of notification events associated with the contract.
Contains the definition of a contract
Definition: Contract.cs:22
string ContractId
Contract identity
Definition: Contract.cs:65
Represents a case-insensitive string.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
Definition: Database.cs:247
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
Definition: Database.cs:95
This filter selects objects that conform to all child-filters provided.
Definition: FilterAnd.cs:10
This filter selects objects that have a named field equal to a given value.
SortedDictionary< CaseInsensitiveString, NotificationEvent[]> GetEventsByCategory(NotificationEventType Type)
Gets available notification events for a button, sorted by category.
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.
SelectContractAction
Actions to take when a contact has been selected.
class HeaderModel(string Label)
Represents a header
Definition: HeaderModel.cs:7