1using CommunityToolkit.Mvvm.ComponentModel;
 
    2using CommunityToolkit.Mvvm.Input;
 
    9using System.ComponentModel;
 
   10using System.Globalization;
 
   25        private readonly TaskCompletionSource<string?>? uriToSend = 
null;
 
   35            this.navigationArguments = Args;
 
   36            this.shareQrCode = ShareQrCode;
 
   41            if (Args?.Uri is not 
null)
 
   43                this.Uri = Args.
Uri.UriString;
 
   44                this.Id = Args.
Uri.Id;
 
   45                this.Amount = Args.
Uri.Amount;
 
   46                this.AmountExtra = Args.
Uri.AmountExtra;
 
   47                this.Currency = Args.
Uri.Currency;
 
   48                this.Created = Args.
Uri.Created;
 
   49                this.Expires = Args.
Uri.Expires;
 
   50                this.ExpiresStr = this.Expires.ToShortDateString();
 
   51                this.From = Args.
Uri.From;
 
   52                this.FromType = Args.
Uri.FromType;
 
   53                this.To = Args.
Uri.To;
 
   54                this.ToType = Args.
Uri.ToType;
 
   55                this.ToPreset = !
string.IsNullOrEmpty(Args.
Uri.To);
 
   56                this.Complete = Args.
Uri.Complete;
 
   61            this.AmountText = !this.Amount.HasValue || this.Amount.Value <= 0 ? string.Empty : 
MoneyToString.
ToString(this.Amount.Value);
 
   63            this.AmountPreset = !
string.IsNullOrEmpty(this.AmountText) && this.AmountOk;
 
   64            this.AmountAndCurrency = this.AmountText + 
" " + this.Currency;
 
   66            this.AmountExtraText = this.AmountExtra.HasValue ? 
MoneyToString.
ToString(this.AmountExtra.Value) : 
string.Empty;
 
   67            this.AmountExtraOk = !this.AmountExtra.HasValue || this.AmountExtra.Value >= 0;
 
   68            this.AmountExtraPreset = this.AmountExtra.HasValue;
 
   69            this.AmountExtraAndCurrency = this.AmountExtraText + 
" " + this.Currency;
 
   71            StringBuilder Url = 
new();
 
   73            Url.Append(
"https://");
 
   74            Url.Append(this.From);
 
   75            Url.Append(
"/Images/eDalerFront200.png");
 
   77            this.EDalerFrontGlyph = Url.ToString();
 
   80            Url.Append(
"https://");
 
   82            Url.Append(
"/Images/eDalerBack200.png");
 
   83            this.EDalerBackGlyph = Url.ToString();
 
   89            await base.OnInitialize();
 
   91            if (this.navigationArguments is not 
null)
 
   93                if (this.navigationArguments.Uri?.EncryptedMessage is not 
null)
 
   95                    if (this.navigationArguments.Uri.EncryptionPublicKey is 
null)
 
   96                        this.Message = Encoding.UTF8.GetString(this.navigationArguments.Uri.EncryptedMessage);
 
   99                        this.Message = await 
ServiceRef.
XmppService.TryDecryptMessage(this.navigationArguments.Uri.EncryptedMessage,
 
  100                        this.navigationArguments.Uri.EncryptionPublicKey, 
this.navigationArguments.Uri.Id, 
this.navigationArguments.Uri.From);
 
  102                    this.HasMessage = !
string.IsNullOrEmpty(this.Message);
 
  105                this.MessagePreset = !
string.IsNullOrEmpty(this.Message);
 
  106                this.CanEncryptMessage = this.navigationArguments.Uri?.ToType == 
EntityType.LegalId;
 
  107                this.EncryptMessage = this.CanEncryptMessage;
 
  114            this.uriToSend?.TrySetResult(
null);
 
  116            await base.OnDispose();
 
  131        private decimal? amount;
 
  137        [NotifyCanExecuteChangedFor(nameof(PayOnlineCommand))]
 
  138        [NotifyCanExecuteChangedFor(nameof(GenerateQrCodeCommand))]
 
  139        [NotifyCanExecuteChangedFor(nameof(SendPaymentCommand))]
 
  140        private bool amountOk;
 
  142        protected override void OnPropertyChanged(PropertyChangedEventArgs e)
 
  144            base.OnPropertyChanged(e);
 
  146            switch (e.PropertyName)
 
  148                case nameof(this.IsConnected):
 
  149                    this.AcceptCommand.NotifyCanExecuteChanged();
 
  150                    this.PayOnlineCommand.NotifyCanExecuteChanged();
 
  151                    this.SubmitCommand.NotifyCanExecuteChanged();
 
  154                case nameof(this.HasQrCode):
 
  155                    this.PayOnlineCommand.NotifyCanExecuteChanged();
 
  156                    this.GenerateQrCodeCommand.NotifyCanExecuteChanged();
 
  157                    this.ShareCommand.NotifyCanExecuteChanged();
 
  160                case nameof(this.AmountText):
 
  161                    if (
CommonTypes.TryParse(this.AmountText, out decimal d) && d > 0)
 
  164                        this.AmountOk = 
