1using CommunityToolkit.Mvvm.ComponentModel;
2using CommunityToolkit.Mvvm.Input;
10using System.Collections.ObjectModel;
24 private readonly PhotosLoader photosLoader;
25 private readonly
string? requestorFullJid;
26 private readonly
string? requestedIdentityId;
27 private readonly
string? petitionId;
28 private readonly
string? bareJid;
36 this.photosLoader =
new PhotosLoader(this.
Photos);
40 this.RequestorIdentity = Args.RequestorIdentity;
41 this.requestorFullJid = Args.RequestorFullJid;
42 this.requestedIdentityId = Args.RequestedIdentityId;
43 this.petitionId = Args.PetitionId;
44 this.Purpose = Args.Purpose;
45 this.ContentToSign = Args.ContentToSign;
47 if (!
string.IsNullOrEmpty(this.requestorFullJid))
49 else if (Args.RequestorIdentity is not
null)
50 this.bareJid = Args.RequestorIdentity.GetJid();
52 this.bareJid =
string.Empty;
61 View.BindingContext =
this;
62 this.stepViews[Step] = View;
74 private readonly SortedDictionary<ReviewStep, BaseContentView> stepViews = [];
79 await base.OnInitializeAsync();
81 if (!
string.IsNullOrEmpty(this.bareJid))
88 Info.
LegalId !=
this.RequestorIdentity?.Id &&
93 Info.LegalId = this.LegalId;
101 this.ThirdPartyInContacts = Info is not
null;
104 this.AssignProperties();
105 this.NotifyCommandsCanExecuteChanged();
110 private async
void ReloadPhotos()
114 this.photosLoader.CancelLoadPhotos();
119 if (Attachments is not
null)
121 First = await this.photosLoader.LoadPhotos(Attachments,
SignWith.LatestApprovedId);
123 this.FirstPhotoSource = First?.Source;
124 this.FirstPhotoRotation = First?.Rotation ?? 0;
129 if (Attachments is not
null)
131 First = await this.photosLoader.LoadPhotos(Attachments,
SignWith.LatestApprovedId);
133 this.MyFirstPhotoSource = First?.Source;
134 this.MyFirstPhotoRotation = First?.Rotation ?? 0;
146 this.photosLoader.CancelLoadPhotos();
148 await base.OnDisposeAsync();
154 public ObservableCollection<Photo>
Photos {
get; } = [];
164 return MainThread.InvokeOnMainThreadAsync(async () =>
166 await base.XmppService_ConnectionStateChanged(Sender, NewState);
168 this.NotifyCommandsCanExecuteChanged();
174 base.SetIsBusy(IsBusy);
175 this.NotifyCommandsCanExecuteChanged();
178 private void NotifyCommandsCanExecuteChanged()
180 this.AcceptCommand.NotifyCanExecuteChanged();
181 this.DeclineCommand.NotifyCanExecuteChanged();
182 this.AuthenticateReviewerCommand.NotifyCanExecuteChanged();
192 if (!this.IsConnected || this.IsBusy || this.ContentToSign is
null)
195 if (this.
HasPhoto && !this.IsPhotoOk)
198 if (this.
HasName && !this.IsNameOk)
219 if (!this.AcknowledgeResponsibility || !this.ConsentProcessing || !this.ConfirmCorrect)
226 [RelayCommand(CanExecute = nameof(
CanAccept))]
227 private Task Accept()
229 return this.Accept(
true);
232 private async Task Accept(
bool GoBackIfOk)
234 if (this.ContentToSign is
null || !await this.authenticationService.AuthenticateUserAsync(
AuthenticationPurpose.AcceptPeerReview))
242 this.petitionId!,
this.requestorFullJid!,
true);
245 if (Succeeded && GoBackIfOk)
252 public bool CanDecline => this.IsConnected && !this.IsBusy && this.ContentToSign is not
null;
254 [RelayCommand(CanExecute = nameof(
CanDecline))]
255 private Task Decline()
257 return this.Decline(
true);
260 private async Task Decline(
bool GoBackIfOk)
262 if (this.ContentToSign is
null || !await this.authenticationService.AuthenticateUserAsync(
AuthenticationPurpose.DeclinePeerReview))
270 this.petitionId!,
this.requestorFullJid!,
false);
273 if (Succeeded && GoBackIfOk)
278 private async Task Ignore()
283 [RelayCommand(CanExecute = nameof(IsPhotoOk))]
284 private void AcceptPhoto()
290 [RelayCommand(CanExecute = nameof(IsNameOk))]
291 private void AcceptName()
297 [RelayCommand(CanExecute = nameof(IsPnrOk))]
298 private void AcceptPnr()
304 [RelayCommand(CanExecute = nameof(IsNationalityOk))]
305 private void AcceptNationality()
307 if (this.IsNationalityOk)
311 [RelayCommand(CanExecute = nameof(IsBirthDateOk))]
312 private void AcceptBirthDate()
314 if (this.IsBirthDateOk)
318 [RelayCommand(CanExecute = nameof(IsGenderOk))]
319 private void AcceptGender()
325 [RelayCommand(CanExecute = nameof(IsPersonalAddressInfoOk))]
326 private void AcceptPersonalAddressInfo()
328 if (this.IsPersonalAddressInfoOk)
332 [RelayCommand(CanExecute = nameof(IsOrganizationalInfoOk))]
333 private void AcceptOrganizationalInfo()
335 if (this.IsOrganizationalInfoOk)
340 private void AcceptConsent()
346 private void NextPage()
354 IsVisible = Current
switch
357 ReviewStep.Name => this.
HasName,
369 this.CurrentStep = Current;
372 private bool PrevPage()
383 IsVisible = Current
switch
386 ReviewStep.Name => this.
HasName,
398 this.CurrentStep = Current;
406 public bool HasPhoto => this.FirstPhotoSource is not
null;
411 public bool HasName => !
string.IsNullOrEmpty(this.FullName);
441 !
string.IsNullOrEmpty(this.Address) ||
442 !
string.IsNullOrEmpty(this.Address2) ||
443 !
string.IsNullOrEmpty(this.Area) ||
444 !
string.IsNullOrEmpty(this.City) ||
445 !
string.IsNullOrEmpty(this.Region) ||
446 !
string.IsNullOrEmpty(this.CountryCode);
458 !
string.IsNullOrEmpty(this.OrgName) ||
459 !
string.IsNullOrEmpty(this.OrgNumber) ||
460 !
string.IsNullOrEmpty(this.OrgDepartment) ||
461 !
string.IsNullOrEmpty(this.OrgRole) ||
462 !
string.IsNullOrEmpty(this.OrgAddress) ||
463 !
string.IsNullOrEmpty(this.OrgAddress2) ||
464 !
string.IsNullOrEmpty(this.OrgArea) ||
465 !
string.IsNullOrEmpty(this.OrgCity) ||
466 !
string.IsNullOrEmpty(this.OrgRegion) ||
467 !
string.IsNullOrEmpty(this.OrgCountryCode);
477 private DateTime created;
483 private DateTime? updated;
489 private string? legalId;
501 private DateTime? from;
507 private DateTime? to;
513 [NotifyPropertyChangedFor(nameof(FullName))]
518 private string? firstName;
524 [NotifyPropertyChangedFor(nameof(FullName))]
529 private string? middleNames;
535 [NotifyPropertyChangedFor(nameof(FullName))]
540 private string? lastNames;
547 private string? personalNumber;
556 if (
string.IsNullOrEmpty(this.CountryCode) ||
560 return this.PersonalNumber;
563 return Country.EmojiInfo.Unicode +
"\t" + this.PersonalNumber;
570 [
System.Diagnostics.CodeAnalysis.SuppressMessage(
"Performance",
"CA1822:Mark members as static",
571 Justification =
"Must be instance property for view binding to work.")]
582 if (
string.IsNullOrEmpty(MyCountryCode) ||
586 return MyPersonalNumber;
589 return MyCountry.EmojiInfo.Unicode +
"\t" + MyPersonalNumber;
597 private string? address;
603 private string? address2;
609 private string? zipCode;
615 private string? area;
621 private string? city;
627 private string? region;
634 private string? countryCode;
641 private string? nationalityCode;
650 if (
string.IsNullOrEmpty(this.NationalityCode) ||
654 return this.NationalityCode;
657 return Country.EmojiInfo.Unicode +
"\t" + Country.Name;
666 private string? gender;
675 if (
string.IsNullOrEmpty(this.
Gender) ||
690 private DateTime? birthDate;
696 private string? orgName;
702 private string? orgNumber;
708 private string? orgDepartment;
714 private string? orgRole;
720 private string? orgAddress;
726 private string? orgAddress2;
732 private string? orgZipCode;
738 private string? orgArea;
744 private string? orgCity;
750 private string? orgRegion;
756 private string? orgCountryCode;
768 public GridLength
OrgRowHeight => this.HasOrg ? GridLength.Auto :
new GridLength(0, GridUnitType.Absolute);
774 private string? phoneNr;
780 private string? eMail;
786 private string? deviceId;
792 private bool isApproved;
798 private string? purpose;
804 private byte[]? contentToSign;
810 private bool thirdPartyInContacts;
816 private ImageSource? firstPhotoSource;
822 private int firstPhotoRotation;
828 private ImageSource? myFirstPhotoSource;
834 private int myFirstPhotoRotation;
840 [
System.Diagnostics.CodeAnalysis.SuppressMessage(
"Performance",
"CA1822:Mark members as static",
841 Justification =
"Must be instance property for view binding to work.")]
848 [NotifyCanExecuteChangedFor(nameof(AcceptPhotoCommand))]
849 private bool isPhotoOk;
855 [NotifyCanExecuteChangedFor(nameof(AcceptNameCommand))]
856 private bool isNameOk;
862 [NotifyCanExecuteChangedFor(nameof(AcceptPnrCommand))]
863 private bool isPnrOk;
869 [NotifyCanExecuteChangedFor(nameof(AcceptNationalityCommand))]
870 private bool isNationalityOk;
876 [NotifyCanExecuteChangedFor(nameof(AcceptBirthDateCommand))]
877 private bool isBirthDateOk;
883 [NotifyCanExecuteChangedFor(nameof(AcceptGenderCommand))]
884 private bool isGenderOk;
890 [NotifyCanExecuteChangedFor(nameof(AcceptPersonalAddressInfoCommand))]
891 private bool isPersonalAddressInfoOk;
897 [NotifyCanExecuteChangedFor(nameof(AcceptOrganizationalInfoCommand))]
898 private bool isOrganizationalInfoOk;
904 [NotifyCanExecuteChangedFor(nameof(AcceptConsentCommand))]
906 private bool acknowledgeResponsibility;
912 [NotifyCanExecuteChangedFor(nameof(AcceptConsentCommand))]
914 private bool consentProcessing;
920 [NotifyCanExecuteChangedFor(nameof(AcceptConsentCommand))]
922 private bool confirmCorrect;
928 private bool showDetails;
933 public bool IsConsentOk => this.AcknowledgeResponsibility && this.ConsentProcessing && this.ConfirmCorrect;
961 this.IsPhotoOk = !this.IsPhotoOk;
970 this.IsNameOk = !this.IsNameOk;
979 this.IsPnrOk = !this.IsPnrOk;
988 this.IsNationalityOk = !this.IsNationalityOk;
997 this.IsBirthDateOk = !this.IsBirthDateOk;
1006 this.IsGenderOk = !this.IsGenderOk;
1015 this.IsPersonalAddressInfoOk = !this.IsPersonalAddressInfoOk;
1024 this.IsOrganizationalInfoOk = !this.IsOrganizationalInfoOk;
1033 this.AcknowledgeResponsibility = !this.AcknowledgeResponsibility;
1042 this.ConsentProcessing = !this.ConsentProcessing;
1051 this.ConfirmCorrect = !this.ConfirmCorrect;
1060 this.ShowDetails = !this.ShowDetails;
1065 private void AssignProperties()
1093 if (!
string.IsNullOrEmpty(BirthDayStr) &&
int.TryParse(BirthDayStr, out
int BirthDay) &&
1094 !
string.IsNullOrEmpty(BirthMonthStr) &&
int.TryParse(BirthMonthStr, out
int BirthMonth) &&
1095 !
string.IsNullOrEmpty(BirthYearStr) &&
int.TryParse(BirthYearStr, out
int BirthYear))
1099 this.BirthDate =
new DateTime(BirthYear, BirthMonth, BirthDay);
1101 catch (Exception ex)
1104 this.BirthDate =
null;
1120 !
string.IsNullOrEmpty(this.OrgName) ||
1121 !
string.IsNullOrEmpty(this.OrgNumber) ||
1122 !
string.IsNullOrEmpty(this.OrgDepartment) ||
1123 !
string.IsNullOrEmpty(this.OrgRole) ||
1124 !
string.IsNullOrEmpty(this.OrgAddress) ||
1125 !
string.IsNullOrEmpty(this.OrgAddress2) ||
1126 !
string.IsNullOrEmpty(this.OrgZipCode) ||
1127 !
string.IsNullOrEmpty(this.OrgArea) ||
1128 !
string.IsNullOrEmpty(this.OrgCity) ||
1129 !
string.IsNullOrEmpty(this.OrgRegion) ||
1130 !
string.IsNullOrEmpty(this.OrgCountryCode);
1134 this.IsApproved = this.RequestorIdentity.State ==
IdentityState.Approved;
1138 this.Created = DateTime.MinValue;
1139 this.Updated =
null;
1157 this.BirthDate =
null;
1169 this.HasOrg =
false;
1173 this.IsApproved =
false;
1177 [RelayCommand(CanExecute = nameof(
CanAccept))]
1178 private async Task AuthenticateReviewer()
1182 if (await this.authenticationService.AuthenticateUserAsync(
AuthenticationPurpose.AuthenticateReviewer,
true))
1184 await this.Accept(
false);
1188 catch (Exception ex)
1201 if (!this.PrevPage())
1202 await base.GoBack();
1211 return base.GoBack();
1214 #region ILinkableView
XMPP Protocol Properties.
const string PersonalNumber
Personal number
const string OrgAddress2
Organization Address line 2
const string DeviceId
Device ID
const string Country
Country
const string OrgArea
Organization Area
const string Region
Region
const string OrgRegion
Organization Region
const string Nationality
Nationality
const string ZipCode
Zip Code
const string BirthYear
Birth Year
const string OrgCity
Organization City
const string OrgRole
Organization Role
const string Phone
Phone number
const string EMail
e-Mail address
const string OrgZipCode
Organization Zip Code
const string MiddleNames
Middle names
const string BirthDay
Birth Day
const string OrgCountry
Organization Country
const string OrgDepartment
Organization Department
const string Address2
Address line 2
const string OrgAddress
Organization Address line 1
const string Address
Address line 1
const string LastNames
Last names
const string OrgNumber
Organization number
const string BirthMonth
Birth Month
const string FirstName
First name
const string Gender
Gender
const string OrgName
Organization name
A set of never changing property constants and helpful values.
const string NotAvailableValue
A generic "no value available" string.
A strongly-typed resource class, for looking up localized strings, etc.
static string UnableToSignReview
Looks up a localized string similar to Unable to sign the review..
static string PeerReviewConfirmCorrectText
Looks up a localized string similar to I confirm that the information provided by {0} is correct....
static string PeerReviewPhotoText
Looks up a localized string similar to The photo clearly represents {0}..
static string ReviewApproved
Looks up a localized string similar to You have now approved the information provided by {0}....
static string PeerReviewAuthenticationText
Looks up a localized string similar to By authenticating myself and signing the review,...
static string ErrorTitle
Looks up a localized string similar to An error has occurred.
Conversion between Country Names and ISO-3166-1 country codes.
static bool TryGetCountryByCode(string? CountryCode, [NotNullWhen(true)] out ISO_3166_Country? Country)
Tries to get the country, given its country code.
Static class containing ISO 5218 gender codes
static bool LetterToGender(string Letter, out ISO_5218_Gender? Gender)
Tries to get the gender label corresponding to an ISO 5218 gender code.
Base class that references services in the app.
static IServiceProvider Provider
The service provider for the app. This is set before the app is started, and will be used to resolve ...
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 IReportingStringLocalizer Localizer
Localization service
static IXmppService XmppService
The XMPP service for XMPP communication.
The view model to bind to when displaying petitioning of an identity in a view or page.
string ReviewApproved
Information that peer review has been approved.
bool HasGender
If request contains gender
string? MyPersonalNumberWithFlag
Personal number of reviewer with country flag.
void ToggleAcknowledgeResponsibility()
Toggles AcknowledgeResponsibility
string PeerReviewConfirmCorrectText
Instruction to reviewer when confirming reviewed information is correct.
bool HasName
If request contains a full name
string PhotoReviewText
Instruction to reviewer when reviewing photo.
void ToggleShowDetails()
Toggles ShowDetails
void ToggleIsPnrOk()
Toggles IsPnrOk
void ToggleIsOrganizationalInfoOk()
Toggles IsOrganizationalInfoOk
GridLength OrgRowHeight
If organization information is available.
bool CanAccept
If the user can accept the review.
override Task< string > Title
Title of the current view
bool HasBirthDate
If request contains birth date
string PeerReviewAuthenticationText
Instruction to reviewer when accepting peer review.
bool IsConsentOk
If proper consent and acknowledgement has been given.
void ToggleIsNationalityOk()
Toggles IsNationalityOk
string? NationalityWithFlag
Nationality with country flag.
bool HasPersonalAddressInfo
If request contains personal address information
string? PersonalNumberWithFlag
Personal number with country flag.
void AddView(ReviewStep Step, BaseContentView View)
Adds a view to the wizard dialog.
PetitionPeerReviewViewModel(PetitionPeerReviewNavigationArgs? Args)
Creates a new instance of the PetitionPeerReviewViewModel class.
void ToggleIsPhotoOk()
Toggles IsPhotoOk
override async Task GoBack()
Method called when user wants to navigate to the previous screen.
bool CanDecline
If the user can decline the review.
bool HasPersonalNumber
If request contains a personal number
string? GenderWithSymbol
Gender with Unicode symbol.
void ToggleIsGenderOk()
Toggles IsGenderOk
override async Task OnDisposeAsync()
Method called when the view is disposed, and will not be used more. Use this method to unregister eve...
void ToggleIsNameOk()
Toggles IsNameOk
void ToggleIsBirthDateOk()
Toggles IsBirthDateOk
bool HasNationality
If request contains nationality
LegalIdentity? RequestorIdentity
The identity of the requestor.
override Task XmppService_ConnectionStateChanged(object? Sender, XmppState NewState)
Listens to connection state changes from the XMPP server.
override void SetIsBusy(bool IsBusy)
Sets the IsBusy property.
ObservableCollection< Photo > Photos
The list of photos related to the identity being petitioned.
void ToggleIsPersonalAddressInfoOk()
Toggles IsPersonalAddressInfoOk
void ToggleConsentProcessing()
Toggles ConsentProcessing
bool HasPhoto
If request contains a photo
void ToggleConfirmCorrect()
Toggles ConfirmCorrect
bool HasOrganizationalInfo
If request contains organizational information
Task Close()
Closes the view.
override async Task OnInitializeAsync()
Method called when view is initialized for the first time. Use this method to implement registration ...
A view model that holds the XMPP state.
Contains a reference to an attachment assigned to a legal object.
DateTime From
From what point in time the legal identity is valid.
DateTime Updated
When the identity object was last updated
DateTime To
To what point in time the legal identity is valid.
DateTime Created
When the identity object was created
IdentityState State
Current state of identity
string Id
ID of the legal identity
Attachment[] Attachments
Attachments assigned to the legal identity.
Abstract base class of signatures
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 IDatabaseProvider Provider
Registered database provider.
static async Task Update(object Object)
Updates an object in the database.
Task Flush()
Persists any pending changes.
class ISO_3166_Country(string Name, string Alpha2, string Alpha3, int NumericCode, string DialCode, EmojiInfo? EmojiInfo=null)
Representation of an ISO3166-1 Country
class ISO_5218_Gender(string Gender, int Code, string Letter, string LocalizedNameId, char Unicode)
Contains one record of the ISO 5218 data set.
class Photo(byte[] Binary, int Rotation, Attachment? Attachment)
Class containing information about a photo.
ReviewStep
Steps in the peer-review process
AuthenticationPurpose
Purpose for requesting the user to authenticate itself.
IdentityState
Lists recognized legal identity states.
SignWith
Options on what keys to use when signing data.
Gender
Gender classification in a legal ID.
XmppState
State of XMPP connection.