1using CommunityToolkit.Mvvm.ComponentModel;
2using CommunityToolkit.Mvvm.Input;
26using System.ComponentModel;
27using System.Globalization;
28using System.Security.Cryptography;
49 private readonly SortedDictionary<string, LinkedListNode<MessageRecord>> messagesByObjectId = [];
50 private readonly LinkedList<MessageRecord> messages = [];
51 private readonly LinkedList<MessageFrame> frames = [];
53 private readonly
object synchObject =
new();
54 private TaskCompletionSource<bool> waitUntilBound =
new();
55 private IView? scrollTo;
60 public LinkedListNode<MessageFrame> FrameNode = FrameNode;
62 public DateTime Created => this.Message.
Created;
75 this.LegalId = Args?.
LegalId ??
string.Empty;
76 this.BareJid = Args?.
BareJid ??
string.Empty;
80 this.page.OnAfterAppearing += this.Page_OnAfterAppearing;
88 this.HyperlinkClicked =
new Command(async
Parameter => await ExecuteHyperlinkClicked(
Parameter));
126 private static async Task ExecuteHyperlinkClicked(
object Parameter)
138 await base.OnInitialize();
140 this.scrollTo = await this.LoadMessagesAsync(
false);
142 this.waitUntilBound.TrySetResult(
true);
151 await base.OnDispose();
153 this.waitUntilBound =
new TaskCompletionSource<bool>();
156 private Task Page_OnAfterAppearing(
object Sender, EventArgs e)
158 if (this.scrollTo is Element)
163 this.scrollTo =
null;
166 return Task.CompletedTask;
173 private string? uniqueId;
179 private string? bareJid;
185 private string? legalId;
191 private string? friendlyName;
197 [NotifyCanExecuteChangedFor(nameof(SendCommand))]
198 [NotifyCanExecuteChangedFor(nameof(CancelCommand))]
199 private string markdownInput =
string.Empty;
204 base.OnPropertyChanged(e);
206 switch (e.PropertyName)
208 case nameof(this.MarkdownInput):
209 this.IsWriting = !
string.IsNullOrEmpty(this.MarkdownInput);
212 case nameof(this.MessageId):
213 this.IsWriting = !
string.IsNullOrEmpty(this.MessageId);
216 case nameof(this.IsWriting):
217 this.IsButtonExpanded =
false;
220 case nameof(this.IsRecordingAudio):
224 this.IsWriting = this.IsRecordingAudio;
236 this.CancelCommand.NotifyCanExecuteChanged();
239 case nameof(this.IsConnected):
240 this.SendCommand.NotifyCanExecuteChanged();
241 this.CancelCommand.NotifyCanExecuteChanged();
242 this.RecordAudioCommand.NotifyCanExecuteChanged();
243 this.TakePhotoCommand.NotifyCanExecuteChanged();
244 this.EmbedFileCommand.NotifyCanExecuteChanged();
245 this.EmbedIdCommand.NotifyCanExecuteChanged();
246 this.EmbedContractCommand.NotifyCanExecuteChanged();
247 this.EmbedMoneyCommand.NotifyCanExecuteChanged();
248 this.EmbedTokenCommand.NotifyCanExecuteChanged();
249 this.EmbedThingCommand.NotifyCanExecuteChanged();
258 private string? messageId;
264 [NotifyCanExecuteChangedFor(nameof(LoadMoreMessagesCommand))]
265 private bool existsMoreMessages;
271 [NotifyCanExecuteChangedFor(nameof(RecordAudioCommand))]
272 [NotifyCanExecuteChangedFor(nameof(TakePhotoCommand))]
273 [NotifyCanExecuteChangedFor(nameof(EmbedFileCommand))]
274 [NotifyCanExecuteChangedFor(nameof(EmbedIdCommand))]
275 [NotifyCanExecuteChangedFor(nameof(EmbedContractCommand))]
276 [NotifyCanExecuteChangedFor(nameof(EmbedMoneyCommand))]
277 [NotifyCanExecuteChangedFor(nameof(EmbedTokenCommand))]
278 [NotifyCanExecuteChangedFor(nameof(EmbedThingCommand))]
279 private bool isWriting;
285 [NotifyCanExecuteChangedFor(nameof(SendCommand))]
286 private bool isRecordingAudio;
292 private bool isRecordingPaused;
319 MainThread.BeginInvokeOnMainThread(async () =>
323 IView? View = await this.MessageAddedMainThread(Message,
true);
327 await Task.Delay(25);
328 double x = this.page.ScrollView.ScrollX;
329 double y = this.page.ScrollView.ContentSize.Height;
330 await this.page.ScrollView.ScrollToAsync(x, y,
true);
335 private async Task<IView?> MessageAddedMainThread(
ChatMessage Message,
bool Historic)
337 this.HasMessages =
true;
339 TaskCompletionSource<IView?> Result =
new();
346 lock (this.synchObject)
348 LinkedListNode<MessageRecord>? MessageNode = Historic ? this.messages.Last : this.messages.First;
349 LinkedListNode<MessageFrame>? FrameNode;
354 if (MessageNode is
null)
359 this.page.Messages.Add(Frame);
361 FrameNode = this.frames.AddLast(Frame);
363 Rec =
new(Message, FrameNode);
364 MessageNode = this.messages.AddLast(Rec);
368 while (MessageNode is not
null && Message.
Created > MessageNode.Value.Created)
369 MessageNode = MessageNode.Next;
370 if (MessageNode is
null)
372 FrameNode = this.frames.Last!;
374 if (FrameNode.Value.MessageType != Message.
MessageType)
377 this.page.Messages.Add(FrameNode.Value);
380 View = FrameNode.Value.AddLast(Message);
382 Rec =
new(Message, FrameNode);
383 MessageNode = this.messages.AddLast(Rec);
393 while (MessageNode is not
null && Message.
Created < MessageNode.Value.Created)
394 MessageNode = MessageNode.Previous;
396 if (MessageNode is
null)
398 FrameNode = this.frames.First!;
400 if (FrameNode.Value.MessageType != Message.
MessageType)
403 this.page.Messages.Insert(0, FrameNode.Value);
406 View = FrameNode.Value.AddFirst(Message);
408 Rec =
new(Message, FrameNode);
409 MessageNode = this.messages.AddFirst(Rec);
418 Result.TrySetResult(View);
446 this.messagesByObjectId[Message.ObjectId ??
string.Empty] = MessageNode;
451 Result.TrySetException(ex);
454 return await Result.Task;
473 if (Message.
ParsedXaml is not IView MessageXaml ||
string.IsNullOrEmpty(Message.
ObjectId))
476 MainThread.BeginInvokeOnMainThread(() =>
480 lock (this.synchObject)
484 if (this.messagesByObjectId.TryGetValue(Message.
ObjectId, out LinkedListNode<MessageRecord>? Node) &&
485 Node.Value.Message.ParsedXaml is IView PrevMessageXaml &&
486 PrevMessageXaml.Parent is VerticalStackLayout Parent &&
487 (i = Parent.IndexOf(PrevMessageXaml)) >= 0)
490 Parent.Insert(i, MessageXaml);
492 Node.Value.Message = Message;
505 private async Task<IView?> LoadMessagesAsync(
bool LoadMore =
true)
507 IEnumerable<ChatMessage>? Messages =
null;
514 this.ExistsMoreMessages =
false;
516 lock (this.synchObject)
518 LastTime = LoadMore && this.messages.First is not
null ? this.messages.First.Value.Created : DateTime.MaxValue;
534 this.ExistsMoreMessages =
false;
538 TaskCompletionSource<IView?> Result =
new();
540 MainThread.BeginInvokeOnMainThread(async () =>
547 Last = await this.MessageAddedMainThread(Message,
true);
549 this.ExistsMoreMessages = c <= 0;
551 Result.TrySetResult(Last);
555 Result.TrySetException(ex);
559 return await Result.Task;
563 private bool hasMessages =
false;
569 private bool isButtonExpanded;
575 private void ExpandButtons()
577 this.IsButtonExpanded = !this.IsButtonExpanded;
583 [RelayCommand(CanExecute = nameof(CanExecuteLoadMoreMessages))]
584 private Task<IView?> LoadMoreMessages()
586 return this.LoadMessagesAsync(
true);
589 private bool CanExecuteLoadMoreMessages()
591 return this.ExistsMoreMessages && this.page.Messages.Count > 0;
594 private bool CanExecuteSendMessage()
596 return this.IsConnected && (!
string.IsNullOrEmpty(this.MarkdownInput) || this.IsRecordingAudio);
602 [RelayCommand(CanExecute = nameof(CanExecuteSendMessage))]
603 private async Task Send()
605 if (this.IsRecordingAudio)
628 await this.ExecuteSendMessage(this.MessageId, this.MarkdownInput);
633 private Task ExecuteSendMessage(
string? ReplaceObjectId,
string MarkdownInput)
635 return ExecuteSendMessage(ReplaceObjectId, MarkdownInput, this.BareJid!,
this);
646 return ExecuteSendMessage(ReplaceObjectId, MarkdownInput, BareJid,
null);
660 if (
string.IsNullOrEmpty(MarkdownInput))
665 AllowScriptTag =
false,
667 AudioAutoplay =
false,
668 AudioControls =
false,
669 ParseMetaData =
false,
670 VideoAutoplay =
false,
671 VideoControls =
false
678 Created = DateTime.UtcNow,
679 RemoteBareJid = BareJid,
680 RemoteObjectId =
string.Empty,
685 Markdown = MarkdownInput
688 StringBuilder Xml =
new();
690 Xml.Append(
"<content xmlns=\"urn:xmpp:content\" type=\"text/markdown\">");
692 Xml.Append(
"</content><html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>");
694 HtmlDocument HtmlDoc =
new(
"<root>" + Message.Html +
"</root>");
696 foreach (
HtmlNode N
in (HtmlDoc.Body ?? HtmlDoc.Root).Children)
699 Xml.Append(
"</body></html>");
701 if (!
string.IsNullOrEmpty(ReplaceObjectId))
703 Xml.Append(
"<replace id='");
704 Xml.Append(ReplaceObjectId);
705 Xml.Append(
"' xmlns='urn:xmpp:message-correct:0'/>");
708 if (
string.IsNullOrEmpty(ReplaceObjectId))
721 ReplaceObjectId =
null;
730 Old.Html = Message.
Html;
743 BareJid, Xml.ToString(), Message.
PlainText,
string.Empty,
string.Empty,
string.Empty,
string.Empty,
null,
null);
754 [RelayCommand(CanExecute = nameof(CanExecutePauseResume))]
755 private Task PauseResume()
766 return Task.CompletedTask;
769 private static bool CanExecutePauseResume()
777 private bool CanExecuteCancelMessage()
779 return this.IsConnected && (!
string.IsNullOrEmpty(this.MarkdownInput) || this.IsRecordingAudio);
785 [RelayCommand(CanExecute = nameof(CanExecuteCancelMessage))]
786 private Task Cancel()
788 if (this.IsRecordingAudio)
807 this.MarkdownInput =
string.Empty;
808 this.MessageId =
string.Empty;
811 return Task.CompletedTask;
830 private bool CanExecuteRecordAudio()
835 private void OnAudioRecorderTimer(
object? source, ElapsedEventArgs e)
844 [RelayCommand(CanExecute = nameof(CanExecuteRecordAudio))]
845 private async Task RecordAudio()
856 PermissionStatus Status = await Permissions.RequestAsync<Permissions.Microphone>();
858 if (Status == PermissionStatus.Granted)
872 private bool CanExecuteTakePhoto()
880 [RelayCommand(CanExecute = nameof(CanExecuteTakePhoto))]
881 private async Task TakePhoto()
890 if (DeviceInfo.Platform == DevicePlatform.iOS)
892 FileResult? capturedPhoto;
896 capturedPhoto = await MediaPicker.Default.CapturePhotoAsync(
new MediaPickerOptions()
904 ServiceRef.
Localizer[nameof(AppResources.TakingAPhotoIsNotSupported)] +
": " + ex.Message);
908 if (capturedPhoto is not
null)
912 await this.EmbedMedia(capturedPhoto.FullPath,
true);
922 FileResult? capturedPhoto;
926 capturedPhoto = await MediaPicker.CapturePhotoAsync();
927 if (capturedPhoto is
null)
933 ServiceRef.
Localizer[nameof(AppResources.TakingAPhotoIsNotSupported)] +
": " + ex.Message);
937 if (capturedPhoto is not
null)
941 await this.EmbedMedia(capturedPhoto.FullPath,
true);
951 private async Task EmbedMedia(
string FilePath,
bool DeleteFile)
955 byte[] Bin = File.ReadAllBytes(FilePath);
974 string FileName = Path.GetFileName(FilePath);
978 using RandomNumberGenerator Rnd = RandomNumberGenerator.Create();
979 byte[] Key =
new byte[16];
980 byte[] IV =
new byte[16];
985 Aes Aes = Aes.Create();
988 Aes.Mode = CipherMode.CBC;
989 Aes.Padding = PaddingMode.PKCS7;
991 using ICryptoTransform Transform = Aes.CreateEncryptor(Key, IV);
992 Bin = Transform.TransformFinalBlock(Bin, 0, Bin.Length);
996 StringBuilder Xml =
new();
998 Xml.Append(
"<prepare xmlns='http://waher.se/Schema/EncryptedStorage.xsd' filename='");
1000 Xml.Append(
"' size='");
1001 Xml.Append(Bin.Length.ToString(CultureInfo.InvariantCulture));
1002 Xml.Append(
"' content-type='application/octet-stream'/>");
1010 FileName,
"application/octet-stream", Bin.Length);
1013 throw Slot.StanzaError ??
new Exception(Slot.
ErrorText);
1021 StringBuilder Markdown =
new();
1023 Markdown.Append(
";
1027 Markdown.Append(
':');
1028 Markdown.Append(Convert.ToBase64String(Key));
1029 Markdown.Append(
':');
1030 Markdown.Append(Convert.ToBase64String(IV));
1031 Markdown.Append(
':');
1032 Markdown.Append(ContentType);
1033 Markdown.Append(
':');
1034 Markdown.Append(Slot.
GetUrl);
1036 SKImageInfo ImageInfo = SKBitmap.DecodeBounds(Bin);
1037 if (!ImageInfo.IsEmpty)
1039 Markdown.Append(
' ');
1040 Markdown.Append(ImageInfo.Width.ToString(CultureInfo.InvariantCulture));
1041 Markdown.Append(
' ');
1042 Markdown.Append(ImageInfo.Height.ToString(CultureInfo.InvariantCulture));
1045 Markdown.Append(
')');
1047 await this.ExecuteSendMessage(
string.Empty, Markdown.ToString());
1052 File.Delete(FilePath);
1054 catch (Exception ex)
1062 private bool CanExecuteEmbedFile()
1070 [RelayCommand(CanExecute = nameof(CanExecuteEmbedFile))]
1071 private async Task EmbedFile()
1079 FileResult? pickedPhoto = await MediaPicker.PickPhotoAsync();
1081 if (pickedPhoto is not
null)
1082 await this.EmbedMedia(pickedPhoto.FullPath,
false);
1085 private bool CanExecuteEmbedId()
1087 return this.IsConnected && !this.IsWriting;
1093 [RelayCommand(CanExecute = nameof(CanExecuteEmbedId))]
1094 private async Task EmbedId()
1096 TaskCompletionSource<ContactInfoModel?> SelectedContact =
new();
1099 CanScanQrCode =
true
1105 if (Contact is
null)
1108 await this.waitUntilBound.Task;
1112 StringBuilder Markdown =
new();
1114 Markdown.Append(
"```");
1119 Markdown.AppendLine();
1120 Markdown.AppendLine(
"```");
1122 await this.ExecuteSendMessage(
string.Empty, Markdown.ToString());
1126 if (!
string.IsNullOrEmpty(Contact.
LegalId))
1132 if (!
string.IsNullOrEmpty(Contact.
BareJid))
1139 private bool CanExecuteEmbedContract()
1141 return this.IsConnected && !this.IsWriting;
1147 [RelayCommand(CanExecute = nameof(CanExecuteEmbedContract))]
1148 private async Task EmbedContract()
1150 TaskCompletionSource<Contract?> SelectedContract =
new();
1159 await this.waitUntilBound.Task;
1161 StringBuilder Markdown =
new();
1163 Markdown.Append(
"```");
1168 Markdown.AppendLine();
1169 Markdown.AppendLine(
"```");
1171 await this.ExecuteSendMessage(
string.Empty, Markdown.ToString());
1174 private bool CanExecuteEmbedMoney()
1176 return this.IsConnected && !this.IsWriting;
1182 [RelayCommand(CanExecute = nameof(CanExecuteEmbedMoney))]
1183 private async Task EmbedMoney()
1185 StringBuilder sb =
new();
1187 sb.Append(
"edaler:");
1189 if (!
string.IsNullOrEmpty(this.LegalId))
1192 sb.Append(this.LegalId);
1194 else if (!
string.IsNullOrEmpty(this.BareJid))
1197 sb.Append(this.BareJid);
1205 sb.Append(CurrentBalance.
Currency);
1210 TaskCompletionSource<string?> UriToSend =
new();
1215 string? Uri = await UriToSend.Task;
1219 await this.waitUntilBound.Task;
1224 if (Parsed.AmountExtra.HasValue)
1232 sb.Append(Parsed.Currency);
1234 await this.ExecuteSendMessage(
string.Empty,
"");
1237 private bool CanExecuteEmbedToken()
1239 return this.IsConnected && !this.IsWriting;
1245 [RelayCommand(CanExecute = nameof(CanExecuteEmbedToken))]
1246 private async Task EmbedToken()
1254 if (Selected is
null)
1257 StringBuilder Markdown =
new();
1259 Markdown.AppendLine(
"```nfeat");
1263 Markdown.AppendLine();
1264 Markdown.AppendLine(
"```");
1266 await this.ExecuteSendMessage(
string.Empty, Markdown.ToString());
1269 private bool CanExecuteEmbedThing()
1271 return this.IsConnected && !this.IsWriting;
1277 [RelayCommand(CanExecute = nameof(CanExecuteEmbedThing))]
1278 private async Task EmbedThing()
1280 TaskCompletionSource<ContactInfoModel?> ThingToShare =
new();
1289 await this.waitUntilBound.Task;
1291 StringBuilder sb =
new();
1295 sb.Append(
"](iotdisco:JID=");
1298 if (!
string.IsNullOrEmpty(Thing.
SourceId))
1304 if (!
string.IsNullOrEmpty(Thing.
Partition))
1310 if (!
string.IsNullOrEmpty(Thing.
NodeId))
1318 await this.ExecuteSendMessage(
string.Empty, sb.ToString());
1325 private Task MessageSelected(
object Parameter)
1340 switch (Message.MessageType)
1344 this.MessageId = Message.ObjectId;
1345 this.MarkdownInput = Message.Markdown;
1350 string s = Message.Markdown;
1351 if (
string.IsNullOrEmpty(s))
1354 string[] Rows = s.Replace(
"\r\n",
"\n").Replace(
"\r",
"\n").Split(
'\n');
1356 StringBuilder Quote =
new();
1358 foreach (
string Row
in Rows)
1361 Quote.AppendLine(Row);
1366 this.MessageId =
string.Empty;
1367 this.MarkdownInput = Quote.ToString();
1372 return Task.CompletedTask;
1388 int i = Uri.IndexOf(
':');
1392 string s = Uri[(i + 1)..].Trim();
1393 if (s.StartsWith(
'<') && s.EndsWith(
'>'))
1395 XmlDocument Doc =
new()
1397 PreserveWhitespace =
true
1405 ViewIdentityNavigationArgs ViewIdentityArgs =
new(Id);
1437 catch (Exception ex)
1450 int i = Uri.IndexOf(
':');
1454 string Jid = Uri[(i + 1)..].TrimStart();
1457 i = Jid.IndexOf(
'?');
1459 Command =
"subscribe";
1462 Command = Jid[(i + 1)..].TrimStart();
1463 Jid = Jid[..i].TrimEnd();
1466 Jid = System.Web.HttpUtility.UrlDecode(Jid);
1469 switch (Command.ToLower(CultureInfo.InvariantCulture))
1478 if (SubscribeTo.HasValue && SubscribeTo.Value)
1483 IdXml =
string.Empty;
1486 StringBuilder Xml =
new();
1488 IdXml = Xml.ToString();
1509 #region ILinkableView
1524 public string Link => Constants.UriSchemes.Xmpp +
":" + this.BareJid;
1529 public Task<string>
Title => Task.FromResult<
string>(this.FriendlyName ??
string.Empty);
Contains information about a balance.
CaseInsensitiveString Currency
Currency of amount.
Abstract base class for eDaler URIs
static bool TryParse(string Uri, out EDalerUri Result)
Tries to parse an eDaler URI
The Application class, representing an instance of the Neuro-Access app.
static Task< bool > OpenUrlAsync(string Url)
Opens an URL in the application.
const int MessageBatchSize
Number of messages to load in a single batch.
static readonly TimeSpan XmppConnect
XMPP Connect timeout
static readonly TimeSpan UploadFile
Upload file timeout
const string IotSc
The IoT Smart Contract URI Scheme (iotsc)
const string Aes256
AES-256-encrypted data.
const string IotId
The IoT ID URI Scheme (iotid)
A set of never changing property constants and helpful values.
Base class that references services in the app.
static ILogService LogService
Log service.
static IUiService UiService
Service serializing and managing UI-related tasks.
static INotificationService NotificationService
Service for managing notifications for the user.
static ITagProfile TagProfile
TAG Profile service.
static IStringLocalizer Localizer
Localization service
static IXmppService XmppService
The XMPP service for XMPP communication.
string? UniqueId
An unique view identifier used to search the args of similar view types.
Helper class to perform scanning of QR Codes by displaying the UI and handling async results.
static Task< bool > OpenUrl(string Url)
Scans a QR Code, and depending on the actual result, takes different actions. This typically means na...
Converts values to strings.
static string ToString(decimal Money)
Converts a monetary value to a string, removing any round-off errors.
async Task GenerateXaml(IChatView View)
Parses the XAML in the message.
object? ParsedXaml
Parsed XAML
DateTime Created
When message was created
string Html
HTML of message
MessageType MessageType
Message Type
string PlainText
Plain text of message
string Markdown
Markdown of message
string? ObjectId
Object ID
Holds navigation parameters specific to views displaying a list of contacts.
string? FriendlyName
Friendly name
string? BareJid
Bare JID of remote chat party
string? LegalId
Legal ID, if available.
A page that displays a list of the current user's contacts.
The view model to bind to when displaying the list of contacts.
byte?[] Media
Encoded media, if available.
Command XmppUriClicked
Command executed when a multi-media-link with the xmpp URI scheme is clicked.
static string RecordingTime
If the audio recording is paused
Command HyperlinkClicked
Command executed when a hyperlink in rendered markdown has been clicked.
bool IsLinkable
If the current view is linkable.
bool EncodeAppLinks
If App links should be encoded with the link.
Command EDalerUriClicked
Command executed when a multi-media-link with the edaler URI scheme is clicked.
bool HasMedia
If linkable view has media associated with link.
string Link
Link to the current view
static async Task ExecuteSendMessage(string? ReplaceObjectId, string MarkdownInput, string BareJid, ChatViewModel? ChatViewModel)
Sends a Markdown-formatted chat message
override async Task OnInitialize()
Method called when view is initialized for the first time. Use this method to implement registration ...
override async Task OnDispose()
Method called when the view is disposed, and will not be used more. Use this method to unregister eve...
Task< string > Title
Title of the current view
static async Task< bool > ProcessXmppUri(string Uri)
Processes an XMPP URI
Command IotScUriClicked
Command executed when a multi-media-link with the iotsc URI scheme is clicked.
Command NeuroFeatureUriClicked
Command executed when a multi-media-link with the nfeat URI scheme is clicked.
async Task ExecuteUriClicked(string Uri, UriScheme Scheme)
Called when a Multi-media URI link using the XMPP URI scheme.
async Task MessageAddedAsync(ChatMessage Message)
External message has been received
override void OnPropertyChanged(PropertyChangedEventArgs e)
static Task ExecuteSendMessage(string? ReplaceObjectId, string MarkdownInput, string BareJid)
Sends a Markdown-formatted chat message
async Task MessageUpdatedAsync(ChatMessage Message)
External message has been updated
string? MediaContentType
Content-Type of associated media.
ChatViewModel(ChatPage Page, ChatNavigationArgs? Args)
Creates an instance of the ChatViewModel class.
Command IotDiscoUriClicked
Command executed when a multi-media-link with the iotdisco URI scheme is clicked.
Command IotIdUriClicked
Command executed when a multi-media-link with the iotid URI scheme is clicked.
Frame containing sent messages.
static MessageFrame Create(ChatMessage Message)
Creates a message frame for a given message.
IView AddLast(ChatMessage Message)
Adds a message to the frame.
Contact Information model, including related notification information.
LegalIdentity? LegalIdentity
Legal Identity object.
string? Partition
Partition
string? SourceId
Source ID
CaseInsensitiveString? LegalId
Legal ID of contact.
string? FriendlyName
Friendly name.
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.
Holds navigation parameters specific to views displaying a list of contacts.
A page that displays a list of the current user's contracts.
A page that displays a specific contract.
A page to display when the user wants to view an identity.
Holds navigation parameters specific to viewing things.
A page that displays a list of the current user's things.
Holds navigation parameters specific to eDaler URIs.
Holds navigation parameters for viewing tokens.
TaskCompletionSource< TokenItem?> TokenItemProvider
Task completion source; can be used to wait for a result.
A page that allows the user to view its tokens.
Encapsulates a Token object.
A page that allows the user to realize payments.
Holds navigation parameters specific to a token.
A page that allows the user to view information about a token.
A view model that holds the XMPP state.
static bool TryParse(XmlElement Xml, out Token Token)
Serializes the Token, in normalized form.
void Serialize(StringBuilder Xml)
Serializes the Token, in normalized form.
static string GetBody(string Html)
Extracts the contents of the BODY element in a HTML string.
Base class for all HTML nodes.
abstract void Export(XmlWriter Output)
Exports the HTML document to XML.
Static class managing encoding and decoding of internet content.
static bool TryGetContentType(string FileExtension, out string ContentType)
Tries to get the content type of an item, given its file extension.
Contains a markdown document. This markdown document class supports original markdown,...
static string Encode(string s)
Encodes all special characters in a string so that it can be included in a markdown document without ...
async Task< string > GeneratePlainText()
Generates Plain Text from the markdown text.
async Task< string > GenerateHTML()
Generates HTML from the markdown text.
static Task< MarkdownDocument > CreateAsync(string MarkdownText, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
Contains settings that the Markdown parser uses to customize its behavior.
Helps with common XML-related tasks.
static string Encode(string s)
Encodes a string for use in XML.
Contains the definition of a contract
static Task< ParsedContract > Parse(XmlDocument Xml)
Validates a contract XML Document, and returns the contract definition in it.
void Serialize(StringBuilder Xml, bool IncludeNamespace, bool IncludeIdAttribute, bool IncludeClientSignatures, bool IncludeAttachments, bool IncludeStatus, bool IncludeServerSignature, bool IncludeAttachmentReferences)
Serializes the Contract, in normalized form.
Adds support for legal identities, smart contracts and signatures to an XMPP client.
static string LegalIdUriString(string LegalId)
Legal identity URI, as a string.
void Serialize(StringBuilder Xml, bool IncludeNamespace, bool IncludeIdAttribute, bool IncludeClientSignature, bool IncludeAttachments, bool IncludeStatus, bool IncludeServerSignature, bool IncludeAttachmentReferences)
Serializes the identity to XML
static LegalIdentity Parse(XmlElement Xml)
Parses an identity from its XML representation
Abstract base class for contractual parameters
Contains information about a parsed contract.
Contract Contract
Contract object
bool Ok
If the response is an OK result response (true), or an error response (false).
string ErrorText
Any error specific text.
Event arguments for HTTP File Upload callback methods.
async Task PUT(byte[] Content, string ContentType, int Timeout)
Uploads file content to the server.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
static string GetBareJID(string JID)
Gets the Bare JID from a JID, which may be a Full JID.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static async Task Update(object Object)
Updates 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 Task< object > TryLoadObject(string CollectionName, object ObjectId)
Tries to load an object given its Object ID ObjectId and its collection name CollectionName .
This filter selects objects that conform to all child-filters provided.
This filter selects objects that have a named field equal to a given value.
This filter selects objects that have a named field lesser than a given value.
Task DeleteEvents(NotificationEventType Type, CaseInsensitiveString Category)
Deletes events for a given button and category.
bool TryGetNotificationEvents(NotificationEventType Type, CaseInsensitiveString Category, [NotNullWhen(true)] out NotificationEvent[]? Events)
Tries to get available notification events.
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.
Interfaces for views displaying markdown
Interface for linkable views.
abstract class NotificationEvent()
Abstract base class of notification events.
NotificationEventType
Button on which event is to be displayed.
BackMethod
Navigation Back Method
ContractsListMode
What list of contracts to display
QoSLevel
Quality of Service Level for asynchronous messages. Support for QoS Levels must be supported by the r...
MessageType
Type of message received.
ContentType
DTLS Record content type.