f-miyu / Plugin.CloudFirestore

MIT License
121 stars 44 forks source link

Various listener #75

Closed angelru closed 2 years ago

angelru commented 3 years ago

@f-miyu I have a complex scenario (a chat), I get the conversations like this:

  var listener = CrossCloudFirestore.Current.Instance.Collection(Settings.ChatsCollection)
                                              .WhereArrayContains(Settings.UserIds, MyUserId)
                                              .AddSnapshotListener(async (snapshot, error) =>
                                              {
                                                  if (error != null)
                                                  {
                                                      ChatsTabPageState = LayoutState.Error;
                                                      ChatRooms.Clear();
                                                  }
                                                  else if (snapshot?.IsEmpty is true || snapshot is null)
                                                  {
                                                      ChatsTabPageState = LayoutState.Empty;
                                                      ChatRooms.Clear();
                                                  }
                                                  else
                                                  {
                                                      foreach (var documentChange in snapshot.DocumentChanges)
                                                      {
                                                          ChatRoom chatRoom;
                                                          switch (documentChange.Type)
                                                          {
                                                              case DocumentChangeType.Added:
                                                                  chatRoom = documentChange.Document.ToObject<ChatRoom>();
                                                                  var rChatRoom = ChatRooms.FirstOrDefault(f => f.Id == chatRoom.Id);
                                                                  if (rChatRoom != null) break;
                                                                  ChatRooms.Add(chatRoom);
                                                                  break;
                                                              case DocumentChangeType.Modified:
                                                                  chatRoom = documentChange.Document.ToObject<ChatRoom>();
                                                                  var modChatRoom = ChatRooms.FirstOrDefault(f => f.Id == chatRoom.Id);
                                                                  if (modChatRoom is null) break;
                                                                  if (!modChatRoom.IsPrivate)
                                                                  {
                                                                      modChatRoom.Title = chatRoom.Title;
                                                                      modChatRoom.Image = chatRoom.Image;
                                                                      modChatRoom.PendingUserIds = chatRoom.PendingUserIds;
                                                                  }
                                                                  modChatRoom.UserIds = chatRoom.UserIds;
                                                                  modChatRoom.FCMTokens = chatRoom.FCMTokens;
                                                                  modChatRoom.RecentMessage = chatRoom.RecentMessage;
                                                                  break;
                                                              case DocumentChangeType.Removed:
                                                                  chatRoom = documentChange.Document.ToObject<ChatRoom>();
                                                                  var removeChatRoom = ChatRooms.FirstOrDefault(f => f.Id == chatRoom.Id);
                                                                  if (removeChatRoom is null) break;
                                                                  ChatRooms.Remove(removeChatRoom);
                                                                  break;
                                                          }

                                                          if (documentChange.Type is DocumentChangeType.Added)
                                                          {
                                                              chatRoom = documentChange.Document.ToObject<ChatRoom>();
                                                              //UnreadListener
                                                              ChatsUnreadMessagesAddListener(chatRoom.Id);
                                                          }
                                                      }

                                                      Device.BeginInvokeOnMainThread(() =>
                                                      {
                                                          var roomsOrder = ChatRooms.OrderByDescending(chatRoom => 
                                                                                           chatRoom.RecentMessage.CreatedAt).ToList();
                                                          ChatRooms.ReplaceRange(roomsOrder);
                                                      });

                                                      if (ChatsTabPageState != LayoutState.Success)
                                                          ChatsTabPageState = LayoutState.Success;

                                                  }
                                              });

            chatsListener.Add(listener);

UnreadListener:

            var listener = CrossCloudFirestore.Current.Instance.Collection(Settings.UnreadChatMessagesCollection)
                                              .Document(chatId)
                                              .Collection(Settings.MessagesCollection)
                                              .Document(MyUserId)
                                              .AddSnapshotListener((snapshot, error) =>
                                              {
                                                  if (error != null)
                                                  {
                                                  }
                                                  else if (snapshot != null)
                                                  {
                                                      var unreadMessage = snapshot.ToObject<UnreadMessage>();

                                                      Device.BeginInvokeOnMainThread(() =>
                                                      {
                                                          var chatRoom = ChatRooms.FirstOrDefault(f => f.Id == unreadMessage.ChatId);
                                                          chatRoom.UnreadMessages = unreadMessage.Total;
                                                      });
                                                  }
                                              });

            chatsListener.Add(listener);

The problem seems that sometimes the collection is modified and at the same time sorted and I get:

System.ArgumentOutOfRangeException Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index

This only happens if you click the push notification that I get a new message and go to the conversation. If I open the app and go to the chats tab and click on the conversation, the exception does not jump.

     Device.BeginInvokeOnMainThread(() =>
                {
                     var roomsOrder = ChatRooms.OrderByDescending(chatRoom => chatRoom.RecentMessage.CreatedAt).ToList();
                                                    ChatRooms.ReplaceRange(roomsOrder);
            });

If I remove this code everything seems to be fine, but I need to always sort the collection, but I cannot control how fast new messages are received. Any ideas? should I change the focus?

angelru commented 3 years ago

I ended up making an auxiliary list and it seems that for now the exception is not thrown. But I don't know if it's the "optimal" approach.