Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
CanControlViewModel.cs
1using CommunityToolkit.Mvvm.ComponentModel;
2using CommunityToolkit.Mvvm.Input;
11using System.Collections.ObjectModel;
12using System.ComponentModel;
18using Waher.Things;
19
21{
25 public partial class CanControlViewModel : XmppViewModel
26 {
27 private readonly NotificationEvent? @event;
28 private readonly CanControlNavigationArgs? navigationArguments;
29
35 : base()
36 {
37 this.navigationArguments = Args;
38
39 this.Tags = [];
40 this.CallerTags = [];
41 this.Parameters = [];
42 this.RuleRanges = [];
43
44 if (Args is not null)
45 {
46 this.@event = Args.Event;
47 this.BareJid = Args.BareJid;
48 this.FriendlyName = Args.FriendlyName;
49 this.RemoteJid = Args.RemoteJid;
50 this.RemoteFriendlyName = Args.RemoteFriendlyName;
51 this.Key = Args.Key;
52 this.ProvisioningService = Args.ProvisioningService;
53 this.NodeId = Args.NodeId;
54 this.SourceId = Args.SourceId;
55 this.PartitionId = Args.PartitionId;
56
57 if (this.FriendlyName == this.BareJid)
58 this.FriendlyName = ServiceRef.Localizer[nameof(AppResources.NotAvailable)];
59
60 this.RemoteFriendlyNameAvailable = this.RemoteFriendlyName != this.RemoteJid;
61 if (!this.RemoteFriendlyNameAvailable)
62 this.RemoteFriendlyName = ServiceRef.Localizer[nameof(AppResources.NotAvailable)];
63 }
64 }
65
67 public override async Task OnInitializeAsync()
68 {
69 await base.OnInitializeAsync();
70
71 if (this.navigationArguments is not null)
72 {
73 this.Tags.Clear();
74 this.CallerTags.Clear();
75
76 ContactInfo Thing = await ContactInfo.FindByBareJid(this.BareJid ?? string.Empty);
77 if (Thing?.MetaData is not null)
78 {
79 foreach (Property Tag in Thing.MetaData)
80 this.Tags.Add(new HumanReadableTag(Tag));
81 }
82
83 ContactInfo Caller = await ContactInfo.FindByBareJid(this.RemoteJid ?? string.Empty);
84 this.CallerInContactsList = Caller is not null;
85 if (Caller?.MetaData is not null)
86 {
87 foreach (Property Tag in Caller.MetaData)
88 this.CallerTags.Add(new HumanReadableTag(Tag));
89 }
90
91 if (this.navigationArguments.UserTokens is not null && this.navigationArguments.UserTokens.Length > 0)
92 {
93 foreach (ProvisioningToken Token in this.navigationArguments.UserTokens)
94 this.CallerTags.Add(new HumanReadableTag(new Property(ServiceRef.Localizer[nameof(AppResources.User)], Token.FriendlyName ?? Token.Token)));
95
96 this.HasUser = true;
97 }
98
99 if (this.navigationArguments.ServiceTokens is not null && this.navigationArguments.ServiceTokens.Length > 0)
100 {
101 foreach (ProvisioningToken Token in this.navigationArguments.ServiceTokens)
103
104 this.HasService = true;
105 }
106
107 if (this.navigationArguments.DeviceTokens is not null && this.navigationArguments.DeviceTokens.Length > 0)
108 {
109 foreach (ProvisioningToken Token in this.navigationArguments.DeviceTokens)
110 this.CallerTags.Add(new HumanReadableTag(new Property(ServiceRef.Localizer[nameof(AppResources.Device)], Token.FriendlyName ?? Token.Token)));
111
112 this.HasDevice = true;
113 }
114
115 this.Parameters.Clear();
116
117 SortedDictionary<string, bool> PermittedParameters = [];
118 string[]? AllParameters = this.navigationArguments.AllParameters;
119
120 if (AllParameters is null && !string.IsNullOrEmpty(this.BareJid))
121 {
122 AllParameters = await CanControlNotificationEvent.GetAvailableParameterNames(this.BareJid,
123 new ThingReference(this.NodeId, this.SourceId, this.PartitionId));
124
125 if (AllParameters is not null && this.navigationArguments?.Event is not null)
126 {
127 this.navigationArguments.Event.AllParameters = AllParameters;
128 await Database.Update(this.navigationArguments.Event);
129 }
130 }
131
132 bool AllParametersPermitted = this.navigationArguments?.Parameters is null;
133
134 if (AllParameters is not null)
135 {
136 foreach (string Parameter in AllParameters)
137 PermittedParameters[Parameter] = AllParametersPermitted;
138 }
139
140 if (!AllParametersPermitted && this.navigationArguments?.Parameters is not null)
141 {
142 foreach (string Parameter in this.navigationArguments.Parameters)
143 PermittedParameters[Parameter] = true;
144 }
145
146 foreach (KeyValuePair<string, bool> P in PermittedParameters)
147 {
148 FieldReference Parameter = new(P.Key, P.Value);
149 this.Parameters.Add(Parameter);
150 }
151
152 this.RuleRanges.Clear();
154
155 if (this.HasUser)
156 this.RuleRanges.Add(new RuleRangeModel("User", ServiceRef.Localizer[nameof(AppResources.ToUser)]));
157
158 if (this.HasUser)
159 this.RuleRanges.Add(new RuleRangeModel("Service", ServiceRef.Localizer[nameof(AppResources.ToService)]));
160
161 if (this.HasUser)
162 this.RuleRanges.Add(new RuleRangeModel("Device", ServiceRef.Localizer[nameof(AppResources.ToDevice)]));
163
166
167 this.SelectedRuleRangeIndex = 0;
168 }
169 }
170
171 #region Properties
172
176 public ObservableCollection<HumanReadableTag> Tags { get; }
177
181 public ObservableCollection<HumanReadableTag> CallerTags { get; }
182
186 public ObservableCollection<FieldReference> Parameters { get; }
187
191 public ObservableCollection<RuleRangeModel> RuleRanges { get; }
192
196 [ObservableProperty]
197 private string? bareJid;
198
202 [ObservableProperty]
203 private string? friendlyName;
204
208 [ObservableProperty]
209 private string? remoteJid;
210
211
215 [ObservableProperty]
216 private string? remoteFriendlyName;
217
221 [ObservableProperty]
222 private bool remoteFriendlyNameAvailable;
223
227 [ObservableProperty]
228 private string? key;
229
233 [ObservableProperty]
234 private bool hasUser;
235
239 [ObservableProperty]
240 private bool hasService;
241
245 [ObservableProperty]
246 private bool hasDevice;
247
251 [ObservableProperty]
252 private string? provisioningService;
253
257 [ObservableProperty]
258 private bool callerInContactsList;
259
263 [ObservableProperty]
264 private int selectedRuleRangeIndex;
265
269 [ObservableProperty]
270 private string? nodeId;
271
275 [ObservableProperty]
276 private string? sourceId;
277
281 [ObservableProperty]
282 private string? partitionId;
283
284 #endregion
285
289 [RelayCommand]
290 private static Task Click(object obj)
291 {
292 if (obj is HumanReadableTag Tag)
293 return ViewClaimThingViewModel.LabelClicked(Tag.Name, Tag.Value, Tag.LocalizedValue);
294 else if (obj is string s)
295 return ViewClaimThingViewModel.LabelClicked(string.Empty, s, s);
296 else
297 return Task.CompletedTask;
298 }
299
303 [RelayCommand]
304 private async Task AddContact()
305 {
306 if (!this.CallerInContactsList)
307 {
308 ContactInfo Info = new()
309 {
310 BareJid = this.RemoteJid,
311 FriendlyName = (this.RemoteFriendlyNameAvailable ? this.RemoteFriendlyName : this.RemoteJid) ?? string.Empty
312 };
313
314 await Database.Insert(Info);
315
316 this.CallerInContactsList = true;
317 }
318 }
319
323 [RelayCommand]
324 private async Task RemoveContact()
325 {
326 if (this.CallerInContactsList && !string.IsNullOrEmpty(this.RemoteJid))
327 {
328 ContactInfo Info = await ContactInfo.FindByBareJid(this.RemoteJid);
329 if (Info is not null)
330 await Database.Delete(Info);
331
332 this.CallerInContactsList = false;
333 }
334 }
335
339 [RelayCommand(CanExecute = nameof(CanExecuteAccept))]
340 private void Accept()
341 {
342 this.Respond(true);
343 }
344
346 protected override void OnPropertyChanged(PropertyChangedEventArgs e)
347 {
348 base.OnPropertyChanged(e);
349
350 switch (e.PropertyName)
351 {
352 case nameof(this.IsConnected):
353 this.AcceptCommand.NotifyCanExecuteChanged();
354 break;
355 }
356 }
357
358 private bool CanExecuteAccept()
359 {
360 if (!this.IsConnected)
361 return false;
362
363 foreach (FieldReference Parameter in this.Parameters)
364 {
365 if (Parameter.Permitted)
366 return true;
367 }
368
369 return false;
370 }
371
375 [RelayCommand(CanExecute = nameof(IsConnected))]
376 private void Reject()
377 {
378 this.Respond(false);
379 }
380
381 private void Respond(bool Accepts)
382 {
383 if (this.SelectedRuleRangeIndex >= 0)
384 {
385 RuleRangeModel Range = this.RuleRanges[this.SelectedRuleRangeIndex];
386 ThingReference Thing = new(this.NodeId, this.SourceId, this.PartitionId);
387
388 if (Range.RuleRange is RuleRange RuleRange)
389 {
390 ControlRequestResolver Resolver = new(this.BareJid!, this.RemoteFriendlyName ?? string.Empty, RuleRange);
391
392 switch (RuleRange)
393 {
394 case RuleRange.Caller:
395 default:
396 ServiceRef.XmppService.CanControlResponseCaller(this.ProvisioningService ?? ServiceRef.TagProfile.ProvisioningJid ?? string.Empty,
397 this.BareJid!, this.RemoteJid!, this.Key!, Accepts, this.GetParameters(), Thing, this.ResponseHandler, Resolver);
398 break;
399
400 case RuleRange.Domain:
401 ServiceRef.XmppService.CanControlResponseDomain(this.ProvisioningService ?? ServiceRef.TagProfile.ProvisioningJid ?? string.Empty,
402 this.BareJid!, this.RemoteJid!, this.Key!, Accepts, this.GetParameters(), Thing, this.ResponseHandler, Resolver);
403 break;
404
405 case RuleRange.All:
406 ServiceRef.XmppService.CanControlResponseAll(this.ProvisioningService ?? ServiceRef.TagProfile.ProvisioningJid ?? string.Empty,
407 this.BareJid!, this.RemoteJid!, this.Key!, Accepts, this.GetParameters(), Thing, this.ResponseHandler, Resolver);
408 break;
409
410 }
411 }
412 else if (Range.RuleRange is ProvisioningToken Token)
413 {
414 ControlRequestResolver Resolver = new(this.BareJid!, this.RemoteFriendlyName ?? string.Empty, Token);
415
416 switch (Token.Type)
417 {
418 case TokenType.User:
419 ServiceRef.XmppService.CanControlResponseUser(this.ProvisioningService ?? ServiceRef.TagProfile.ProvisioningJid ?? string.Empty,
420 this.BareJid!, this.RemoteJid!, this.Key!, Accepts, this.GetParameters(), Token.Token, Thing, this.ResponseHandler, Resolver);
421 break;
422
423 case TokenType.Service:
424 ServiceRef.XmppService.CanControlResponseService(this.ProvisioningService ?? ServiceRef.TagProfile.ProvisioningJid ?? string.Empty,
425 this.BareJid!, this.RemoteJid!, this.Key!, Accepts, this.GetParameters(), Token.Token, Thing, this.ResponseHandler, Resolver);
426 break;
427
428 case TokenType.Device:
429 ServiceRef.XmppService.CanControlResponseDevice(this.ProvisioningService ?? ServiceRef.TagProfile.ProvisioningJid ?? string.Empty,
430 this.BareJid!, this.RemoteJid!, this.Key!, Accepts, this.GetParameters(), Token.Token, Thing, this.ResponseHandler, Resolver);
431 break;
432 }
433 }
434 }
435 }
436
437 private string[]? GetParameters()
438 {
439 List<string> Result = [];
440 bool AllPermitted = true;
441
442 foreach (FieldReference Parameter in this.Parameters)
443 {
444 if (Parameter.Permitted)
445 Result.Add(Parameter.Name);
446 else
447 AllPermitted = false;
448 }
449
450 if (AllPermitted)
451 return null;
452 else
453 return [.. Result];
454 }
455
456 private async Task ResponseHandler(object? Sender, IqResultEventArgs e)
457 {
458 if (e.Ok)
459 {
460 if (this.@event is not null)
462
464
465 MainThread.BeginInvokeOnMainThread(async () =>
466 {
467 await this.GoBack();
468 });
469 }
470 else
471 {
472 MainThread.BeginInvokeOnMainThread(async () => await ServiceRef.UiService.DisplayException(e.StanzaError ??
473 new Exception(ServiceRef.Localizer[nameof(AppResources.UnableToRespond)])));
474 }
475 }
476
480 [RelayCommand]
481 private async Task Ignore()
482 {
483 if (this.@event is not null)
485
486 await this.GoBack();
487 }
488
492 [RelayCommand]
493 private void AllParameters()
494 {
495 foreach (FieldReference Parameter in this.Parameters)
496 Parameter.Permitted = true;
497 }
498
502 [RelayCommand]
503 private void NoParameters()
504 {
505 foreach (FieldReference Parameter in this.Parameters)
506 Parameter.Permitted = false;
507 }
508
509 }
510}
A strongly-typed resource class, for looking up localized strings, etc.
static string ToService
Looks up a localized string similar to To service, regardless of source.
static string NotAvailable
Looks up a localized string similar to Not Available.
static string Device
Looks up a localized string similar to Device.
static string UnableToRespond
Looks up a localized string similar to Unable to respond to request..
static string ToDevice
Looks up a localized string similar to To device, regardless of source.
static string CallerOnly
Looks up a localized string similar to Caller Only.
static string ToUser
Looks up a localized string similar to To user, regardless of source.
static string Service
Looks up a localized string similar to Service.
static string EntireDomain
Looks up a localized string similar to Everyone from {0}.
static string Everyone
Looks up a localized string similar to Everyone.
static string User
Looks up a localized string similar to User.
Contains information about a contact.
Definition: ContactInfo.cs:22
Property?[] MetaData
Meta-data related to a thing.
Definition: ContactInfo.cs:211
static Task< ContactInfo > FindByBareJid(string BareJid)
Finds information about a contact, given its Bare JID.
Definition: ContactInfo.cs:221
static async Task< string[]?> GetAvailableParameterNames(string BareJid, ThingReference Thing)
Gets available fields for a thing.
Base class that references services in the app.
Definition: ServiceRef.cs:43
static IUiService UiService
Service serializing and managing UI-related tasks.
Definition: ServiceRef.cs:130
static INotificationService NotificationService
Service for managing notifications for the user.
Definition: ServiceRef.cs:334
static ITagProfile TagProfile
TAG Profile service.
Definition: ServiceRef.cs:202
static IReportingStringLocalizer Localizer
Localization service
Definition: ServiceRef.cs:370
static IXmppService XmppService
The XMPP service for XMPP communication.
Definition: ServiceRef.cs:190
virtual async Task GoBack()
Method called when user wants to navigate to the previous screen.
Holds navigation parameters specific to displaying the can-control provisioning question.
new? CanControlNotificationEvent Event
Notification event objcet.
The view model to bind to when displaying a thing.
override void OnPropertyChanged(PropertyChangedEventArgs e)
ObservableCollection< RuleRangeModel > RuleRanges
Available Rule Ranges
CanControlViewModel(CanControlNavigationArgs? Args)
Creates an instance of the CanControlViewModel class.
override async Task OnInitializeAsync()
Method called when view is initialized for the first time. Use this method to implement registration ...
ObservableCollection< HumanReadableTag > Tags
Holds a list of meta-data tags associated with a thing.
ObservableCollection< HumanReadableTag > CallerTags
Holds a list of meta-data tags associated with the caller.
ObservableCollection< FieldReference > Parameters
Holds a list of parameters that will be permitted.
Class used to present a meta-data tag in a human interface.
string? RemoteJid
Bare JID of remote entity trying to connect to device.
The view model to bind to for when displaying thing claim information.
static async Task LabelClicked(string Name, string Value, string LocalizedValue)
Processes the click of a localized meta-data label.
A view model that holds the XMPP state.
Abstract base class for contractual parameters
Definition: Parameter.cs:17
Event arguments for responses to IQ queries.
bool Ok
If the response is an OK result response (true), or an error response (false).
object State
State object passed to the original request.
XmppException StanzaError
Any stanza error returned.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:58
static string GetDomain(string JID)
Gets the domain part of a JID.
Definition: XmppClient.cs:6986
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:21
static async Task Update(object Object)
Updates an object in the database.
Definition: Database.cs:1211
static async Task Delete(object Object)
Deletes an object in the database.
Definition: Database.cs:1291
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
Definition: Database.cs:97
Contains a reference to a thing
Interface for event resolvers. Such can be used to resolve multiple pending notifications at once.
Task DeleteEvents(NotificationEventType Type, CaseInsensitiveString Category)
Deletes events for a given button and category.
Task DeleteResolvedEvents(IEventResolver Resolver)
Deletes pending events that have already been resolved.
abstract class NotificationEvent()
Abstract base class of notification events.
class RuleRangeModel(object RuleRange, string Label)
Rule Range model
RuleRange
Range of a rule change
Definition: RuleRange.cs:7