Esempio n. 1
0
        internal void FixupUnresolvedObjectsForThread(YamsterThread thread, YamsterMessage latestMessage,
                                                      YamsterModelEventCollector eventCollector)
        {
            Debug.Assert(latestMessage.Thread == thread);

            DbThreadState dbThreadState;

            if (unresolvedThreadStatesById.TryGetValue(thread.ThreadId, out dbThreadState))
            {
                unresolvedThreadStatesById.Remove(thread.ThreadId);
                thread.SetDbThreadState(dbThreadState, eventCollector);
            }

            // Is this thread part of a conversation?
            long conversationId = latestMessage.DbMessage.ConversationId;

            if (conversationId != 0)
            {
                // Register the thread as the owner of this conversation
                this.threadsByConversationId[conversationId] = thread;

                // Is there an unresolved conversation object?
                DbConversation unresolvedConversation;
                if (this.unresolvedConversationsById.TryGetValue(conversationId, out unresolvedConversation))
                {
                    // Yes, so apply it now
                    this.unresolvedConversationsById.Remove(conversationId);
                    thread.UpdateConversation(unresolvedConversation, eventCollector);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// If the YamsterMessage with messageId already exists, this calls messageAction
        /// immediately.  Otherwise, messageAction is queued and will be called later when
        /// the message appears.  If the same listener calls ListenForMessageById() more
        /// than once, only the most recent request is kept.
        /// </summary>
        internal void ListenForMessageById(long messageId,
                                           object listener,
                                           YamsterModelEventCollector eventCollector,
                                           ListenedMessageAction messageAction)
        {
            YamsterMessage message = this.GetMessageById(messageId, nullIfMissing: true);

            if (message != null)
            {
                messageAction(message, eventCollector);
                return;
            }

            ListenedMessage listenedMessage;

            if (!listenedMessagesById.TryGetValue(messageId, out listenedMessage))
            {
                listenedMessage = new ListenedMessage()
                {
                    MessageId = messageId
                };
                listenedMessagesById.Add(messageId, listenedMessage);
            }

            listenedMessage.ActionsByListener[listener] = messageAction;
        }
Esempio n. 3
0
        void ProcessDbMessage(DbMessage record)
        {
            // Does the message exist yet?
            var message = this.GetMessageById(record.MessageId, nullIfMissing: true);

            bool messageIsNew = message == null;

            var eventCollector = new YamsterModelEventCollector();

            if (messageIsNew)
            {
                message = new YamsterMessage(record.MessageId, this);
                this.messagesById.Add(record.MessageId, message);
                eventCollector.NotifyAfterAdd(message);
                message.SetDbMessage(record, eventCollector);

                // For now we assume that messages cannot move between threads
                var           threadId = message.ThreadId;
                YamsterThread thread   = GetThreadById(threadId, nullIfMissing: true);
                if (thread == null)
                {
                    thread = new YamsterThread(threadId, message.Group, this);
                    threadsById.Add(threadId, thread);
                    eventCollector.NotifyAfterAdd(thread);
                    message.Group.AddThread(thread, eventCollector);

                    thread.AddMessage(message, eventCollector);

                    FixupUnresolvedObjectsForThread(thread, message, eventCollector);
                }
                else
                {
                    thread.AddMessage(message, eventCollector);
                }
            }
            else
            {
                message.SetDbMessage(record, eventCollector);
            }

            // Was there an unresolved message that we can process now?
            DbMessageState unresolvedMessageState;

            if (this.unresolvedMessageStatesById.TryGetValue(record.MessageId, out unresolvedMessageState))
            {
                this.unresolvedMessageStatesById.Remove(record.MessageId);
                ProcessDbMessageState(unresolvedMessageState, eventCollector);
            }

            if (messageIsNew)
            {
                CheckForListenedMessage(message, eventCollector);
            }

            eventCollector.FireEvents();
        }
Esempio n. 4
0
        void UpdateViewWithMessage(YamsterMessage message)
        {
            bool shouldBeInView = false;

            if (CompiledFunc != null)
            {
                var executionContext = new YqlExecutionContext(this.appContext);
                executionContext.Message = message;
                shouldBeInView           = CompiledFunc(executionContext);
            }

            ViewedMessage viewedMessage = null;
            bool          isInView      = viewedMessagesById.TryGetValue(message.MessageId, out viewedMessage);

            bool statisticsChanged = false;

            if (isInView)
            {
                if (!shouldBeInView)
                {
                    this.RemoveViewedMessage(viewedMessage);
                    NotifyViewChanged(YamsterViewChangeType.ModelLeaveView, message);

                    // TotalItemCount changed
                    statisticsChanged = true;
                }
                else
                {
                    if (message.Read != viewedMessage.Read)
                    {
                        this.readMessageCount += message.Read ? +1 : -1;
                        viewedMessage.Read     = message.Read;
                        statisticsChanged      = true;
                    }
                }
            }
            else
            {
                if (shouldBeInView)
                {
                    AddViewedMessage(new ViewedMessage(message));
                    NotifyViewChanged(YamsterViewChangeType.ModelEnterView, message);

                    // TotalItemCount changed
                    statisticsChanged = true;
                }
            }

            if (statisticsChanged)
            {
                NotifyViewChanged(YamsterViewChangeType.StatisticsChanged, null);
            }
        }
Esempio n. 5
0
        public static YamsterNewMessage CreateReply(YamsterMessage messageBeingRepliedTo)
        {
            if (messageBeingRepliedTo == null)
            {
                throw new ArgumentNullException("messageRepliedTo");
            }
            var newMessage = new YamsterNewMessage();

            newMessage.MessageBeingRepliedTo = messageBeingRepliedTo;
            newMessage.Group = messageBeingRepliedTo.Group;
            return(newMessage);
        }
Esempio n. 6
0
        public YamsterMessage GetMessageById(long messageId, bool nullIfMissing = false)
        {
            YamsterMessage message = null;

            if (!this.messagesById.TryGetValue(messageId, out message))
            {
                if (!nullIfMissing)
                {
                    throw new KeyNotFoundException("The message ID " + messageId + " was not found");
                }
            }
            return(message);
        }
Esempio n. 7
0
        void CheckForListenedMessage(YamsterMessage message, YamsterModelEventCollector eventCollector)
        {
            ListenedMessage listenedMessage;

            if (!listenedMessagesById.TryGetValue(message.MessageId, out listenedMessage))
            {
                return;
            }
            listenedMessagesById.Remove(message.MessageId);

            foreach (var messageAction in listenedMessage.ActionsByListener.Values)
            {
                messageAction(message, eventCollector);
            }
        }
Esempio n. 8
0
        internal void AddMessage(YamsterMessage message, YamsterModelEventCollector eventCollector)
        {
            // Insert sorted by MessageId
            int index = this.messagesInternal.BinarySearch(message,
                                                           Comparer <YamsterMessage> .Create((x, y) => Math.Sign(x.MessageId - y.MessageId)));
            int deletedIndex = this.deletedMessagesInternal.BinarySearch(message,
                                                                         Comparer <YamsterMessage> .Create((x, y) => Math.Sign(x.MessageId - y.MessageId)));

            if (index >= 0 || deletedIndex >= 0)
            {
                throw new InvalidOperationException("Program Bug: The message was already added to this thread");
            }

            bool oldAllMessagesDeleted = this.AllMessagesDeleted;

            if (!message.Deleted)
            {
                this.PerformActionAndCheckRead(() => {
                    this.messagesInternal.Insert(~index, message);
                }, eventCollector);

                message.NotifyAddedToThread(this);

                if (message.Read)
                {
                    // Increment the read message counter
                    this.NotifyMessageReadChanged(newReadValue: true, eventCollector: eventCollector);
                }

                NotifyTotalLikesChanged(+message.LikesCount, eventCollector);

                // Adding a message changes LastUpdate, Messages.Count, and possibly other properties
                // like TotalLikesCount
                eventCollector.NotifyAfterUpdate(this);
            }
            else
            {
                this.deletedMessagesInternal.Insert(~deletedIndex, message);
            }

            if (oldAllMessagesDeleted != this.AllMessagesDeleted)
            {
                // Remove and re-add the thread so it moves to the appropriate
                // collection (YamsterGroup.Threads or DeletedThreads)
                this.Group.RemoveThread(this, eventCollector);
                this.Group.AddThread(this, eventCollector);
            }
        }
Esempio n. 9
0
        internal void RemoveMessage(YamsterMessage message, YamsterModelEventCollector eventCollector)
        {
            int index = this.messagesInternal.BinarySearch(message,
                                                           Comparer <YamsterMessage> .Create((x, y) => Math.Sign(x.MessageId - y.MessageId)));
            int deletedIndex = this.deletedMessagesInternal.BinarySearch(message,
                                                                         Comparer <YamsterMessage> .Create((x, y) => Math.Sign(x.MessageId - y.MessageId)));

            if (index < 0 && deletedIndex < 0)
            {
                Debug.Assert(false, "RemoveMessage() called on message that doesn't belong to this thread");
                return;
            }

            if (index >= 0)
            {
                bool oldAllMessagesDeleted = this.AllMessagesDeleted;

                this.PerformActionAndCheckRead(() => {
                    this.messagesInternal.RemoveAt(index);
                }, eventCollector);


                if (oldAllMessagesDeleted != this.AllMessagesDeleted)
                {
                    // Remove and re-add the thread so it moves to the appropriate
                    // collection (YamsterGroup.Threads or DeletedThreads)
                    // (Note that NotifyMessageReadChanged() assumes that the thread
                    // is in the right collection.)
                    this.Group.RemoveThread(this, eventCollector);
                    this.Group.AddThread(this, eventCollector);
                }

                if (message.Read)
                {
                    // Decrement the read message counter
                    this.NotifyMessageReadChanged(newReadValue: false, eventCollector: eventCollector);
                }

                this.NotifyTotalLikesChanged(-message.LikesCount, eventCollector);
            }
            else
            {
                this.deletedMessagesInternal.RemoveAt(deletedIndex);
            }
        }
Esempio n. 10
0
 public ViewedMessage(YamsterMessage message)
 {
     this.Message = message;
     this.Read    = message.Read;
 }
Esempio n. 11
0
 public YamsterMessageChangedEventArgs(YamsterMessage message, YamsterModelChangeType changeType)
     : base(changeType)
 {
     this.Message = message;
 }
Esempio n. 12
0
        internal void SetDbMessage(DbMessage newValue, YamsterModelEventCollector eventCollector)
        {
            if (newValue == null)
            {
                throw new ArgumentNullException("DbMessage");
            }
            if (newValue.MessageId != messageId)
            {
                throw new ArgumentException("Cannot change ID");
            }

            var oldValue = this.dbMessage;

            this.dbMessage         = newValue;
            this.cachedPreviewText = null;

            this.group      = this.YamsterCache.FetchGroupById(this.dbMessage.GroupId, eventCollector);
            this.senderUser = this.YamsterCache.FetchUserById(this.dbMessage.SenderUserId, eventCollector);

            this.messageRepliedTo = null;
            if (this.dbMessage.MessageIdRepliedTo != 0
                // The Yammer UI doesn't show "in reply to" when messageRepliedTo is the threadstarter.
                // TODO: What does it do if the threadstarter's MessageId != ThreadId?
                && this.dbMessage.MessageIdRepliedTo != this.dbMessage.ThreadId)
            {
                this.YamsterCache.ListenForMessageById(
                    this.dbMessage.MessageIdRepliedTo,
                    this,
                    eventCollector,
                    delegate(YamsterMessage listenedMessage, YamsterModelEventCollector ec)
                {
                    if (listenedMessage.MessageId == this.dbMessage.MessageIdRepliedTo)
                    {
                        this.messageRepliedTo = listenedMessage;
                        ec.NotifyAfterUpdate(this);
                    }
                }
                    );
            }

            int oldlikingUsersCount = likingUsers.Count;

            likingUsers.Clear();
            foreach (long userId in this.dbMessage.LikingUserIds)
            {
                var user = this.YamsterCache.FetchUserById(userId, eventCollector);
                likingUsers.AddUser(user);
            }

            if (this.thread != null)
            {
                int totalLikesCountDelta = newValue.LikesCount - oldValue.LikesCount;
                if (totalLikesCountDelta != 0)
                {
                    this.thread.NotifyTotalLikesChanged(totalLikesCountDelta, eventCollector);
                }
            }

            notifiedUsers.Clear();
            foreach (long userId in this.dbMessage.NotifiedUserIds)
            {
                var user = this.YamsterCache.FetchUserById(userId, eventCollector);
                notifiedUsers.AddUser(user);
            }

            UpdateLoadedStatus();

            eventCollector.NotifyAfterUpdate(this);
        }