Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ViewIdentityViewModel.cs
1using System.Collections.ObjectModel;
2using CommunityToolkit.Mvvm.ComponentModel;
9using Microsoft.Extensions.Localization;
10using System.Globalization;
12using CommunityToolkit.Mvvm.Input;
20
22{
23
24
26 {
27 private readonly PhotosLoader photosLoader;
28 private readonly ViewIdentityNavigationArgs? args;
29 private readonly IDispatcherTimer? timer;
30 private readonly IDispatcherTimer? qrTimer;
31
32 private LegalIdentity? identity = null;
33
34 private bool hasAppeared;
35
39 [ObservableProperty]
40 private bool shouldCelebrate = false;
41
42 [ObservableProperty]
43 private bool canAddContact = false;
44 [ObservableProperty]
45 private bool canRemoveContact = false;
46
47 [ObservableProperty]
48 private bool isThirdPartyIdentity = false;
49
50 [ObservableProperty]
51 [NotifyPropertyChangedFor(nameof(HasPersonalFields))]
52 private bool hasDomainProperty = false;
53
54 [ObservableProperty]
55 private string friendlyName = string.Empty;
56 [ObservableProperty]
57 private string subText = string.Empty;
58
59 [ObservableProperty]
60 [NotifyPropertyChangedFor(nameof(HasAge))]
61 private string ageText = string.Empty;
62 public bool HasAge => !string.IsNullOrEmpty(this.AgeText);
63
64 [ObservableProperty]
65 [NotifyPropertyChangedFor(nameof(IsApproved))]
66 private IdentityState? identityState = Waher.Networking.XMPP.Contracts.IdentityState.Created;
67
68 public bool IsApproved => this.IdentityState is not null && this.IdentityState == Waher.Networking.XMPP.Contracts.IdentityState.Approved;
69
70
71 [ObservableProperty]
72 private DateTime? expireDate = null;
73 [ObservableProperty]
74 private DateTime? issueDate = null;
75
76 [ObservableProperty]
77 private int timerSeconds = Convert.ToInt32(Constants.Timeouts.IdentityAllowedWatch.TotalSeconds);
78
79 public ObservableCollection<ObservableFieldItem> PersonalFields { get; } = [];
80 public ObservableCollection<ObservableFieldItem> OrganizationFields { get; } = [];
81 public ObservableCollection<ObservableFieldItem> TechnicalFields { get; } = [];
82 public ObservableCollection<ObservableFieldItem> OtherFields { get; } = [];
83
84 public bool HasPersonalFields => this.PersonalFields.Count > 0 && !this.HasDomainProperty;
85 public bool HasOrganizationFields => this.OrganizationFields.Count > 0;
86 public bool HasTechnicalFields => this.TechnicalFields.Count > 0;
87 public bool HasOtherFields => this.OtherFields.Count > 0;
88
89 public double SuperSafeAreaBottom => SafeArea.ResolveInsetsForMode(SafeAreaMode.Bottom).Bottom;
90
91 public ObservableTask<bool> LoadIdentityTask { get; }
92 public ObservableTask<int> LoadPhotosTask { get; }
93 public ObservableCollection<Photo> Photos { get; } = [];
94
95 public ImageSource? ProfilePhoto
96 {
97 get
98 {
99 // Look for a photo named "ProfilePhoto" (adjust property as needed)
100 Photo? Profile = this.Photos.FirstOrDefault(p => p.Attachment?.FileName.StartsWith("ProfilePhoto", StringComparison.OrdinalIgnoreCase) ?? false);
101
102 // If not found, fallback to first photo
103 return (Profile ?? this.Photos.FirstOrDefault())?.Source;
104 }
105 }
106
107 public bool HasProfilePhoto => this.ProfilePhoto is not null;
108
109 public bool HasPhotos => this.Photos.Count > 0;
110
111 public bool HasTimer => this.timer?.IsRunning ?? false;
112
113 // Get the length of the profile image side in DIPs (device independent pixels).
114 public double ProfileImageSideLength
115 {
116 get
117 {
118 // Width and Height are in pixels
119 double Width = DeviceDisplay.Current.MainDisplayInfo.Width;
120 double Height = DeviceDisplay.Current.MainDisplayInfo.Height;
121
122 // Aspect ratio (width / height)
123 double AspectRatio = Height / Width;
124
125 double Length = AspectRatio * AspectRatio * 45; // Base length adjusted by aspect ratio squared
126
127 if (Length > 250) Length = 250;
128 if (Length < 125) Length = 125;
129
130 return Length;
131 }
132 }
133
134 // Define custom field descriptors for any multi-part or special properties for example BDAY BMONTH BYEAR -> B
135 private static readonly List<CustomFieldDefinition> customFields =
136 [
137 new CustomFieldDefinition
138 (
141 GetLabel: (_) => ServiceRef.Localizer[nameof(AppResources.BirthDate), false],
142 GetValue: static identity =>
143 {
144 string D = identity[Constants.XmppProperties.BirthDay];
145 string M = identity[Constants.XmppProperties.BirthMonth];
146 string y = identity[Constants.XmppProperties.BirthYear];
147 if (int.TryParse(D, out int Day) && int.TryParse(M, out int Month) && int.TryParse(y, out int Year))
148 {
149 try
150 {
151 return new DateTime(Year, Month, Day).ToString("d", CultureInfo.CurrentCulture.DateTimeFormat);
152 }
153 catch(Exception Ex)
154 {
155 ServiceRef.LogService.LogException(Ex);
156 }
157 }
158 return null;
159 }),
160 new CustomFieldDefinition(
161 Keys: Array.Empty<string>(),
163 GetLabel: _ => ServiceRef.Localizer[nameof(AppResources.NeuroID)],
164 GetValue: identity => identity.Id),
165
166 new CustomFieldDefinition(
167 Keys: Array.Empty<string>(),
169 GetLabel: _ => ServiceRef.Localizer[nameof(AppResources.Provider)],
170 GetValue: identity => identity.Provider),
171
172 new CustomFieldDefinition(
173 Keys: Array.Empty<string>(),
175 GetLabel: identity => ServiceRef.Localizer[nameof(AppResources.Status)],
176 GetValue: identity => ServiceRef.Localizer["IdentityState_" + identity.State.ToString()]),
177
178 new CustomFieldDefinition(
179 Keys: Array.Empty<string>(),
181 GetLabel: (_) => ServiceRef.Localizer[nameof(AppResources.Created)],
182 GetValue: identity => identity.Created.ToString("g", CultureInfo.CurrentCulture)),
183
184 new CustomFieldDefinition(
185 Keys: Array.Empty<string>(),
187 GetLabel: (_) => ServiceRef.Localizer[nameof(AppResources.Updated)],
188 GetValue: identity => identity.Updated.ToString("g", CultureInfo.CurrentCulture)),
189
190 new CustomFieldDefinition(
191 Keys: Array.Empty<string>(),
193 GetLabel: (_) => ServiceRef.Localizer[nameof(AppResources.Issued)],
194 GetValue: identity => identity.From.ToString("d", CultureInfo.CurrentCulture)),
195
196 new CustomFieldDefinition(
197 Keys: Array.Empty<string>(),
199 GetLabel: (_) => ServiceRef.Localizer[nameof(AppResources.Expires)],
200 GetValue: identity => identity.To.ToString("d", CultureInfo.CurrentCulture)),
201 ];
202
203 public string BannerUriLight => ServiceRef.ThemeService.GetImageUri(Constants.Branding.BannerSmallLight);
204 public string BannerUriDark => ServiceRef.ThemeService.GetImageUri(Constants.Branding.BannerSmallDark);
205
206 public string BannerUri =>
207 (Application.Current?.RequestedTheme ?? AppTheme.Light) switch
208 {
209 AppTheme.Dark => this.BannerUriDark,
210 AppTheme.Light => this.BannerUriLight,
211 _ => this.BannerUriLight
212 };
213
214
215 public ViewIdentityViewModel()
216 : base()
217 {
218 this.args = ServiceRef.NavigationService.PopLatestArgs<ViewIdentityNavigationArgs>();
219 this.photosLoader = new PhotosLoader();
220
221 this.LoadIdentityTask = new ObservableTask<bool>();
222 this.LoadPhotosTask = new ObservableTask<int>();
223
224 if (Application.Current is not null)
225 {
226 Application.Current.RequestedThemeChanged += (_, __) =>
227 {
228 this.OnPropertyChanged(nameof(this.BannerUri));
229 };
230 }
231
232 this.timer = Application.Current?.Dispatcher.CreateTimer();
233 if (this.timer is null)
234 return;
235 this.timer.Interval = TimeSpan.FromSeconds(1);
236 this.timer.Tick += this.OnTimerTick;
237
238 this.qrTimer = Application.Current?.Dispatcher.CreateTimer();
239 if (this.qrTimer is null)
240 return;
241 this.qrTimer.Interval = Constants.Intervals.Qr;
242 this.qrTimer.Tick += this.OnQrTimerTick;
243 }
244
245
246
247 public override async Task OnAppearingAsync()
248 {
249 await base.OnAppearingAsync();
250
251 bool IsRefresh = this.hasAppeared;
252 this.hasAppeared = true;
253
254 // Determine identity source
255 LegalIdentity Identity = this.args?.Identity ?? ServiceRef.TagProfile.LegalIdentity!;
256 this.identity = Identity;
257
258 if (IsRefresh)
259 {
260 // TODO: Refresh identity from server
261 // identity = await ServiceRef.XmppService.GetLegalIdentity(identity.Id);
262 ServiceRef.LogService.LogWarning("Refreshing identity...");
263 }
264
265 this.IdentityState = Identity.State;
266
267 string Domain = Identity.GetDomain();
268
269 string FullJid = Identity.GetJid();
270 string[]? Jid = null;
271
272
273 if (!string.IsNullOrEmpty(FullJid))
274 {
275 Jid = FullJid.Split('@');
276 Jid[1] = "@" + Jid[1];
277 this.FriendlyName = Jid.Length > 0 ? Jid[0] : FullJid;
278 this.SubText = Jid.Length > 1 ? Jid[1] : string.Empty;
279 }
280 else
281 {
282 this.FriendlyName = Identity.Id;
283 }
284
285 if (!string.IsNullOrEmpty(Domain))
286 {
287 this.FriendlyName = Domain;
288 this.SubText = Identity.Id;
289 this.HasDomainProperty = true;
290 }
291
292 PersonalInformation? PInfo = null;
293 try
294 {
295 if (!this.HasDomainProperty)
296 {
297 PInfo = Identity.GetPersonalInformation();
298 }
299 }
300 catch (Exception Ex)
301 {
302 ServiceRef.LogService.LogException(Ex);
303 }
304
305 if (PInfo is not null)
306 {
307 if (!string.IsNullOrEmpty(PInfo.FullName))
308 {
309 this.FriendlyName = PInfo.FullName;
310 if (PInfo.HasBirthDate)
311 this.SubText = PInfo.BirthDate!.Value.ToShortDateString();
312 else
313 this.SubText = Jid is not null ? Jid[1] : string.Empty;
314 }
315 if (PInfo.HasBirthDate && PInfo.Age > 0)
316 this.AgeText = PInfo.Age.ToString(CultureInfo.InvariantCulture);
317 }
318
319
320 this.IssueDate = Identity.From;
321 this.ExpireDate = Identity.To;
322
323 // Load fields
324 this.LoadIdentityTask.Load(async ctx =>
325 {
327
328 List<ObservableFieldItem> PersonalList = new();
329 List<ObservableFieldItem> OrganizationList = new();
330 List<ObservableFieldItem> TechnicalList = new();
331 List<ObservableFieldItem> OtherList = new();
332
333 foreach (IdentitySummaryFormatter.DisplayField F in Groups.Personal)
334 PersonalList.Add(new ObservableFieldItem(F.Key, new LocalizedString(F.Label, F.Label), Identity, F.IsReviewable, F.Value));
335 foreach (IdentitySummaryFormatter.DisplayField F in Groups.Organization)
336 OrganizationList.Add(new ObservableFieldItem(F.Key, new LocalizedString(F.Label, F.Label), Identity, F.IsReviewable, F.Value));
337 foreach (IdentitySummaryFormatter.DisplayField F in Groups.Technical)
338 TechnicalList.Add(new ObservableFieldItem(F.Key, new LocalizedString(F.Label, F.Label), Identity, F.IsReviewable, F.Value));
339 foreach (IdentitySummaryFormatter.DisplayField F in Groups.Other)
340 OtherList.Add(new ObservableFieldItem(F.Key, new LocalizedString(F.Label, F.Label), Identity, F.IsReviewable, F.Value));
341
342 bool ShouldCelebrate = PersonalList.Any(Item => Item.Key == Constants.CustomXmppProperties.BirthDate &&
343 !string.IsNullOrEmpty(Item.Value) &&
344 DateTime.TryParse(Item.Value, out DateTime BirthDate) &&
345 BirthDate == DateTime.Today);
346
347 // Check if we can add or remove contact and update contact info
348 bool CanAddContact = false;
349 bool CanRemoveContact = false;
350 bool IsThirdPartyIdentity = false;
351
352 string MyJid = ServiceRef.TagProfile.Account + "@" + ServiceRef.TagProfile.Domain;
353 string Jid = this.identity.GetJid();
354 if (!Jid.Equals(MyJid, StringComparison.OrdinalIgnoreCase))
355 {
356 try
357 {
358 ContactInfo? Info = await ContactInfo.FindByBareJid(Jid);
359 if ((Info is not null) &&
360 (Info.LegalIdentity is null ||
361 (Info.LegalId != this.identity.Id &&
362 Info.LegalIdentity.Created < this.identity!.Created &&
363 this.identity.State == Waher.Networking.XMPP.Contracts.IdentityState.Approved)))
364 {
365 Info.LegalId = this.identity.Id;
366 Info.LegalIdentity = this.identity;
367 Info.FriendlyName = ContactInfo.GetFriendlyName(this.identity);
368
369 await Database.Update(Info);
370 await Database.Provider.Flush();
371 }
372
373 CanAddContact = Info is null;
374 CanRemoveContact = Info is not null;
375
376 IsThirdPartyIdentity = true;
377 }
378 catch (Exception Ex)
379 {
380 ServiceRef.LogService.LogException(Ex);
381 }
382
383 }
384
385 // Apply to UI on main thread
386 await MainThread.InvokeOnMainThreadAsync(async () =>
387 {
388 this.PersonalFields.Clear(); PersonalList.ForEach(this.PersonalFields.Add);
389 await Task.Yield(); // Sacrifice performance for UI responsiveness. In the future, we might encounter identities with a ridiculous amount of fields.
390 this.OrganizationFields.Clear(); OrganizationList.ForEach(this.OrganizationFields.Add);
391 await Task.Yield();
392 this.TechnicalFields.Clear(); TechnicalList.ForEach(this.TechnicalFields.Add);
393 await Task.Yield();
394 this.OtherFields.Clear(); OtherList.ForEach(this.OtherFields.Add);
395
396 this.ShouldCelebrate = ShouldCelebrate;
397 this.CanAddContact = CanAddContact;
398 this.CanRemoveContact = CanRemoveContact;
399
400 this.IsThirdPartyIdentity = IsThirdPartyIdentity;
401
402 this.OnPropertyChanged(nameof(this.HasPersonalFields));
403 this.OnPropertyChanged(nameof(this.HasOrganizationFields));
404 this.OnPropertyChanged(nameof(this.HasTechnicalFields));
405 this.OnPropertyChanged(nameof(this.HasOtherFields));
406 this.OnPropertyChanged(nameof(this.HasAge));
407
408
409 this.timer?.Start();
410 this.OnPropertyChanged(nameof(this.HasTimer));
411
412 this.OnQrTimerTick(this, EventArgs.Empty); // Generate the QR code for the first time
413 //this.qrTimer?.Start(); //Currently the qr is not random, so no need to set time for refresh
414
415 });
416
417 });
418
419 // Load photos
420 this.LoadPhotosTask.Load(async ctx =>
421 {
422 this.photosLoader.CancelLoadPhotos();
423
424 List<Photo> Buffer = [];
425 Attachment[] Atts = Identity.Attachments ?? [];
426 string[] AllowedContentTypes = new[]
427 {
430 };
431
432 for (int Index = 0; Index < Atts.Length; Index++)
433 {
434 if (!AllowedContentTypes.Contains(Atts[Index].ContentType))
435 continue;
436
437 if (ctx.CancellationToken.IsCancellationRequested)
438 break;
439
440 ctx.Progress.Report(Index * 100 / Math.Max(Atts.Length, 1));
441 (byte[]? Bin, string _, int Rot) = await this.photosLoader.LoadOnePhoto(Atts[Index], SignWith.LatestApprovedIdOrCurrentKeys);
442 if (Bin is not null)
443 Buffer.Add(new Photo(Bin, Rot, Atts[Index]));
444 }
445
446 await MainThread.InvokeOnMainThreadAsync(() =>
447 {
448 this.Photos.Clear();
449 Buffer.ForEach(this.Photos.Add);
450
451 this.OnPropertyChanged(nameof(this.ProfilePhoto));
452 this.OnPropertyChanged(nameof(this.HasProfilePhoto));
453 this.OnPropertyChanged(nameof(this.HasPhotos));
454
455 });
456
457 ctx.Progress.Report(100);
458 });
459 }
460
461 public override Task OnDisappearingAsync()
462 {
463 try
464 {
465 this.timer?.Stop();
466 }
467 catch
468 {
469 //Ignore, timer might already been stopped (not sure if it throws when already stopped)
470 }
471 return base.OnDisappearingAsync();
472 }
473
474 private void OnTimerTick(object? sender, EventArgs e)
475 {
476 MainThread.BeginInvokeOnMainThread(async () =>
477 {
478 if (this.TimerSeconds > 0)
479 {
480 this.TimerSeconds--;
481 }
482 else
483 {
484 try
485 {
486 this.timer?.Stop();
487 await this.GoBack();
488 }
489 catch (Exception Ex)
490 {
491 ServiceRef.LogService.LogException(Ex);
492 }
493 }
494 });
495 }
496
497 private void OnQrTimerTick(object? sender, EventArgs e)
498 {
499 MainThread.BeginInvokeOnMainThread(() =>
500 {
501
502 try
503 {
504 if (this.identity is null)
505 return;
506 this.GenerateQrCode(Constants.UriSchemes.CreateIdUri(this.identity.Id));
507 }
508 catch (Exception Ex)
509 {
510 ServiceRef.LogService.LogException(Ex);
511 }
512 });
513 }
514
515 [RelayCommand(AllowConcurrentExecutions = false)]
516 private async Task ImageTappedAsync(Attachment ClickedAttachment)
517 {
518 await MainThread.InvokeOnMainThreadAsync(() =>
519 {
520 this.timer?.Stop();
521 });
522
523 try
524 {
525 ImagesPopup ImagesPopup = new();
526 ImagesViewModel ImagesViewModel = new([ClickedAttachment]);
527 ImagesPopup.BindingContext = ImagesViewModel;
528 await ServiceRef.PopupService.PushAsync(ImagesPopup);
529 }
530 catch (Exception Ex)
531 {
532 ServiceRef.LogService.LogException(Ex);
533 }
534
535 MainThread.BeginInvokeOnMainThread(() =>
536 {
537 this.timer?.Start();
538 });
539 }
540
541 [RelayCommand(AllowConcurrentExecutions = false)]
542 private async Task QrTappedAsync()
543 {
544 if (this.QrCodeBin is null || string.IsNullOrEmpty(this.QrCodeUri))
545 return;
546
547 await MainThread.InvokeOnMainThreadAsync(() =>
548 {
549 this.timer?.Stop();
550 });
551
552 try
553 {
554 await Clipboard.SetTextAsync(this.QrCodeUri);
558 }
559 catch (Exception Ex)
560 {
561 ServiceRef.LogService.LogException(Ex);
562 }
563
564 MainThread.BeginInvokeOnMainThread(() =>
565 {
566 this.timer?.Start();
567 });
568 }
569
570 [RelayCommand(AllowConcurrentExecutions = false)]
571 private async Task FieldTappedAsync(string Value)
572 {
573 if (this.QrCodeBin is null || string.IsNullOrEmpty(this.QrCodeUri))
574 return;
575
576 await MainThread.InvokeOnMainThreadAsync(() =>
577 {
578 this.timer?.Stop();
579 });
580
581 try
582 {
583 await Clipboard.SetTextAsync(Value);
587 }
588 catch (Exception Ex)
589 {
590 ServiceRef.LogService.LogException(Ex);
591 }
592
593 MainThread.BeginInvokeOnMainThread(() =>
594 {
595 this.timer?.Start();
596 });
597 }
598
599 [RelayCommand(AllowConcurrentExecutions = false)]
600 private async Task ShareAsync()
601 {
602 if (this.identity is null && this.LoadIdentityTask.IsSucceeded)
603 return;
604
605 await MainThread.InvokeOnMainThreadAsync(() =>
606 {
607 this.timer?.Stop();
608 });
609
610 try
611 {
612 await this.OpenQrPopup(ServiceRef.Localizer[nameof(AppResources.PersonalId)]);
613 }
614 catch (Exception Ex)
615 {
616 ServiceRef.LogService.LogException(Ex);
617 }
618
619 MainThread.BeginInvokeOnMainThread(() =>
620 {
621 this.timer?.Start();
622 });
623
624 }
625
626 [RelayCommand(AllowConcurrentExecutions = false)]
627 private async Task RemoveContact()
628 {
629 if (this.identity is null)
630 return;
631 try
632 {
633 if (!await ServiceRef.UiService.DisplayAlert(ServiceRef.Localizer["Confirm"], ServiceRef.Localizer["AreYouSureYouWantToRemoveContact"], ServiceRef.Localizer["Yes"], ServiceRef.Localizer["Cancel"]))
634 return;
635
636 string BareJid = this.identity.GetJid();
637
638 ContactInfo Info = await ContactInfo.FindByBareJid(BareJid);
639 if (Info is not null)
640 {
641 await Database.Delete(Info);
642 await ServiceRef.AttachmentCacheService.MakeTemporary(Info.LegalId);
643 await Database.Provider.Flush();
644 }
645
646 RosterItem? Item = ServiceRef.XmppService.GetRosterItem(BareJid);
647 if (Item is not null)
648 ServiceRef.XmppService.RemoveRosterItem(BareJid);
649
650 await MainThread.InvokeOnMainThreadAsync(() =>
651 {
652 this.CanAddContact = true;
653 this.CanRemoveContact = false;
654 });
655 }
656 catch (Exception Ex)
657 {
658 ServiceRef.LogService.LogException(Ex);
659 }
660 }
661
662 [RelayCommand(AllowConcurrentExecutions = false)]
663 private async Task AddContact()
664 {
665 if (this.identity is null)
666 return;
667
668 try
669 {
670
671 string FriendlyName = ContactInfo.GetFriendlyName(this.identity);
672 string BareJid = this.identity.GetJid();
673
674 RosterItem? Item = ServiceRef.XmppService.GetRosterItem(BareJid);
675 if (Item is null)
676 ServiceRef.XmppService.AddRosterItem(new RosterItem(BareJid, FriendlyName));
677
678 ContactInfo Info = await ContactInfo.FindByBareJid(BareJid);
679 if (Info is null)
680 {
681 Info = new ContactInfo()
682 {
683 BareJid = BareJid,
684 LegalId = this.identity.Id,
685 LegalIdentity = this.identity,
686 FriendlyName = FriendlyName,
687 IsThing = false
688 };
689
690 await Database.Insert(Info);
691 }
692 else
693 {
694 Info.LegalId = this.identity.Id;
695 Info.LegalIdentity = this.identity;
696 Info.FriendlyName = FriendlyName;
697
698 await Database.Update(Info);
699 }
700 await ServiceRef.AttachmentCacheService.MakePermanent(this.identity.Id!);
701 await Database.Provider.Flush();
702
703 await MainThread.InvokeOnMainThreadAsync(() =>
704 {
705 this.CanAddContact = false;
706 this.CanRemoveContact = true;
707 });
708 }
709 catch (Exception Ex)
710 {
711 ServiceRef.LogService.LogException(Ex);
712 }
713 }
714
715 [RelayCommand(AllowConcurrentExecutions = false)]
716 private async Task OpenChat()
717 {
718 if (this.identity is null)
719 return;
720 try
721 {
722 string? Jid = this.identity.GetJid();
723 PersonalInformation? PersonalInfo = this.identity.GetPersonalInfo();
724
725 if (string.IsNullOrEmpty(Jid))
726 return;
727
728 ChatNavigationArgs ChatArgs = new(this.identity.Id, Jid, PersonalInfo.FullName);
729 await ServiceRef.NavigationService.GoToAsync(nameof(ChatPage), ChatArgs, BackMethod.Inherited, Jid);
730 }
731 catch (Exception Ex)
732 {
733 ServiceRef.LogService.LogException(Ex);
734 }
735 }
736
737 #region ILinkableView
738
743 public override Task<string> Title => Task.FromResult("Test");//Task.FromResult<string>(ContactInfo.GetFriendlyName(this.LegalIdentity!));
744
745 #endregion
746
747 // Simple holder for custom field metadata
748 private record CustomFieldDefinition(string[] Keys,
749 string NewKey,
750 Func<LegalIdentity, LocalizedString> GetLabel,
751 Func<LegalIdentity, string?> GetValue);
752 }
753}
Image identifiers for branding.
Definition: Constants.cs:1083
Custom XMPP Protocol Properties.
Definition: Constants.cs:322
const string To
“To” / expiry date
Definition: Constants.cs:361
const string State
Current state (Approved, Rejected, …)
Definition: Constants.cs:341
const string Created
When it was created
Definition: Constants.cs:346
const string Updated
When it was last updated
Definition: Constants.cs:351
const string Provider
Issuer / Provider
Definition: Constants.cs:336
static readonly TimeSpan Qr
Qr interval
Definition: Constants.cs:676
static readonly TimeSpan IdentityAllowedWatch
Allowed time to watch an Identity
Definition: Constants.cs:722
static string CreateIdUri(string id)
Generates a IoT ID Uri form the specified id.
Definition: Constants.cs:252
const string BirthYear
Birth Year
Definition: Constants.cs:454
const string BirthMonth
Birth Month
Definition: Constants.cs:449
A set of never changing property constants and helpful values.
Definition: Constants.cs:24
A strongly-typed resource class, for looking up localized strings, etc.
static string BirthDate
Looks up a localized string similar to Birth Date.
static string Updated
Looks up a localized string similar to Updated.
static string Provider
Looks up a localized string similar to Provider.
static string Issued
Looks up a localized string similar to Issued.
static string Status
Looks up a localized string similar to Status.
static string IdCopiedSuccessfully
Looks up a localized string similar to A link to the ID was copied to the clipboard....
static string TagValueCopiedToClipboard
Looks up a localized string similar to Tag value copied to clipboard.
static string PersonalId
Looks up a localized string similar to Personal ID.
static string Expires
Looks up a localized string similar to Expires.
static string Created
Looks up a localized string similar to Created.
static string SuccessTitle
Looks up a localized string similar to Success.
static string NeuroID
Looks up a localized string similar to Neuro-ID.
Contains information about a contact.
Definition: ContactInfo.cs:22
static async Task< string > GetFriendlyName(CaseInsensitiveString RemoteId)
Gets the friendly name of a remote identity (Legal ID or Bare JID).
Definition: ContactInfo.cs:258
static Task< ContactInfo > FindByBareJid(string BareJid)
Finds information about a contact, given its Bare JID.
Definition: ContactInfo.cs:221
CaseInsensitiveString LegalId
Legal ID of contact.
Definition: ContactInfo.cs:72
Builds friendly, localized summaries for identity-like data from mapped properties and attachments....
static IdentityGroupsResult BuildIdentityGroups(LegalIdentity Identity, CultureInfo? Culture=null)
Build grouped identity fields (Personal/Organization/Technical/Other) from a LegalIdentity....
Base class that references services in the app.
Definition: ServiceRef.cs:43
static ILogService LogService
Log service.
Definition: ServiceRef.cs:214
static IUiService UiService
Service serializing and managing UI-related tasks.
Definition: ServiceRef.cs:130
static INavigationService NavigationService
The navigation service for navigating between pages.
Definition: ServiceRef.cs:178
static IPopupService PopupService
Popup service for presenting application popups.
Definition: ServiceRef.cs:142
static IAttachmentCacheService AttachmentCacheService
AttachmentCache service.
Definition: ServiceRef.cs:274
static ITagProfile TagProfile
TAG Profile service.
Definition: ServiceRef.cs:202
static IReportingStringLocalizer Localizer
Localization service
Definition: ServiceRef.cs:370
static IXmppService XmppService
The XMPP service for XMPP communication.
Definition: ServiceRef.cs:190
Provides a data-binding friendly mechanism to manage and report the status of asynchronous operations...
virtual ? object GetValue(string PropertyName)
Gets the value of a property in the view model.
Holds navigation parameters specific to views displaying a list of contacts.
A page that displays a list of the current user's contacts.
ViewModel for a single property field of a LegalIdentity.
override async Task OnAppearingAsync()
Method called when view is appearing on the screen.
override Task OnDisappearingAsync()
Method called when view is disappearing from the screen.
A view model that holds the XMPP state.
Image encoder/decoder.
Definition: ImageCodec.cs:14
const string ContentTypeJpg
image/jpeg
Definition: ImageCodec.cs:35
const string ContentTypePng
image/png
Definition: ImageCodec.cs:30
Contains a reference to an attachment assigned to a legal object.
Definition: Attachment.cs:10
string ContentType
Internet Content Type of binary attachment.
Definition: Attachment.cs:48
Contains personal information found in a legal identity.
Maintains information about an item in the roster.
Definition: RosterItem.cs:75
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:21
static IDatabaseProvider Provider
Registered database provider.
Definition: Database.cs:59
static async Task Update(object Object)
Updates an object in the database.
Definition: Database.cs:1211
static async Task Delete(object Object)
Deletes an object in the database.
Definition: Database.cs:1291
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
Definition: Database.cs:97
Task GoToAsync(string Route)
Navigates to the specified route and pushes the page onto the navigation stack.
Task< bool > DisplayAlert(string Title, string Message, string? Accept=null, string? Cancel=null)
Displays an alert/message box to the user.
Task Flush()
Persists any pending changes.
Definition: ImplTypes.g.cs:58
class Photo(byte[] Binary, int Rotation, Attachment? Attachment)
Class containing information about a photo.
Definition: Photo.cs:10
BackMethod
Navigation Back Method
Definition: BackMethod.cs:7
IdentityState
Lists recognized legal identity states.
SignWith
Options on what keys to use when signing data.
Definition: Enumerations.cs:82
Definition: App.xaml.cs:4