11using System.Collections.ObjectModel;
12using CommunityToolkit.Mvvm.ComponentModel;
14using CommunityToolkit.Mvvm.Input;
18using CommunityToolkit.Maui.Core.Extensions;
30 private readonly TaskCompletionSource<Contract?>? selection;
31 private Contract? selectedContract =
null;
32 private readonly Dictionary<string, SelectableTag> tagMap =
new(StringComparer.OrdinalIgnoreCase);
39 private readonly
string AllCategory =
"All";
40 private readonly
int contractBatchSize = 10;
42 private int loadedContracts;
43 private string currentCategory;
48 public ObservableCollection<SelectableTag>
FilterTags {
get;
set; } =
new();
54 private int hasMore = 0;
60 private bool canShareTemplate;
71 this.loadedContracts = 0;
73 this.currentCategory = this.AllCategory;
77 this.contractsListMode = Args.
Mode;
81 switch (this.contractsListMode)
86 this.CanShareTemplate =
false;
92 this.CanShareTemplate =
true;
98 this.CanShareTemplate =
true;
107 await base.OnInitializeAsync();
110 this.ShowContractsMissing =
false;
112 await this.LoadCategories();
115 MainThread.BeginInvokeOnMainThread(() =>
117 if (this.tagMap.TryGetValue(
this.AllCategory, out
SelectableTag? allTag))
119 allTag.IsSelected = true;
123 SelectableTag all = new(this.AllCategory, true);
124 this.tagMap[this.AllCategory] = all;
125 this.FilterTags.Insert(0, all);
129 this.currentCategory = this.AllCategory;
131 await this.LoadContracts();
133 this.ShowContractsMissing = this.Contracts.Count < 1;
139 await base.OnAppearingAsync();
141 if (this.selection is not
null && this.selection.Task.IsCompleted)
153 this.ShowContractsMissing =
false;
156 this.selection?.TrySetResult(this.selectedContract);
158 await base.OnDisposeAsync();
165 private string? title;
171 private string? description;
183 private bool showContractsMissing;
188 public ObservableCollection<ContractModel>
Contracts {
get; } = [];
193 [RelayCommand(AllowConcurrentExecutions =
false)]
194 private async Task ContractSelected(
object? parameter)
219 private async Task OpenFilterPopup()
223 if (selectedTag is not
null && !
string.Equals(selectedTag.Category,
this.currentCategory, StringComparison.OrdinalIgnoreCase))
224 await this.FilterChanged(selectedTag);
230 [RelayCommand(AllowConcurrentExecutions =
false)]
231 private async Task FilterChanged(
object? parameter)
233 if (parameter is SelectableTag Tag)
235 bool wasSelected = Tag.IsSelected;
240 t.IsSelected = t.Category == this.AllCategory;
241 if (
string.Equals(t.Category,
this.AllCategory, StringComparison.OrdinalIgnoreCase))
242 this.TagSelected?.Invoke(t);
245 this.currentCategory = this.AllCategory;
249 foreach (SelectableTag t
in this.FilterTags)
250 t.IsSelected = (t == Tag);
252 this.currentCategory = Tag.Category;
253 this.TagSelected?.Invoke(Tag);
256 await this.ApplySearchFilter();
265 string? previousCategory = this.currentCategory;
269 if (
string.IsNullOrEmpty(text))
273 Tag.IsSelected =
false;
275 this.FilterTags[0].IsSelected =
true;
276 selectedTag = this.FilterTags[0];
277 this.currentCategory = this.AllCategory;
284 if (Tag.Category.Contains(text ??
string.Empty, StringComparison.OrdinalIgnoreCase) && !found)
287 Tag.IsSelected =
true;
289 this.currentCategory = Tag.Category;
293 Tag.IsSelected =
false;
298 if (!
string.Equals(previousCategory, this.currentCategory, StringComparison.OrdinalIgnoreCase))
300 if (selectedTag is not
null)
301 this.TagSelected?.Invoke(selectedTag);
303 this.ApplySearchFilter().ConfigureAwait(
false);
310 private async Task ApplySearchFilter()
312 await MainThread.InvokeOnMainThreadAsync(async () =>
315 this.loadedContracts = 0;
319 await this.LoadContracts();
333 bool Delete = await MainThread.InvokeOnMainThreadAsync(async () =>
343 await this.LoadContracts();
352 ViewContractNavigationArgs Args =
new(Ref,
false);
353 await MainThread.InvokeOnMainThreadAsync(async () =>
365 await MainThread.InvokeOnMainThreadAsync(async () =>
369 this.selection?.TrySetResult(
Contract);
392 private async Task ShareTemplateQR(
object? parameter)
401 string ContractName = Model.
Category;
403 if (
string.IsNullOrEmpty(ContractUri))
408 byte[] QrBytes = Services.UI.QR.QrCode.GeneratePng(ContractUri, Width, Height);
422 private async Task LoadCategories()
426 object Categories = await
Expression.
EvalAsync($
"select distinct Category from NeuroAccessMaui.Services.Contracts.ContractReference where IsTemplate={this.contractsListMode != ContractsListMode.Contracts}");
428 if (Categories is not
object[] Items)
431 foreach (
object Item
in Items)
433 if (Item is
string category && !
string.IsNullOrWhiteSpace(category))
435 MainThread.BeginInvokeOnMainThread(() =>
437 if (!this.tagMap.ContainsKey(category))
439 SelectableTag NewTag = new(category, false);
440 this.tagMap[category] = NewTag;
441 this.FilterTags.Add(NewTag);
456 [RelayCommand(AllowConcurrentExecutions =
false)]
457 private async Task LoadMoreContracts()
459 await this.LoadContracts();
465 private async Task LoadContracts()
469 IEnumerable<ContractReference>? ContractReferences = await this.LoadFromDatabase();
471 if (ContractReferences is
null)
481 MainThread.BeginInvokeOnMainThread(() =>
489 this.loadedContracts += this.contractBatchSize;
492 if (this.HasMore == -1 && this.contractsListMode ==
ContractsListMode.TokenCreationTemplates)
502 if (Existing is
null)
509 ContractId = Contract.ContractId
517 MainThread.BeginInvokeOnMainThread(() =>
520 this.OnPropertyChanged(nameof(this.ShowContractsMissing));
533 private async Task<IEnumerable<ContractReference>?> LoadFromDatabase()
535 IEnumerable<ContractReference> ContractReferences;
537 if (this.currentCategory == this.AllCategory)
539 switch (this.contractsListMode)
547 this.HasMore = (ContractReferences.Count() < this.contractBatchSize) ? -1 : 0;
556 this.HasMore = (ContractReferences.Count() < this.contractBatchSize) ? -1 : 0;
565 this.HasMore = (ContractReferences.Count() < this.contractBatchSize) ? -1 : 0;
574 switch (this.contractsListMode)
583 this.HasMore = (ContractReferences.Count() < this.contractBatchSize) ? -1 : 0;
593 this.HasMore = (ContractReferences.Count() < this.contractBatchSize) ? -1 : 0;
603 this.HasMore = (ContractReferences.Count() < this.contractBatchSize) ? -1 : 0;
611 return ContractReferences;
623 private string category;
628 private bool isSelected;
637 this.category = Category;
638 this.isSelected = IsSelected;
static readonly string[] TokenCreationTemplates
Array of contract templates for creating tokens.
const int DefaultImageHeight
The default height to use when generating QR Code images.
const int DefaultImageWidth
The default width to use when generating QR Code images.
A set of never changing property constants and helpful values.
A strongly-typed resource class, for looking up localized strings, etc.
static string Yes
Looks up a localized string similar to Yes.
static string ReferencedID
Looks up a localized string similar to Referenced ID.
static string ContractCouldNotBeFound
Looks up a localized string similar to Contract could not be found, it could have been deleted....
static string Contracts
Looks up a localized string similar to Contracts.
static string ContractTemplates
Looks up a localized string similar to Contract Templates.
static string ContractTemplatesInfoText
Looks up a localized string similar to Below is a list of contract templates that you have used,...
static string ContractsInfoText
Looks up a localized string similar to Below is a list of contracts that you have created or signed,...
static string TokenCreationTemplates
Looks up a localized string similar to Token Templates.
static string No
Looks up a localized string similar to No.
static string ErrorTitle
Looks up a localized string similar to An error has occurred.
static string TokenCreationTemplatesInfoText
Looks up a localized string similar to Below is a list of token templates that you have used,...
Contains a local reference to a contract that the user has created or signed.
async Task< Contract?> GetContract()
Gets a parsed contract.
async Task SetContract(Contract Contract)
Sets a parsed contract.
CaseInsensitiveString? ContractId
Contract reference
Base class that references services in the app.
static ILogService LogService
Log service.
static IUiService UiService
Service serializing and managing UI-related tasks.
static INavigationService NavigationService
The navigation service for navigating between pages.
static IPopupService PopupService
Popup service for presenting application popups.
static IContractOrchestratorService ContractOrchestratorService
Contract orchestrator service.
static IReportingStringLocalizer Localizer
Localization service
static IXmppService XmppService
The XMPP service for XMPP communication.
A base class for all view models, inheriting from the BindableObject. NOTE: using this class requir...
virtual async Task GoBack()
Method called when user wants to navigate to the previous screen.
Holds navigation parameters specific to views displaying a list of contacts.
SelectContractAction Action
Action to take when a contact has been selected.
ContractsListMode Mode
What list of contracts to display.
TaskCompletionSource< Contract?>? Selection
Selection source, if selecting identity.
Container class representing a selectable category tag.
void ToggleSelection()
Toggles the selection state of the tag.
SelectableTag(string Category, bool IsSelected)
Creates a new SelectableTag.
View model responsible for presenting and filtering a list of contracts and templates....
override async Task OnDisposeAsync()
Method called when the view is disposed, and will not be used more. Use this method to unregister eve...
ObservableCollection< SelectableTag > FilterTags
Collection of available filter tags for categories. One tag can be selected at a time.
void UpdateSearch(string? text)
Should be called by page on text change.
override async Task OnInitializeAsync()
Method called when view is initialized for the first time. Use this method to implement registration ...
override async Task OnAppearingAsync()
Method called when view is appearing on the screen.
MyContractsViewModel(MyContractsNavigationArgs? Args)
Creates an instance of the MyContractsViewModel class.
ObservableCollection< ContractModel > Contracts
Holds the flat list of contracts to display.
async Task ContractSelectedAsync(ContractModel Model)
Handle contract selection.
Action< SelectableTag >? TagSelected
Event raised when a filter tag becomes selected. Consumers can react (e.g., scroll into view).
void ContractSelected(ContractModel Model)
Legacy helper maintained for compatibility with existing callers.
The data model for a contract.
string ContractIdUriString
URI string for the contract ID, used for sharing and QR codes.
string Category
Displayable category for the contract.
ContractReference ContractRef
A reference to the contract.
A page that displays a specific contract.
Contains the definition of a contract
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task< IEnumerable< object > > FindDelete(string Collection, params string[] SortOrder)
Finds objects in a given collection and deletes them in the same atomic operation.
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.
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.
Class managing a script expression.
static Task< object > EvalAsync(string Script)
Evaluates script, in string format.
Task OpenContract(string ContractId, string Purpose, Dictionary< CaseInsensitiveString, object >? ParameterValues)
Downloads the specified Contract and opens the corresponding page in the app to show it.
Task GoToAsync(string Route)
Navigates to the specified route and pushes the page onto the navigation stack.
Task< bool > DisplayAlert(string Title, string Message, string? Accept=null, string? Cancel=null)
Displays an alert/message box to the user.
BackMethod
Navigation Back Method
ContractsListMode
What list of contracts to display
SelectContractAction
Actions to take when a contact has been selected.