Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
TokenDetailsViewModel.cs
1using CommunityToolkit.Mvvm.ComponentModel;
2using CommunityToolkit.Mvvm.Input;
15using NeuroFeatures;
18using System.Collections.ObjectModel;
19using System.ComponentModel;
20using System.Globalization;
21using System.Text;
22using System.Web;
23using System.Xml;
24using Waher.Content;
28using Waher.Security;
29
31{
38 {
39 private readonly TokenDetailsNavigationArgs? navigationArguments = Args;
40 private readonly TokenDetailsPage page = Page;
41
43 protected override async Task OnInitialize()
44 {
45 await base.OnInitialize();
46
47 if (this.navigationArguments is not null)
48 {
49 this.Created = this.navigationArguments.Token?.Created;
50 this.Updated = this.navigationArguments.Token?.Updated;
51 this.Expires = this.navigationArguments.Token?.Expires;
52 this.ArchiveRequired = this.navigationArguments.Token?.ArchiveRequired;
53 this.ArchiveOptional = this.navigationArguments.Token?.ArchiveOptional;
54 this.SignatureTimestamp = this.navigationArguments.Token?.SignatureTimestamp;
55 this.Signature = this.navigationArguments.Token?.Signature;
56 this.DefinitionSchemaDigest = this.navigationArguments.Token?.DefinitionSchemaDigest;
57 this.DefinitionSchemaHashFunction = this.navigationArguments.Token?.DefinitionSchemaHashFunction;
58 this.CreatorCanDestroy = this.navigationArguments.Token?.CreatorCanDestroy ?? false;
59 this.OwnerCanDestroyBatch = this.navigationArguments.Token?.OwnerCanDestroyBatch ?? false;
60 this.OwnerCanDestroyIndividual = this.navigationArguments.Token?.OwnerCanDestroyIndividual ?? false;
61 this.CertifierCanDestroy = this.navigationArguments.Token?.CertifierCanDestroy ?? false;
62 this.FriendlyName = this.navigationArguments.Token?.FriendlyName;
63 this.Category = this.navigationArguments.Token?.Category;
64 this.Description = this.navigationArguments.Token?.Description is null ? null : await this.navigationArguments.Token.Description.MarkdownToParsedXaml();
65 this.GlyphContentType = this.navigationArguments.Token?.GlyphContentType;
66 this.Ordinal = this.navigationArguments.Token?.Ordinal;
67 this.Value = this.navigationArguments.Token?.Value;
68 this.TokenIdMethod = this.navigationArguments.Token?.TokenIdMethod;
69 this.TokenId = this.navigationArguments.Token?.TokenId;
70 this.ShortTokenId = this.navigationArguments.Token?.ShortTokenId;
71 this.Visibility = this.navigationArguments.Token?.Visibility;
72 this.Creator = this.navigationArguments.Token?.Creator;
73 this.CreatorFriendlyName = await ContactInfo.GetFriendlyName(this.navigationArguments.Token?.Creator);
74 this.CreatorJid = this.navigationArguments.Token?.CreatorJid;
75 this.Owner = this.navigationArguments.Token?.Owner;
76 this.OwnerFriendlyName = await ContactInfo.GetFriendlyName(this.navigationArguments.Token?.Owner);
77 this.OwnerJid = this.navigationArguments.Token?.OwnerJid;
78 this.BatchSize = this.navigationArguments.Token?.BatchSize;
79 this.TrustProvider = this.navigationArguments.Token?.TrustProvider;
80 this.TrustProviderFriendlyName = await ContactInfo.GetFriendlyName(this.navigationArguments.Token?.TrustProvider);
81 this.TrustProviderJid = this.navigationArguments.Token?.TrustProviderJid;
82 this.Currency = this.navigationArguments.Token?.Currency;
83 this.Reference = this.navigationArguments.Token?.Reference;
84 this.Definition = this.navigationArguments.Token?.Definition;
85 this.DefinitionNamespace = this.navigationArguments.Token?.DefinitionNamespace;
86 this.CreationContract = this.navigationArguments.Token?.CreationContract;
87 this.OwnershipContract = this.navigationArguments.Token?.OwnershipContract;
88 this.GlyphImage = this.navigationArguments.Token?.GlyphImage;
89 this.HasGlyphImage = this.navigationArguments.Token?.HasGlyphImage ?? false;
90 this.GlyphWidth = this.navigationArguments.Token?.GlyphWidth;
91 this.GlyphHeight = this.navigationArguments.Token?.GlyphHeight;
92 this.TokenXml = this.navigationArguments.Token?.Token.ToXml();
93 this.IsMyToken = string.Equals(this.OwnerJid, ServiceRef.XmppService.BareJid, StringComparison.OrdinalIgnoreCase);
94 this.HasStateMachine = this.navigationArguments.Token?.HasStateMachine ?? false;
95
96 if (!string.IsNullOrEmpty(this.navigationArguments.Token?.Reference))
97 {
98 if (Uri.TryCreate(this.navigationArguments.Token?.Reference, UriKind.Absolute, out Uri? RefUri) &&
99 RefUri.Scheme.ToLower(CultureInfo.InvariantCulture) is string s &&
100 (s == "http" || s == "https"))
101 {
102 this.page.AddLink(this, ServiceRef.Localizer[nameof(AppResources.Reference)], s); // TODO: Replace with grouped collection, when this works in Maui.
103 }
104 }
105
106 if (this.navigationArguments.Token?.Tags is not null)
107 {
108 foreach (TokenTag Tag in this.navigationArguments.Token.Tags)
109 this.page.AddLink(this, Tag.Name, Tag.Value?.ToString() ?? string.Empty); // TODO: Replace with grouped collection, when this works in Maui.
110 }
111
112 if (this.TokenId is not null)
113 this.GenerateQrCode(Constants.UriSchemes.CreateTokenUri(this.TokenId));
114
115 await this.Populate(ServiceRef.Localizer[nameof(AppResources.Witness)], string.Empty, this.navigationArguments.Token?.Witness, null, this.Witnesses);
116 await this.Populate(ServiceRef.Localizer[nameof(AppResources.Certifier)], ServiceRef.Localizer[nameof(AppResources.CertifierJid)], this.navigationArguments.Token?.Certifier, this.navigationArguments.Token?.CertifierJids, this.Certifiers);
117 await this.Populate(ServiceRef.Localizer[nameof(AppResources.Valuator)], string.Empty, this.navigationArguments.Token?.Valuator, null, this.Valuators);
118 await this.Populate(ServiceRef.Localizer[nameof(AppResources.Assessor)], string.Empty, this.navigationArguments.Token?.Assessor, null, this.Assessors);
119
120 this.Tags.Clear();
121
122 if (this.navigationArguments.Token?.Tags is not null)
123 {
124 foreach (TokenTag Tag in this.navigationArguments.Token.Tags)
125 this.Tags.Add(Tag);
126 }
127
128 StringBuilder sb = new();
129 string Domain = this.TokenId?.After("@") ?? string.Empty;
130 Domain = Domain.After("."); // Remove last sub-domain, corresponding to the component hosting the token.
131
132 sb.Append("https://");
133 sb.Append(Domain);
134 sb.Append("/ValidationSchema.md?NS=");
135 sb.Append(HttpUtility.UrlEncode(this.DefinitionNamespace));
136 sb.Append("&H=");
137
138 if (this.DefinitionSchemaDigest is not null)
139 sb.Append(HttpUtility.UrlEncode(Convert.ToBase64String(this.DefinitionSchemaDigest)));
140
141 sb.Append("&Download=1");
142
143 this.DefinitionSchemaUrl = sb.ToString(); // TODO: The above assume contract hosted by the TAG Neuron. URL should be retrieved using API, or be standardized.
144 }
145 }
146
147 private async Task Populate(string LegalIdLabel, string JidLabel, string[]? LegalIds, string[]? Jids, ObservableCollection<PartItem> Parts)
148 {
149 int i, c = LegalIds?.Length ?? 0;
150 int d = Jids?.Length ?? 0;
151 string FriendlyName;
152 string Jid;
153
154 Parts.Clear();
155
156 for (i = 0; i < c; i++)
157 {
158 FriendlyName = await ContactInfo.GetFriendlyName(LegalIds![i]);
159 Jid = i < d ? (Jids![i] ?? string.Empty) : string.Empty;
160
161 Parts.Add(new PartItem(LegalIds[i], Jid, FriendlyName));
162
163 this.page.AddLegalId(this, LegalIdLabel, FriendlyName, LegalIds[i]); // TODO: Replace with grouped collection, when this works in Maui.
164
165 if (!string.IsNullOrEmpty(Jid))
166 this.page.AddJid(this, JidLabel, Jid, LegalIds[i], FriendlyName); // TODO: Replace with grouped collection, when this works in Maui.
167 }
168 }
169
173 [ObservableProperty]
174 private string? definitionSchemaUrl;
175
176 #region Properties
177
181 public ObservableCollection<PartItem> Certifiers { get; } = [];
182
186 public ObservableCollection<PartItem> Valuators { get; } = [];
187
191 public ObservableCollection<PartItem> Assessors { get; } = [];
192
196 public ObservableCollection<PartItem> Witnesses { get; } = [];
197
201 public ObservableCollection<TokenTag> Tags { get; } = [];
202
206 [ObservableProperty]
207 private DateTime? created;
208
212 [ObservableProperty]
213 private DateTime? updated;
214
218 [ObservableProperty]
219 private DateTime? expires;
220
224 [ObservableProperty]
225 private Duration? archiveRequired;
226
230 [ObservableProperty]
231 private Duration? archiveOptional;
232
236 [ObservableProperty]
237 private DateTime? signatureTimestamp;
238
242 [ObservableProperty]
243 private byte[]? signature;
244
248 [ObservableProperty]
249 private byte[]? definitionSchemaDigest;
250
254 [ObservableProperty]
255 private HashFunction? definitionSchemaHashFunction;
256
260 [ObservableProperty]
261 private bool creatorCanDestroy;
262
266 [ObservableProperty]
267 private bool ownerCanDestroyBatch;
268
272 [ObservableProperty]
273 private bool ownerCanDestroyIndividual;
274
278 [ObservableProperty]
279 private bool certifierCanDestroy;
280
284 [ObservableProperty]
285 private string? friendlyName;
286
290 [ObservableProperty]
291 private string? category;
292
296 [ObservableProperty]
297 private object? description;
298
302 [ObservableProperty]
303 private string? glyphContentType;
304
308 [ObservableProperty]
309 private int? ordinal;
310
314 [ObservableProperty]
315 private decimal? value;
316
320 [ObservableProperty]
321 private TokenIdMethod? tokenIdMethod;
322
326 [ObservableProperty]
327 private string? tokenId;
328
332 [ObservableProperty]
333 private string? shortTokenId;
334
336 protected override void OnPropertyChanged(PropertyChangedEventArgs e)
337 {
338 base.OnPropertyChanged(e);
339
340 switch (e.PropertyName)
341 {
342 case nameof(this.ShortTokenId):
343 this.HasShortTokenId = !string.IsNullOrEmpty(this.ShortTokenId);
344 break;
345 }
346 }
347
351 [ObservableProperty]
352 private bool hasShortTokenId;
353
357 [ObservableProperty]
358 private string? tokenXml;
359
363 [ObservableProperty]
364 private ContractVisibility? visibility;
365
369 [ObservableProperty]
370 private string? creator;
371
375 [ObservableProperty]
376 private string? creatorFriendlyName;
377
381 [ObservableProperty]
382 private string? creatorJid;
383
387 [ObservableProperty]
388 private string? owner;
389
393 [ObservableProperty]
394 private string? ownerFriendlyName;
395
399 [ObservableProperty]
400 private string? ownerJid;
401
405 [ObservableProperty]
406 private int? batchSize;
407
411 [ObservableProperty]
412 private string? trustProvider;
413
417 [ObservableProperty]
418 private string? trustProviderFriendlyName;
419
423 [ObservableProperty]
424 private string? trustProviderJid;
425
429 [ObservableProperty]
430 private string? currency;
431
435 [ObservableProperty]
436 private string? reference;
437
441 [ObservableProperty]
442 private string? definition;
443
447 [ObservableProperty]
448 private string? definitionNamespace;
449
453 [ObservableProperty]
454 private string? creationContract;
455
459 [ObservableProperty]
460 private string? ownershipContract;
461
465 [ObservableProperty]
466 private ImageSource? glyphImage;
467
471 [ObservableProperty]
472 private bool hasGlyphImage;
473
477 [ObservableProperty]
478 private int? glyphWidth;
479
483 [ObservableProperty]
484 private int? glyphHeight;
485
489 [ObservableProperty]
490 private bool isMyToken;
491
495 [ObservableProperty]
496 private bool hasStateMachine;
497
498 #endregion
499
500 #region Commands
501
505 [RelayCommand]
506 public static async Task CopyToClipboard(object Parameter)
507 {
508 try
509 {
510 string s = Parameter?.ToString() ?? string.Empty;
511 int i = s.IndexOf('@');
512
513 if (i > 0 && Guid.TryParse(s[..i], out _))
514 {
515 await Clipboard.SetTextAsync(Constants.UriSchemes.NeuroFeature + ":" + s);
516 await ServiceRef.UiService.DisplayAlert(ServiceRef.Localizer[nameof(AppResources.SuccessTitle)],
517 ServiceRef.Localizer[nameof(AppResources.IdCopiedSuccessfully)]);
518 }
519 else
520 {
521 await Clipboard.SetTextAsync(s);
522 await ServiceRef.UiService.DisplayAlert(ServiceRef.Localizer[nameof(AppResources.SuccessTitle)],
523 ServiceRef.Localizer[nameof(AppResources.TagValueCopiedToClipboard)]);
524 }
525 }
526 catch (Exception ex)
527 {
528 ServiceRef.LogService.LogException(ex);
530 }
531 }
532
536 [RelayCommand]
537 private static async Task ViewId(object Parameter)
538 {
539 string? LegalId = Parameter?.ToString();
540 if (string.IsNullOrEmpty(LegalId))
541 return;
542
543 try
544 {
545 await ServiceRef.ContractOrchestratorService.OpenLegalIdentity(LegalId, ServiceRef.Localizer[nameof(AppResources.PurposeReviewToken)]);
546 }
547 catch (Exception ex)
548 {
550 }
551 }
552
556 [RelayCommand]
557 private static async Task ViewContract(object Parameter)
558 {
559 string? ContractId = Parameter?.ToString();
560 if (string.IsNullOrEmpty(ContractId))
561 return;
562
563 try
564 {
565 await ServiceRef.ContractOrchestratorService.OpenContract(ContractId, ServiceRef.Localizer[nameof(AppResources.PurposeReviewToken)], null);
566 }
567 catch (Exception ex)
568 {
570 }
571 }
572
576 [RelayCommand]
577 private async Task OpenChat(object Parameter)
578 {
579 string? s = Parameter?.ToString();
580 if (string.IsNullOrEmpty(s))
581 return;
582
583 string? BareJid;
584 string? LegalId;
585 string? FriendlyName;
586
587 switch (s)
588 {
589 case "Owner":
590 BareJid = this.OwnerJid;
591 LegalId = this.Owner;
592 FriendlyName = this.OwnerFriendlyName;
593 break;
594
595 case "Creator":
596 BareJid = this.CreatorJid;
597 LegalId = this.Creator;
598 FriendlyName = this.CreatorFriendlyName;
599 break;
600
601 case "TrustProvider":
602 BareJid = this.TrustProviderJid;
603 LegalId = this.TrustProvider;
604 FriendlyName = this.TrustProviderFriendlyName;
605 break;
606
607 default:
608 string[] Parts = s.Split(" | ");
609 if (Parts.Length != 3)
610 return;
611
612 BareJid = Parts[0];
613 LegalId = Parts[1];
614 FriendlyName = Parts[2];
615 break;
616 }
617
618 try
619 {
620 ChatNavigationArgs Args = new(LegalId, BareJid, FriendlyName);
621 await ServiceRef.UiService.GoToAsync(nameof(ChatPage), Args, BackMethod.Inherited, BareJid);
622 }
623 catch (Exception ex)
624 {
626 }
627 }
628
632 [RelayCommand]
633 private static async Task OpenLink(object Parameter)
634 {
635 if (Parameter is not null)
636 await App.OpenUrlAsync(Parameter.ToString()!);
637 }
638
642 [RelayCommand]
643 private async Task ShowM2mInfo()
644 {
645 if (this.Definition is null)
646 return;
647
648 try
649 {
650 byte[] Bin = Encoding.UTF8.GetBytes(this.Definition);
651 HttpFileUploadEventArgs e = await ServiceRef.XmppService.RequestUploadSlotAsync(this.TokenId + ".xml", "text/xml; charset=utf-8", Bin.Length);
652
653 if (e.Ok)
654 {
655 await e.PUT(Bin, "text/xml", (int)Constants.Timeouts.UploadFile.TotalMilliseconds);
656 await App.OpenUrlAsync(e.GetUrl);
657 }
658 else
659 await ServiceRef.UiService.DisplayException(e.StanzaError ?? new Exception(e.ErrorText));
660 }
661 catch (Exception ex)
662 {
664 }
665 }
666
670 [RelayCommand]
671 private async Task SendToContact()
672 {
673 TaskCompletionSource<ContactInfoModel?> Selected = new();
674 ContactListNavigationArgs ContactListArgs = new(ServiceRef.Localizer[nameof(AppResources.SendInformationTo)], Selected)
675 {
676 CanScanQrCode = true,
677 };
678
679 await ServiceRef.UiService.GoToAsync(nameof(MyContactsPage), ContactListArgs, BackMethod.Pop);
680
681 ContactInfoModel? Contact = await Selected.Task;
682 if (Contact is null)
683 return;
684
685 StringBuilder Markdown = new();
686
687 Markdown.Append("```");
688 Markdown.AppendLine(Constants.UriSchemes.NeuroFeature);
689 Markdown.AppendLine(this.TokenXml);
690 Markdown.AppendLine("```");
691
692 await ChatViewModel.ExecuteSendMessage(string.Empty, Markdown.ToString(), Contact.BareJid);
693
694 if (Contact.Contact is not null)
695 {
696 await Task.Delay(100); // Otherwise, page doesn't show properly. (Underlying timing issue. TODO: Find better solution.)
697
698 ChatNavigationArgs ChatArgs = new(Contact.Contact);
699 await ServiceRef.UiService.GoToAsync(nameof(ChatPage), ChatArgs, BackMethod.Inherited, Contact.BareJid);
700 }
701 }
702
706 [RelayCommand]
707 private async Task Share()
708 {
709 try
710 {
711 if (this.QrCodeBin is null)
712 return;
713
714 string FileName = "Token.QR." + InternetContent.GetFileExtension(this.QrCodeContentType);
715
716 ServiceRef.PlatformSpecific.ShareImage(this.QrCodeBin, this.FriendlyName ?? string.Empty,
717 ServiceRef.Localizer[nameof(AppResources.Share)], FileName);
718 }
719 catch (Exception ex)
720 {
721 ServiceRef.LogService.LogException(ex);
723 }
724 }
725
729 [RelayCommand]
730 private async Task PublishMarketplace()
731 {
732 try
733 {
734 CreationAttributesEventArgs e = await ServiceRef.XmppService.GetNeuroFeatureCreationAttributes();
736 Template.Visibility = ContractVisibility.Public;
737 NewContractNavigationArgs NewContractArgs = new(Template, true,
738 new Dictionary<CaseInsensitiveString, object>()
739 {
740 { "TokenID", this.TokenId ?? string.Empty },
741 { "Category", this.Category ?? string.Empty },
742 { "FriendlyName", this.FriendlyName ?? string.Empty },
743 { "CommissionPercent", e.Commission },
744 { "Currency", e.Currency }
745 });
746
747 Template.Parts =
748 [
749 new()
750 {
751 Role = "Seller",
752 LegalId = ServiceRef.TagProfile.LegalIdentity?.Id
753 },
754 new()
755 {
756 Role = "Auctioneer",
757 LegalId = e.TrustProviderId
758 }
759 ];
760
761 NewContractArgs.SuppressProposal(e.TrustProviderId);
762
763 await ServiceRef.UiService.GoToAsync(nameof(NewContractPage), NewContractArgs, BackMethod.CurrentPage);
764 }
765 catch (Exception ex)
766 {
768 }
769 }
770
774 [RelayCommand]
775 private async Task OfferToSell()
776 {
777 try
778 {
779 Dictionary<CaseInsensitiveString, object> Parameters = [];
780 string? TrustProviderId = null;
782 Template.Visibility = ContractVisibility.Public;
783
785 {
786 CreationAttributesEventArgs e = await ServiceRef.XmppService.GetNeuroFeatureCreationAttributes();
787 XmlDocument Doc = new()
788 {
789 PreserveWhitespace = true
790 };
791 Doc.LoadXml(Template.ForMachines.OuterXml);
792
793 TrustProviderId = e.TrustProviderId;
794
795 XmlNamespaceManager NamespaceManager = new(Doc.NameTable);
796 NamespaceManager.AddNamespace("nft", NeuroFeaturesClient.NamespaceNeuroFeatures);
797
798 string? SellerRole = Doc.SelectSingleNode("/nft:Transfer/nft:Seller/nft:RoleReference/@role", NamespaceManager)?.Value;
799 string? TrustProviderRole = Doc.SelectSingleNode("/nft:Transfer/nft:TrustProvider/nft:RoleReference/@role", NamespaceManager)?.Value;
800 string? TokenIdParameter = Doc.SelectSingleNode("/nft:Transfer/nft:TokenID/nft:ParameterReference/@parameter", NamespaceManager)?.Value;
801 string? CurrencyParameter = Doc.SelectSingleNode("/nft:Transfer/nft:Currency/nft:ParameterReference/@parameter", NamespaceManager)?.Value;
802 string? CommissionParameter = Doc.SelectSingleNode("/nft:Transfer/nft:CommissionPercent/nft:ParameterReference/@parameter", NamespaceManager)?.Value;
803 string? OwnershipContractParameter = Doc.SelectSingleNode("/nft:Transfer/nft:OwnershipContract/nft:ParameterReference/@parameter", NamespaceManager)?.Value;
804
805 if (Template.Parts is null)
806 {
807 List<Part> Parts = [];
808
809 if (!string.IsNullOrEmpty(SellerRole))
810 {
811 Parts.Add(new Part()
812 {
813 LegalId = ServiceRef.TagProfile.LegalIdentity?.Id,
814 Role = SellerRole
815 });
816 }
817
818 if (!string.IsNullOrEmpty(TrustProviderRole))
819 {
820 Parts.Add(new Part()
821 {
822 LegalId = e.TrustProviderId,
823 Role = TrustProviderRole
824 });
825 }
826
827 Template.Parts = [.. Parts];
828 Template.PartsMode = ContractParts.ExplicitlyDefined;
829 }
830 else
831 {
832 foreach (Part Part in Template.Parts)
833 {
834 if (Part.Role == SellerRole)
835 Part.LegalId = ServiceRef.TagProfile.LegalIdentity?.Id;
836 else if (Part.Role == TrustProviderRole)
837 Part.LegalId = e.TrustProviderId;
838 }
839 }
840
841 if (!string.IsNullOrEmpty(TokenIdParameter))
842 Parameters[TokenIdParameter] = this.TokenId ?? string.Empty;
843
844 if (!string.IsNullOrEmpty(CurrencyParameter))
845 Parameters[CurrencyParameter] = e.Currency;
846
847 if (!string.IsNullOrEmpty(CommissionParameter))
848 Parameters[CommissionParameter] = e.Commission;
849
850 if (!string.IsNullOrEmpty(OwnershipContractParameter))
851 Parameters[OwnershipContractParameter] = this.OwnershipContract ?? string.Empty;
852 }
853
854 NewContractNavigationArgs NewContractArgs = new(Template, true, Parameters);
855
856 if (!string.IsNullOrEmpty(TrustProviderId))
857 NewContractArgs.SuppressProposal(TrustProviderId);
858
859 await ServiceRef.UiService.GoToAsync(nameof(NewContractPage), NewContractArgs, BackMethod.CurrentPage);
860 }
861 catch (Exception ex)
862 {
864 }
865 }
866
870 [RelayCommand]
871 private async Task OfferToBuy()
872 {
873 try
874 {
875 Dictionary<CaseInsensitiveString, object> Parameters = [];
876 string? TrustProviderId = null;
878 Template.Visibility = ContractVisibility.Public;
879
881 {
882 CreationAttributesEventArgs e = await ServiceRef.XmppService.GetNeuroFeatureCreationAttributes();
883 XmlDocument Doc = new()
884 {
885 PreserveWhitespace = true
886 };
887 Doc.LoadXml(Template.ForMachines.OuterXml);
888
889 TrustProviderId = e.TrustProviderId;
890
891 XmlNamespaceManager NamespaceManager = new(Doc.NameTable);
892 NamespaceManager.AddNamespace("nft", NeuroFeaturesClient.NamespaceNeuroFeatures);
893
894 string? BuyerRole = Doc.SelectSingleNode("/nft:Transfer/nft:Buyer/nft:RoleReference/@role", NamespaceManager)?.Value;
895 string? SellerRole = Doc.SelectSingleNode("/nft:Transfer/nft:Seller/nft:RoleReference/@role", NamespaceManager)?.Value;
896 string? TrustProviderRole = Doc.SelectSingleNode("/nft:Transfer/nft:TrustProvider/nft:RoleReference/@role", NamespaceManager)?.Value;
897 string? TokenIdParameter = Doc.SelectSingleNode("/nft:Transfer/nft:TokenID/nft:ParameterReference/@parameter", NamespaceManager)?.Value;
898 string? CurrencyParameter = Doc.SelectSingleNode("/nft:Transfer/nft:Currency/nft:ParameterReference/@parameter", NamespaceManager)?.Value;
899 string? CommissionParameter = Doc.SelectSingleNode("/nft:Transfer/nft:CommissionPercent/nft:ParameterReference/@parameter", NamespaceManager)?.Value;
900 string? OwnershipContractParameter = Doc.SelectSingleNode("/nft:Transfer/nft:OwnershipContract/nft:ParameterReference/@parameter", NamespaceManager)?.Value;
901
902 if (Template.Parts is null)
903 {
904 List<Part> Parts = [];
905
906 if (!string.IsNullOrEmpty(BuyerRole))
907 {
908 Parts.Add(new Part()
909 {
910 LegalId = ServiceRef.TagProfile.LegalIdentity?.Id,
911 Role = BuyerRole
912 });
913 }
914
915 if (!string.IsNullOrEmpty(SellerRole))
916 {
917 Parts.Add(new Part()
918 {
919 LegalId = this.Owner,
920 Role = SellerRole
921 });
922 }
923
924 if (!string.IsNullOrEmpty(TrustProviderRole))
925 {
926 Parts.Add(new Part()
927 {
928 LegalId = e.TrustProviderId,
929 Role = TrustProviderRole
930 });
931 }
932
933 Template.Parts = [.. Parts];
934 Template.PartsMode = ContractParts.ExplicitlyDefined;
935 }
936 else
937 {
938 foreach (Part Part in Template.Parts)
939 {
940 if (Part.Role == BuyerRole)
941 Part.LegalId = ServiceRef.TagProfile.LegalIdentity?.Id;
942 else if (Part.Role == SellerRole)
943 Part.LegalId = this.Owner;
944 else if (Part.Role == TrustProviderRole)
945 Part.LegalId = e.TrustProviderId;
946 }
947 }
948
949 if (!string.IsNullOrEmpty(TokenIdParameter))
950 Parameters[TokenIdParameter] = this.TokenId ?? string.Empty;
951
952 if (!string.IsNullOrEmpty(CurrencyParameter))
953 Parameters[CurrencyParameter] = e.Currency;
954
955 if (!string.IsNullOrEmpty(CommissionParameter))
956 Parameters[CommissionParameter] = e.Commission;
957
958 if (!string.IsNullOrEmpty(OwnershipContractParameter))
959 Parameters[OwnershipContractParameter] = this.OwnershipContract ?? string.Empty;
960 }
961
962 NewContractNavigationArgs NewContractArgs = new(Template, true, Parameters);
963
964 if (!string.IsNullOrEmpty(TrustProviderId))
965 NewContractArgs.SuppressProposal(TrustProviderId);
966
967 await ServiceRef.UiService.GoToAsync(nameof(NewContractPage), NewContractArgs, BackMethod.CurrentPage);
968 }
969 catch (Exception ex)
970 {
972 }
973 }
974
978 [RelayCommand]
979 private async Task ViewEvents()
980 {
981 if (this.TokenId is null)
982 return;
983
984 try
985 {
986 TokenEvent[] Events = this.TokenId is null ? [] : await ServiceRef.XmppService.GetNeuroFeatureEvents(this.TokenId);
987 TokenEventsNavigationArgs Args = new(this.TokenId!, Events);
988
989 await ServiceRef.UiService.GoToAsync(nameof(TokenEventsPage), Args, BackMethod.Pop);
990 }
991 catch (Exception ex)
992 {
994 }
995 }
996
1000 [RelayCommand]
1001 private async Task PresentReport()
1002 {
1003 if (this.TokenId is null)
1004 return;
1005
1006 await this.ShowReport(new TokenPresentReport(this.TokenId));
1007 }
1008
1012 [RelayCommand]
1013 private async Task HistoryReport()
1014 {
1015 if (this.TokenId is null)
1016 return;
1017
1018 await this.ShowReport(new TokenHistoryReport(this.TokenId));
1019 }
1020
1024 [RelayCommand]
1025 private async Task StatesReport()
1026 {
1027 if (this.TokenId is null)
1028 return;
1029
1030 await this.ShowReport(new TokenStateDiagramReport(this.TokenId));
1031 }
1032
1036 [RelayCommand]
1037 private async Task ProfilingReport()
1038 {
1039 if (this.TokenId is null)
1040 return;
1041
1042 await this.ShowReport(new TokenProfilingReport(this.TokenId));
1043 }
1044
1048 [RelayCommand]
1049 private async Task VariablesReport()
1050 {
1051 if (this.TokenId is null)
1052 return;
1053
1054 try
1055 {
1056 CurrentStateEventArgs e = await ServiceRef.XmppService.GetNeuroFeatureCurrentState(this.TokenId);
1057 if (e.Ok)
1058 {
1059 MachineVariablesNavigationArgs Args = new(e.Running, e.Ended, e.CurrentState, e.Variables);
1060
1062 }
1063 else
1064 await ServiceRef.UiService.DisplayAlert(ServiceRef.Localizer[nameof(AppResources.ErrorTitle)], e.ErrorText);
1065 }
1066 catch (Exception ex)
1067 {
1069 }
1070 }
1071
1072 private async Task ShowReport(TokenReport Report)
1073 {
1074 try
1075 {
1076 MachineReportNavigationArgs Args = new(Report);
1077
1078 await ServiceRef.UiService.GoToAsync(nameof(MachineReportPage), Args, BackMethod.Pop);
1079 }
1080 catch (Exception ex)
1081 {
1082 await ServiceRef.UiService.DisplayAlert(ServiceRef.Localizer[nameof(AppResources.ErrorTitle)], ex.Message);
1083 }
1084 }
1085
1086 #endregion
1087
1088 #region ILinkableView
1089
1093 public override Task<string> Title => Task.FromResult<string>(this.FriendlyName ?? string.Empty);
1094
1095 #endregion
1096
1097
1098 }
1099}
The Application class, representing an instance of the Neuro-Access app.
Definition: App.xaml.cs:69
static Task< bool > OpenUrlAsync(string Url)
Opens an URL in the application.
Definition: App.xaml.cs:919
const string TokenConsignmentTemplate
Contract template for consigning the token to an auctioneer with the purpose of selling it.
Definition: Constants.cs:840
const string TransferTokenTemplate
Contract template for transferring a token from a seller to a buyer
Definition: Constants.cs:835
static readonly TimeSpan UploadFile
Upload file timeout
Definition: Constants.cs:581
const string NeuroFeature
eDaler URI Scheme (edaler)
Definition: Constants.cs:124
static string CreateTokenUri(string id)
Generates a Neuro-Feature ID Uri form the specified id.
Definition: Constants.cs:208
A set of never changing property constants and helpful values.
Definition: Constants.cs:7
Contains information about a contact.
Definition: ContactInfo.cs:21
static async Task< string > GetFriendlyName(CaseInsensitiveString RemoteId)
Gets the friendly name of a remote identity (Legal ID or Bare JID).
Definition: ContactInfo.cs:257
Base class that references services in the app.
Definition: ServiceRef.cs:31
static ILogService LogService
Log service.
Definition: ServiceRef.cs:91
static IUiService UiService
Service serializing and managing UI-related tasks.
Definition: ServiceRef.cs:55
static ITagProfile TagProfile
TAG Profile service.
Definition: ServiceRef.cs:79
static IStringLocalizer Localizer
Localization service
Definition: ServiceRef.cs:235
static IContractOrchestratorService ContractOrchestratorService
Contract orchestrator service.
Definition: ServiceRef.cs:115
static IXmppService XmppService
The XMPP service for XMPP communication.
Definition: ServiceRef.cs:67
Holds navigation parameters specific to views displaying a list of contacts.
A page that displays a list of the current user's contacts.
The view model to bind to when displaying the list of contacts.
Contact Information model, including related notification information.
ContactInfo? Contact
Contact Information object in database.
CaseInsensitiveString? BareJid
Bare JID of contact.
Holds navigation parameters specific to views displaying a list of contacts.
A page that displays a list of the current user's contacts.
A page that allows the user to create a new contract.
A view model that holds the XMPP state.
Holds navigation parameters specific to a report from a state-machine.
A page that allows the user to view a state-machine report.
Holds navigation parameters specific to the current state of a state-machine.
A page that allows the user to view information about the current state of a state-machine.
A page that allows the user to view information about a token.
Holds navigation parameters containing the events of a token.
A page that allows the user to view information about a token.
Abstract base class for token events.
Definition: TokenEvent.cs:13
const string NamespaceNeuroFeatures
Namespace for Neuro-Features.
Abstract base class for token tag references.
Definition: TokenTag.cs:12
abstract object Value
Object value.
Definition: TokenTag.cs:37
CaseInsensitiveString Name
Tag Name
Definition: TokenTag.cs:32
Static class managing encoding and decoding of internet content.
static string GetFileExtension(string ContentType)
Gets the file extension of an item, given its content type. It uses the TryGetFileExtension to see if...
Contains the definition of a contract
Definition: Contract.cs:22
string ForMachinesLocalName
Local name used by the root node of the machine-readable contents of the contract (ForMachines).
Definition: Contract.cs:294
XmlElement ForMachines
Machine-readable contents of the contract.
Definition: Contract.cs:276
Part[] Parts
Defined parts for the smart contract.
Definition: Contract.cs:258
string ForMachinesNamespace
Namespace used by the root node of the machine-readable contents of the contract (ForMachines).
Definition: Contract.cs:289
Abstract base class for contractual parameters
Definition: Parameter.cs:17
Class defining a part in a contract
Definition: Part.cs:30
string Role
Role of the part in the contract
Definition: Part.cs:57
Class defining a role
Definition: Role.cs:7
bool Ok
If the response is an OK result response (true), or an error response (false).
XmppException StanzaError
Any stanza error returned.
Event arguments for HTTP File Upload callback methods.
async Task PUT(byte[] Content, string ContentType, int Timeout)
Uploads file content to the server.
Task DisplayException(Exception Exception, string? Title=null)
Displays an alert/message box to the user.
Task GoToAsync(string Route, BackMethod BackMethod=BackMethod.Inherited, string? UniqueId=null)
Navigates the AppShell to the specified route, with page arguments to match.
Task< bool > DisplayAlert(string Title, string Message, string? Accept=null, string? Cancel=null)
Displays an alert/message box to the user.
BackMethod
Navigation Back Method
Definition: BackMethod.cs:7
class TokenPresentReport(string TokenId)
Represent a report of the present state of a token and the underlying state-machine.
class TokenStateDiagramReport(string TokenId)
Represent a state diagram of a token and the underlying state-machine.
class TokenHistoryReport(string TokenId)
Represent a report of the historical states of a token and the underlying state-machine.
class TokenProfilingReport(string TokenId)
Represent a profiling report of a token and the underlying state-machine.
partial class TokenDetailsViewModel(TokenDetailsPage Page, TokenDetailsNavigationArgs? Args)
The view model to bind to for when displaying the contents of a token.
class PartItem(string LegalId, string Jid, string FriendlyName)
Represents a part related to a token.
Definition: PartItem.cs:9
TokenIdMethod
By which mechanism the Token ID was created
Definition: Token.cs:21
ContractParts
How the parts of the contract are defined.
Definition: Part.cs:9
ContractVisibility
Visibility types for contracts.
Definition: Enumerations.cs:58
HashFunction
Hash method enumeration.
Definition: Hashes.cs:28
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:13