public static IListenerRegistration Subscribe <TModel, TViewModel, TKey>(IQuery query,
                                                                          GroupedObservableCollection <TKey, TViewModel> viewModels,
                                                                          Func <TModel, TViewModel> getViewModel,
                                                                          Action?afterSnapshotProcessed = null)
     where TModel : BaseModel
     where TViewModel : CardViewModel <TModel>
 {
     viewModels.Clear();
     return(query.AddSnapshotListener((snapshot, ex) =>
     {
         if (snapshot is null)
         {
             viewModels.Clear();
         }
         else if (viewModels.Elements.Any())
         {
             foreach (var change in snapshot.DocumentChanges)
             {
                 var doc = change.Document;
                 if (change.Type == DocumentChangeType.Added)
                 {
                     viewModels.Add(getViewModel(doc.ToObject <TModel>() !));
                 }
                 else
                 {
                     var vm = viewModels.Elements.SingleOrDefault(x => x.UID == doc.Id);
                     if (vm is null)
                     {
                         return;
                     }
                     if (change.Type == DocumentChangeType.Modified)
                     {
                         var oldKey = viewModels.GroupKeySelector(vm);
                         var oldPriority = viewModels.PrioritySelector(vm);
                         vm.Update(change.Document.ToObject <TModel>() !);
                         var newKey = viewModels.GroupKeySelector(vm) !;
                         if (!newKey.Equals(oldKey))
                         {
                             viewModels.MoveGroup(vm, oldKey);
                         }
                         else if (oldPriority != viewModels.PrioritySelector(vm))
                         {
                             viewModels.UpdatePriority(vm);
                         }
                     }
                     else
                     {
                         viewModels.Remove(vm);
                     }
                 }
             }
         }
         else if (!snapshot.IsEmpty)
         {
             snapshot.Documents.ForEach(x => viewModels.Add(getViewModel(x.ToObject <TModel>() !)));
         }
         afterSnapshotProcessed?.Invoke();
     }));
 }