true;
 
  167                        this.AmountOk = 
false;
 
  169                    this.AmountAndCurrency = this.AmountText + 
" " + this.Currency;
 
  172                case nameof(this.AmountExtraText):
 
  173                    if (string.IsNullOrEmpty(this.AmountExtraText))
 
  175                        this.AmountExtra = 
null;
 
  176                        this.AmountExtraOk = 
true;
 
  180                        this.AmountExtra = d;
 
  181                        this.AmountExtraOk = 
true;
 
  184                        this.AmountExtraOk = 
false;
 
  186                    this.AmountExtraAndCurrency = this.AmountExtraText + 
" " + this.Currency;
 
  195        [NotifyCanExecuteChangedFor(nameof(PayOnlineCommand))]
 
  196        [NotifyCanExecuteChangedFor(nameof(GenerateQrCodeCommand))]
 
  197        [NotifyCanExecuteChangedFor(nameof(SendPaymentCommand))]
 
  198        private string? amountText;
 
  204        private string? amountAndCurrency;
 
  210        private bool amountPreset;
 
  216        private decimal? amountExtra;
 
  222        [NotifyCanExecuteChangedFor(nameof(PayOnlineCommand))]
 
  223        [NotifyCanExecuteChangedFor(nameof(GenerateQrCodeCommand))]
 
  224        [NotifyCanExecuteChangedFor(nameof(SendPaymentCommand))]
 
  225        private bool amountExtraOk;
 
  231        [NotifyCanExecuteChangedFor(nameof(PayOnlineCommand))]
 
  232        [NotifyCanExecuteChangedFor(nameof(GenerateQrCodeCommand))]
 
  233        [NotifyCanExecuteChangedFor(nameof(SendPaymentCommand))]
 
  234        private string? amountExtraText;
 
  240        private string? amountExtraAndCurrency;
 
  246        private bool amountExtraPreset;
 
  252        private string? currency;
 
  258        private DateTime created;
 
  264        private DateTime expires;
 
  270        private string? expiresStr;
 
  282        private string? from;
 
  300        private bool toPreset;
 
  312        private string? friendlyName;
 
  318        private bool complete;
 
  324        private string? message;
 
  330        private bool encryptMessage;
 
  336        private bool canEncryptMessage;
 
  342        private bool hasMessage;
 
  348        private bool messagePreset;
 
  354        [NotifyCanExecuteChangedFor(nameof(PayOnlineCommand))]
 
  355        [NotifyCanExecuteChangedFor(nameof(GenerateQrCodeCommand))]
 
  356        [NotifyCanExecuteChangedFor(nameof(SendPaymentCommand))]
 
  357        private bool notPaid;
 
  363        private string? eDalerFrontGlyph;
 
  369        private string? eDalerBackGlyph;
 
  377        private async Task FromClick()
 
  381                string? Value = this.From;
 
  385                if ((Value.StartsWith(
"http://", StringComparison.CurrentCultureIgnoreCase) ||
 
  386                    Value.StartsWith(
"https://", StringComparison.CurrentCultureIgnoreCase)) &&
 
  387                    System.Uri.TryCreate(Value, UriKind.Absolute, out Uri? Uri) && await Launcher.TryOpenAsync(Uri))
 
  392                if (System.Uri.TryCreate(
"https://" + Value, UriKind.Absolute, out Uri) && await Launcher.TryOpenAsync(Uri))
 
  395                await Clipboard.SetTextAsync(Value);
 
  409        [RelayCommand(CanExecute = nameof(IsConnected))]
 
  410        private async Task Accept()
 
  414                if (this.Uri is 
null)
 
  443        [RelayCommand(CanExecute = nameof(CanPayOnline))]
 
  444        private async Task PayOnline()
 
  460                if (this.EncryptMessage && this.ToType == 
EntityType.LegalId)
 
  466                            this.Currency ?? 
string.Empty, 3, this.Message ?? 
string.Empty);
 
  476                        MainThread.BeginInvokeOnMainThread(async () =>
 
  479                                this.To, Guid.NewGuid().ToString(), 
ServiceRef.
Localizer[nameof(AppResources.EncryptedPayment)]));
 
  493                    Uri = await 
ServiceRef.
XmppService.CreateFullEDalerPaymentUri(this.To!, this.Amount ?? 0, this.AmountExtra,
 
  494                        this.Currency!, 3, this.Message ?? 
string.Empty);
 
  500                this.NotPaid = 
false;
 
  529        [RelayCommand(CanExecute = nameof(CanGenerateQrCode))]
 
  530        private async Task GenerateQrCode()
 
  546                if (this.EncryptMessage && this.ToType == 
EntityType.LegalId)
 
  550                        this.Currency ?? 
