1using System.ComponentModel;
2using System.Globalization;
3using CommunityToolkit.Mvvm.ComponentModel;
24 private readonly Dictionary<CaseInsensitiveString, List<ContactInfoModel>> byBareJid = [];
25 private TaskCompletionSource<ContactInfoModel?>? result;
39 await base.OnInitialize();
41 ServiceRef.XmppService.OnPresence += this.Xmpp_OnPresence;
42 ServiceRef.NotificationService.OnNewNotification += this.NotificationService_OnNewNotification;
43 ServiceRef.NotificationService.OnNotificationsDeleted += this.NotificationService_OnNotificationsDeleted;
49 await base.OnAppearing();
50 this.SelectedThing =
null;
52 if (this.result is not
null && this.result.Task.IsCompleted)
58 await this.LoadThings();
62 private async Task LoadThings()
64 SortedDictionary<string, ContactInfo> SortedByName = [];
65 SortedDictionary<string, ContactInfo> SortedByAddress = [];
74 if (SortedByName.ContainsKey(Name))
80 Suffix =
" " + (++i).ToString(CultureInfo.InvariantCulture);
82 while (SortedByName.ContainsKey(Name + Suffix));
84 SortedByName[Name + Suffix] = Info;
87 SortedByName[Name] = Info;
89 Key = Info.BareJid +
", " + Info.SourceId +
", " + Info.Partition +
", " + Info.
NodeId;
90 SortedByAddress[Key] = Info;
96 Property[] MetaData = ViewClaimThing.ViewClaimThingViewModel.ToProperties(Thing.
Tags);
98 Key = Thing.Jid +
", " + Thing.Node.SourceId +
", " + Thing.Node.Partition +
", " + Thing.
Node.NodeId;
99 if (SortedByAddress.TryGetValue(Key, out
ContactInfo? Info))
101 if (!Info.Owner.HasValue || !Info.Owner.Value || !
AreSame(Info.MetaData, MetaData))
104 Info.MetaData = MetaData;
105 Info.FriendlyName = ViewClaimThing.ViewClaimThingViewModel.GetFriendlyName(MetaData) ??
string.Empty;
116 LegalId =
string.Empty,
118 FriendlyName = ViewClaimThing.ViewClaimThingViewModel.GetFriendlyName(Thing.
Tags) ??
string.Empty,
120 SourceId = Thing.
Node.SourceId,
121 Partition = Thing.
Node.Partition,
122 NodeId = Thing.
Node.NodeId,
125 RegistryJid = ServiceRef.XmppService.RegistryServiceJid
130 if (Tag.
Name.Equals(
"R", StringComparison.OrdinalIgnoreCase))
136 Name = Info.FriendlyName;
137 if (SortedByName.ContainsKey(Name))
143 Suffix =
" " + (++i).
ToString(CultureInfo.InvariantCulture);
145 while (SortedByName.ContainsKey(Name + Suffix));
147 SortedByName[Name + Suffix] = Info;
150 SortedByName[Name] = Info;
152 SortedByAddress[Key] = Info;
157 this.byBareJid.Clear();
159 ObservableItemGroup<IUniqueItem> NewThings =
new(nameof(this.
Things), []);
166 NewThings.Add(InfoModel);
168 if (!this.byBareJid.TryGetValue(Info.
BareJid, out List<ContactInfoModel>? Contacts))
171 this.byBareJid[Info.
BareJid] = Contacts;
174 Contacts.Add(InfoModel);
177 this.ShowThingsMissing = SortedByName.Count == 0;
179 MainThread.BeginInvokeOnMainThread(() => ObservableItemGroup<IUniqueItem>.UpdateGroupsItems(this.
Things, NewThings));
190 if (!
string.IsNullOrEmpty(Thing.
SourceId) ||
191 !
string.IsNullOrEmpty(Thing.
Partition) ||
192 !
string.IsNullOrEmpty(Thing.
NodeId) ||
195 ContactEvents =
null;
201 return ThingEvents is
null ? ContactEvents : (ContactEvents?.Join(ThingEvents) ?? ThingEvents);
207 ServiceRef.XmppService.OnPresence -= this.Xmpp_OnPresence;
208 ServiceRef.NotificationService.OnNewNotification -= this.NotificationService_OnNewNotification;
209 ServiceRef.NotificationService.OnNotificationsDeleted -= this.NotificationService_OnNotificationsDeleted;
211 this.ShowThingsMissing =
false;
214 this.result?.TrySetResult(
null);
216 await base.OnDispose();
227 if ((MetaData1 is
null) ^ (MetaData2 is
null))
230 if (MetaData1 is
null || MetaData2 is
null)
233 int i, c = MetaData1.Length;
234 if (MetaData2.Length != c)
237 for (i = 0; i < c; i++)
239 if ((MetaData1[i].Name != MetaData2[i].Name) || (MetaData1[i].Value != MetaData2[i].Value))
250 private bool showThingsMissing;
255 public ObservableItemGroup<IUniqueItem>
Things {
get; } =
new(nameof(
Things), []);
263 protected override void OnPropertyChanged(PropertyChangedEventArgs e)
267 switch (e.PropertyName)
269 case nameof(this.SelectedThing):
270 if (this.SelectedThing is not null)
271 this.OnSelected(this.SelectedThing);
281 MainThread.BeginInvokeOnMainThread(async () =>
283 if (this.result is
null)
290 this.result.TrySetResult(Thing);
296 private Task Xmpp_OnPresence(
object? Sender, PresenceEventArgs e)
298 if (this.byBareJid.TryGetValue(e.FromBareJID, out List<ContactInfoModel>? Contacts))
304 return Task.CompletedTask;
309 MainThread.BeginInvokeOnMainThread(() =>
315 case NotificationEventType.Contacts:
316 foreach (IUniqueItem Item in this.Things)
318 if (Item is ContactInfoModel Thing)
321 if (!string.IsNullOrEmpty(Thing.NodeId) ||
322 !string.IsNullOrEmpty(Thing.SourceId) ||
323 !string.IsNullOrEmpty(Thing.Partition))
328 if (Event.Category != Thing.BareJid)
331 Thing.RemoveEvent(Event);
336 case NotificationEventType.Things:
337 foreach (IUniqueItem Item in this.Things)
339 if (Item is ContactInfoModel Thing)
342 if (Event.Category != ContactInfo.GetThingNotificationCategoryKey(Thing.BareJid, Thing.NodeId, Thing.SourceId, Thing.Partition))
345 Thing.RemoveEvent(Event);
359 MainThread.BeginInvokeOnMainThread(() =>
363 switch (e.Event.Type)
365 case NotificationEventType.Contacts:
366 foreach (IUniqueItem Item in this.Things)
368 if (Item is ContactInfoModel Thing)
370 if (!string.IsNullOrEmpty(Thing.NodeId) ||
371 !string.IsNullOrEmpty(Thing.SourceId) ||
372 !string.IsNullOrEmpty(Thing.Partition))
377 if (e.Event.Category != Thing.BareJid)
380 Thing.AddEvent(e.Event);
393 Thing.AddEvent(e.Event);
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 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.
Contact Information model, including related notification information.
NotificationEvent[] Events
Notification events.
void PresenceUpdated()
Method called when presence for contact has been updated.
ContactInfo? Contact
Contact Information object in database.
void OnPropertyChanged(string PropertyName)
Called when a property has changed.
Holds navigation parameters specific to viewing things.
TaskCompletionSource< ContactInfoModel?>? ThingToShare
Task completion source where the selected thing is placed.
The view model to bind to when displaying the list of things.
static ? NotificationEvent[] GetNotificationEvents(ContactInfo Thing)
Gets available notification events related to a thing.
override async Task OnAppearing()
Method called when view is appearing on the screen.
override async Task OnDispose()
Method called when the view is disposed, and will not be used more. Use this method to unregister eve...
override async Task OnInitialize()
Method called when view is initialized for the first time. Use this method to implement registration ...
static bool AreSame(Property[]? MetaData1, Property[]? MetaData2)
Checks to sets of meta-data about a thing, to see if they match.
ObservableItemGroup< IUniqueItem > Things
Holds the list of contacts to display.
MyThingsViewModel(MyThingsNavigationArgs? Args)
Creates an instance of the MyThingsViewModel class.
Holds navigation parameters specific to viewing things.
A page that displays information about a thing and allows the user to interact with it.
Contains information about a thing in a search result.
MetaDataTag[] Tags
Meta-data tags.
ThingReference Node
Node reference. Can be equal to ThingReference.Empty if not behind a concentrator.
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.
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 have a named field equal to a given value.
bool TryGetNotificationEvents(NotificationEventType Type, CaseInsensitiveString Category, [NotNullWhen(true)] out NotificationEvent[]? Events)
Tries to get available notification events.
Task GoToAsync(string Route, BackMethod BackMethod=BackMethod.Inherited, string? UniqueId=null)
Navigates the AppShell to the specified route, with page arguments to match.
Task Flush()
Persists any pending changes.
abstract class NotificationEvent()
Abstract base class of notification events.
class NotificationEventsArgs(NotificationEvent[] Events)
Event argument for notification events.
class NotificationEventArgs(NotificationEvent Event)
Event argument for notification events.
NotificationEventType
Button on which event is to be displayed.
BackMethod
Navigation Back Method
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.