string.Empty, 3, this.Message ?? 
string.Empty);
 
  554                    Uri = await 
ServiceRef.
XmppService.CreateFullEDalerPaymentUri(this.To ?? 
string.Empty, this.Amount ?? 0, this.AmountExtra,
 
  555                        this.Currency ?? 
string.Empty, 3, this.Message ?? 
string.Empty);
 
  563                    MainThread.BeginInvokeOnMainThread(async () =>
 
  565                        this.GenerateQrCode(Uri);
 
  567                        if (this.shareQrCode is not 
null)
 
  568                            await this.shareQrCode.ShowQrCode();
 
  579        private bool CanPayOnline => this.AmountOk && this.AmountExtraOk && !this.HasQrCode && this.IsConnected && this.NotPaid; 
 
  580        private bool CanGenerateQrCode => this.AmountOk && this.AmountExtraOk && !this.HasQrCode && this.NotPaid; 
 
  581        private bool CanShare => this.HasQrCode;
 
  586        [RelayCommand(CanExecute = nameof(CanShare))]
 
  587        private async Task Share()
 
  589            if (this.QrCodeBin is 
null)
 
  594                string? Message = this.Message?? this.AmountAndCurrency;
 
  596                ServiceRef.PlatformSpecific.ShareImage(this.QrCodeBin,
 
  597                    string.Format(CultureInfo.CurrentCulture, Message ?? 
string.Empty, 
this.Amount, 
this.Currency),
 
  610        [RelayCommand(CanExecute = nameof(IsConnected))]
 
  611        private async Task Submit()
 
  613            if (this.Uri is 
null)
 
  643        private async Task ShowCode()
 
  645            if (this.Uri is 
null)
 
  655                    MainThread.BeginInvokeOnMainThread(async () =>
 
  657                        this.GenerateQrCode(this.Uri);
 
  659                        if (this.shareQrCode is not 
null)
 
  660                            await this.shareQrCode.ShowQrCode();
 
  671        private bool CanSendPayment()
 
  673            return this.uriToSend is not 
null && this.AmountOk && this.AmountExtraOk && this.NotPaid;
 
  679        [RelayCommand(CanExecute = nameof(CanSendPayment))]
 
  680        private async Task SendPayment()
 
  696                if (this.EncryptMessage && this.ToType == 
EntityType.LegalId)
 
  700                        this.Currency!, 3, this.Message ?? 
string.Empty);
 
  704                    Uri = await 
ServiceRef.
XmppService.CreateFullEDalerPaymentUri(this.To!, this.Amount ?? 0, this.AmountExtra,
 
  705                        this.Currency!, 3, this.Message ?? 
string.Empty);
 
  711                this.uriToSend?.TrySetResult(Uri);
 
  738                    case "AmountExtraText":
 
  751        #region ILinkableView 
Represents a transaction in the eDaler network.
The Application class, representing an instance of the Neuro-Access app.
static Task< bool > AuthenticateUser(AuthenticationPurpose Purpose, bool Force=false)
Authenticates the user using the configured authentication method.
Base class that references services in the app.
static ILogService LogService
Log service.
static INetworkService NetworkService
Network service.
static IUiService UiService
Service serializing and managing UI-related tasks.
static ITagProfile TagProfile
TAG Profile service.
static IStringLocalizer Localizer
Localization service
static IXmppService XmppService
The XMPP service for XMPP communication.
Converts values to strings.
static string ToString(decimal Money)
Converts a monetary value to a string, removing any round-off errors.
bool IsAppearing
Returns true if the view model is shown.
virtual async Task GoBack()
Method called when user wants to navigate to the previous screen.
Holds navigation parameters for the calculator.
A page that allows the user to calculate the value of a numerical input field.
A view model that holds the XMPP state.
Holds navigation parameters specific to eDaler URIs.
string? FriendlyName
Optional Friendly Name associated with URI
TaskCompletionSource< string?>? UriToSend
Task Completion Source in case the URI being built is to be returned to the parent page.
EDalerUri? Uri
The edaler URI
The view model to bind to for when displaying the contents of an eDaler URI.
override async Task OnInitialize()
Method called when view is initialized for the first time. Use this method to implement registration ...
async Task OpenCalculator(object Parameter)
Opens the calculator for calculating the value of a numerical property.
EDalerUriViewModel(IShareQrCode? ShareQrCode, EDalerUriNavigationArgs? Args)
The view model to bind to for when displaying the contents of an eDaler URI.
override Task< string > Title
Title of the current view
override async Task OnDispose()
Method called when the view is disposed, and will not be used more. Use this method to unregister eve...
Helps with parsing of commong data types.
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Abstract base class for contractual parameters
The requesting entity does not possess the necessary permissions to perform an action that only certa...
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.
Interface for pages with a share button.
EntityType
Type of entity referred to in transaction.
BackMethod
Navigation Back Method
AuthenticationPurpose
Purpose for requesting the user to authenticate itself.
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.