Beispiel #1
0
        //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
        #region --Misc Methods (Public)--
        /// <summary>
        /// Retries to download the image from the given ChatMessageTable.
        /// </summary>
        /// <param name="msg">The ChatMessageTable containing the image url.</param>
        /// <returns>The image container.</returns>
        public ImageTable retryImageDownload(ChatMessageTable msg)
        {
            if (msg.isImage)
            {
                ImageTable img = getImageForMessage(msg);
                if (img == null)
                {
                    img = new ImageTable()
                    {
                        messageId = msg.id,
                        path      = null,
                        state     = DownloadState.WAITING,
                        progress  = 0
                    };
                }
                else
                {
                    img.state    = DownloadState.WAITING;
                    img.progress = 0;
                    img.path     = null;
                }

                Task.Run(async() =>
                {
                    update(img);
                    await downloadImageAsync(img, msg.message);
                });

                return(img);
            }
            return(null);
        }
Beispiel #2
0
        public async Task deleteImageAsync(ChatMessageTable msg)
        {
            ImageTable image = await getImageAsync(msg);

            if (!(image is null))
            {
                // Cancel download:
                ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.CancelDownload(image);

                // Try to delete local file:
                try
                {
                    if (!string.IsNullOrEmpty(image.TargetFolderPath) && !string.IsNullOrEmpty(image.TargetFileName))
                    {
                        string      path = image.GetFullPath();
                        StorageFile file = await StorageFile.GetFileFromPathAsync(path);

                        if (!(file is null))
                        {
                            await file.DeleteAsync();
                        }
                    }
                    Logger.Info("Deleted: " + image.TargetFileName);
                }
                catch (Exception e)
                {
                    Logger.Error("Failed to delete image: " + image.TargetFileName, e);
                }

                // Delete DB entry:
                dB.Delete(image);
            }
        }
        private void C_OmemoSessionBuildError(XMPPClient client, XMPP_API.Classes.Events.OmemoSessionBuildErrorEventArgs args)
        {
            Task.Run(() =>
            {
                ChatTable chat = ChatDBManager.INSTANCE.getChat(ChatTable.generateId(args.CHAT_JID, client.getXMPPAccount().getBareJid()));
                if (!(chat is null))
                {
                    // Add an error chat message:
                    ChatMessageTable msg = new ChatMessageTable()
                    {
                        id       = ChatMessageTable.generateErrorMessageId(AbstractMessage.getRandomId(), chat.id),
                        chatId   = chat.id,
                        date     = DateTime.Now,
                        fromUser = args.CHAT_JID,
                        isImage  = false,
                        message  = "Failed to encrypt and send " + args.MESSAGES.Count + " OMEMO message(s) with:\n" + args.ERROR,
                        state    = MessageState.UNREAD,
                        type     = MessageMessage.TYPE_ERROR
                    };
                    ChatDBManager.INSTANCE.setChatMessage(msg, true, false);

                    // Set chat messages to encrypted failed:
                    setOmemoChatMessagesSendFailed(args.MESSAGES, chat);
                }
            });
        }
Beispiel #4
0
        public static void showChatTextToast(ChatMessageTable msg, ChatTable chat)
        {
            ToastContent toastContent = new ToastContent
            {
                Visual = new ToastVisual
                {
                    BindingGeneric = new ToastBindingGeneric
                    {
                        Children =
                        {
                            new AdaptiveText()
                            {
                                Text         = chat.chatJabberId,
                                HintMaxLines = 1
                            },
                            new AdaptiveText()
                            {
                                Text = msg.message
                            }
                        },
                        AppLogoOverride = new ToastGenericAppLogo
                        {
                            Source   = chat.chatType == ChatType.CHAT ? DEFAULT_USER_IMAGE_PATH : DEFAULT_MUC_IMAGE_PATH,
                            HintCrop = ToastGenericAppLogoCrop.Circle
                        }
                    }
                },
                Actions          = getActions(msg, chat),
                DisplayTimestamp = msg.date,
                Launch           = new ChatToastActivation(chat.id, msg.id).generate()
            };

            popToast(toastContent, chat);
        }
Beispiel #5
0
 private static ToastActionsCustom getActions(ChatMessageTable msg, ChatTable chat)
 {
     return(new ToastActionsCustom()
     {
         /*Inputs =
          * {
          *  new ToastTextBox(TEXT_BOX_ID)
          *  {
          *      PlaceholderContent = "Reply"
          *  }
          * },*/
         Buttons =
         {
             /*new ToastButton("Send", new SendReplyToastActivation(chat.id, false).generate())
              * {
              *  ActivationType = ToastActivationType.Background,
              *  ImageUri = SEND_BUTTON_IMAGE_PATH,
              *  TextBoxId = TEXT_BOX_ID,
              * },*/
             new ToastButton("Mark chat as read", new MarkChatAsReadToastActivation(chat.id, false).generate())
             {
                 ActivationType = ToastActivationType.Background
             },
             new ToastButton("Mark as read",      new MarkMessageAsReadToastActivation(msg.id, false).generate())
             {
                 ActivationType = ToastActivationType.Background
             }
         }
     });
 }
Beispiel #6
0
 public void markMessageAsRead(ChatMessageTable msg)
 {
     msg.state = MessageState.READ;
     dB.InsertOrReplace(msg);
     msg.onChanged();
     ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(msg, false));
 }
Beispiel #7
0
        //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
        #region --Constructors--


        #endregion
        //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
        #region --Set-, Get- Methods--
        public async Task <ImageTable> getImageAsync(ChatMessageTable msg)
        {
            await GET_IMAGE_SEMA.WaitAsync();

            // Is already downloading:
            ImageTable img = (ImageTable)await ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.FindAsync((x) => { return(x is ImageTable imageTable && string.Equals(imageTable.messageId, msg.id)); });

            if (img is null)
            {
                // Is in the DB:
                List <ImageTable> list = dB.Query <ImageTable>(true, "SELECT * FROM " + DBTableConsts.IMAGE_TABLE + " WHERE " + nameof(ImageTable.messageId) + " = ?;", msg.id);
                if (list.Count > 0)
                {
                    img = list[0];
                }
                else
                {
                    // Create a new image entry:
                    StorageFolder folder = await ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.GetCacheFolderAsync();

                    img = new ImageTable()
                    {
                        messageId        = msg.id,
                        SourceUrl        = msg.message,
                        TargetFileName   = ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.CreateUniqueFileName(msg.message),
                        TargetFolderPath = folder.Path,
                        State            = DownloadState.NOT_QUEUED,
                        Progress         = 0,
                    };
                    setImage(img);
                }
            }
            GET_IMAGE_SEMA.Release();
            return(img);
        }
Beispiel #8
0
 private static ToastActionsCustom getActions(ChatMessageTable msg, ChatTable chat)
 {
     return(new ToastActionsCustom
     {
         Inputs =
         {
             new ToastTextBox(TEXT_BOX_ID)
             {
                 PlaceholderContent = "Reply"
             }
         },
         Buttons =
         {
             new ToastButton("Send",              new SendReplyToastActivation(chat.id, msg.id).generate())
             {
                 ActivationType = ToastActivationType.Background,
                 ImageUri = chat.omemoEnabled ? SEND_BUTTON_ENCRYPTED_IMAGE_PATH : SEND_BUTTON_IMAGE_PATH,
                 TextBoxId = TEXT_BOX_ID,
             },
             new ToastButton("Mark chat as read", new MarkChatAsReadToastActivation(chat.id, false).generate())
             {
                 ActivationType = ToastActivationType.Background
             },
             new ToastButton("Mark as read",      new MarkMessageAsReadToastActivation(msg.id).generate())
             {
                 ActivationType = ToastActivationType.Background
             }
         }
     });
 }
Beispiel #9
0
 private void cacheImage(ChatMessageTable msg)
 {
     if (!Settings.getSettingBoolean(SettingsConsts.DISABLE_IMAGE_AUTO_DOWNLOAD))
     {
         Task.Run(async() => await ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.DownloadImageAsync(msg));
     }
 }
Beispiel #10
0
        public static void showChatTextEncryptedToast(ChatMessageTable msg, ChatTable chat)
        {
            var toastContent = new ToastContent()
            {
                Visual = new ToastVisual()
                {
                    BindingGeneric = new ToastBindingGeneric()
                    {
                        Children =
                        {
                            new AdaptiveText()
                            {
                                Text         = chat.chatJabberId,
                                HintMaxLines = 1
                            },
                            new AdaptiveText()
                            {
                                Text = "You received an encrypted message!"
                            }
                        },
                        AppLogoOverride = new ToastGenericAppLogo()
                        {
                            Source   = chat.chatType == ChatType.CHAT ? DEFAULT_USER_IMAGE_PATH : DEFAULT_MUC_IMAGE_PATH,
                            HintCrop = ToastGenericAppLogoCrop.Default
                        }
                    }
                },
                Actions          = getActions(msg, chat),
                DisplayTimestamp = msg.date,
                Launch           = new ChatToastActivation(chat.id, false).generate()
            };

            popToast(toastContent, chat);
        }
        //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
        #region --Constructors--


        #endregion
        //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
        #region --Set-, Get- Methods--


        #endregion
        //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
        #region --Misc Methods (Public)--
        public void UpdateView(ChatTable chat, ChatMessageTable message)
        {
            if (chat is null || message is null)
            {
                return;
            }

            Text         = message.message;
            IsCarbonCopy = message.isCC;
            IsEncrypted  = message.isEncrypted;
            Date         = message.date;
            MessageType  = message.type;
            IsImage      = message.isImage;
            State        = message.state;

            if (State == MessageState.UNREAD)
            {
                Task.Run(() => ChatDBManager.INSTANCE.markMessageAsRead(message));
            }

            if (chat.chatType == ChatType.MUC)
            {
                NicknameText = message.fromUser;
            }
            else
            {
                NicknameText = string.Empty;
            }
        }
 //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
 #region --Constructors--
 /// <summary>
 /// Basic Constructor
 /// </summary>
 /// <history>
 /// 27/08/2017 Created [Fabian Sauter]
 /// </history>
 public ChatMasterControl()
 {
     this.InitializeComponent();
     this.subscriptionRequest  = false;
     this.lastChatMessage      = null;
     this.updateBookmarkHelper = null;
 }
Beispiel #13
0
 private void markMessageAsRead(ChatMessageTable msg)
 {
     msg.state = MessageState.READ;
     update(msg);
     msg.onChanged();
     ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(msg));
 }
 private void setOmemoChatMessagesSendFailed(IList <OmemoMessageMessage> messages, ChatTable chat)
 {
     foreach (OmemoMessageMessage msg in messages)
     {
         string msgId = ChatMessageTable.generateId(msg.ID, chat.id);
         ChatDBManager.INSTANCE.updateChatMessageState(msgId, MessageState.ENCRYPT_FAILED);
     }
 }
Beispiel #15
0
        public void markMessageAsRead(string id)
        {
            ChatMessageTable msg = getChatMessageById(id);

            if (msg != null)
            {
                markMessageAsRead(msg);
            }
        }
Beispiel #16
0
        private async Task SendChatMessageAsync(ChatDataTemplate chat, string message)
        {
            MessageMessage toSendMsg;

            string from            = chat.Client.getXMPPAccount().getFullJid();
            string to              = chat.Chat.chatJabberId;
            string chatType        = chat.Chat.chatType == ChatType.CHAT ? MessageMessage.TYPE_CHAT : MessageMessage.TYPE_GROUPCHAT;
            bool   reciptRequested = true;

            if (chat.Chat.omemoEnabled)
            {
                if (chat.Chat.chatType == ChatType.CHAT)
                {
                    toSendMsg = new OmemoMessageMessage(from, to, message, chatType, reciptRequested);
                }
                else
                {
                    // ToDo: Add MUC OMEMO support
                    throw new NotImplementedException("Sending encrypted messages for MUC is not supported right now!");
                }
            }
            else
            {
                toSendMsg = chat.Chat.chatType == ChatType.CHAT
                    ? new MessageMessage(from, to, message, chatType, reciptRequested)
                    : new MessageMessage(from, to, message, chatType, chat.MucInfo.nickname, reciptRequested);
            }

            // Create a copy for the DB:
            ChatMessageTable toSendMsgDB = new ChatMessageTable(toSendMsg, chat.Chat)
            {
                state = toSendMsg is OmemoMessageMessage ? MessageState.TO_ENCRYPT : MessageState.SENDING
            };

            // Set the chat message id for later identification:
            toSendMsg.chatMessageId = toSendMsgDB.id;

            // Update chat last active:
            chat.Chat.lastActive = DateTime.Now;

            // Update DB:
            await Task.Run(() =>
            {
                ChatDBManager.INSTANCE.setChatMessage(toSendMsgDB, true, false);
                ChatDBManager.INSTANCE.setChat(chat.Chat, false, true);
            });

            // Send the message:
            if (toSendMsg is OmemoMessageMessage toSendOmemoMsg)
            {
                await chat.Client.sendOmemoMessageAsync(toSendOmemoMsg, chat.Chat.chatJabberId, chat.Client.getXMPPAccount().getBareJid());
            }
            else
            {
                await chat.Client.SendAsync(toSendMsg);
            }
        }
Beispiel #17
0
        private async Task cacheImageAsync(ChatMessageTable msg)
        {
            if (!Settings.getSettingBoolean(SettingsConsts.DISABLE_IMAGE_AUTO_DOWNLOAD))
            {
                ImageTable img = await ImageDBManager.INSTANCE.getImageAsync(msg);

                await ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.StartDownloadAsync(img);
            }
        }
 private void C_NewDeliveryReceipt(XMPPClient client, NewDeliveryReceiptEventArgs args)
 {
     Task.Run(() =>
     {
         string to     = Utils.getBareJidFromFullJid(args.MSG.getTo());
         string from   = Utils.getBareJidFromFullJid(args.MSG.getFrom());
         string chatId = ChatTable.generateId(from, to);
         string msgId  = ChatMessageTable.generateId(args.MSG.RECEIPT_ID, chatId);
         ChatDBManager.INSTANCE.setMessageAsDeliverd(msgId, true);
     });
 }
Beispiel #19
0
 //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
 #region --Set-, Get- Methods--
 public void setMessageAsDeliverd(string id, bool triggerMessageChanged)
 {
     dB.Execute("UPDATE " + DBTableConsts.CHAT_MESSAGE_TABLE + " SET state = ? WHERE id = ?", MessageState.DELIVERED, id);
     if (triggerMessageChanged)
     {
         ChatMessageTable msg = getChatMessageById(id);
         if (msg != null)
         {
             ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(msg, false));
         }
     }
 }
Beispiel #20
0
        private async Task onMUCErrorMessageAsync(XMPPClient client, MUCErrorMessage errorMessage)
        {
            string room = Utils.getBareJidFromFullJid(errorMessage.getFrom());

            if (room != null)
            {
                string    chatId = ChatTable.generateId(room, client.getXMPPAccount().getBareJid());
                ChatTable muc    = ChatDBManager.INSTANCE.getChat(chatId);
                if (muc != null)
                {
                    MUCChatInfoTable info = MUCDBManager.INSTANCE.getMUCInfo(chatId);
                    if (info != null)
                    {
                        Logger.Error("Received an error message for MUC: " + muc.chatJabberId + "\n" + errorMessage.ERROR_MESSAGE);

                        stopMUCJoinHelper(muc);

                        if (info.state != MUCState.DISCONNECTED)
                        {
                            await sendMUCLeaveMessageAsync(client, muc, info);
                        }

                        switch (errorMessage.ERROR_CODE)
                        {
                        // No access - user got baned:
                        case 403:
                            MUCDBManager.INSTANCE.setMUCState(info.chatId, MUCState.BANED, true);
                            addChatInfoMessage(info.chatId, room, "Unable to join room!\nYou are baned from this room.");
                            return;

                        default:
                            MUCDBManager.INSTANCE.setMUCState(info.chatId, MUCState.ERROR, true);
                            break;
                        }

                        // Add an error chat message:
                        ChatMessageTable msg = new ChatMessageTable()
                        {
                            id       = ChatMessageTable.generateErrorMessageId(errorMessage.ID ?? AbstractMessage.getRandomId(), muc.id),
                            chatId   = muc.id,
                            date     = DateTime.Now,
                            fromUser = errorMessage.getFrom(),
                            isImage  = false,
                            message  = "Code: " + errorMessage.ERROR_CODE + "\nType: " + errorMessage.ERROR_TYPE + "\nMessage:\n" + errorMessage.ERROR_MESSAGE,
                            state    = MessageState.UNREAD,
                            type     = MessageMessage.TYPE_ERROR
                        };
                        ChatDBManager.INSTANCE.setChatMessage(msg, true, false);
                    }
                }
            }
        }
Beispiel #21
0
        public void UpdateLastAction(ChatTable chat)
        {
            Task.Run(() =>
            {
                ChatMessageTable lastMsg = ChatDBManager.INSTANCE.getLastChatMessageForChat(chat.id);
                if (lastMsg is null)
                {
                    LastActionIconText       = "";
                    LastActionIconVisability = Visibility.Collapsed;
                    LastActionState          = MessageState.READ;
                }
                else
                {
                    // Text and icon:
                    LastActionState = lastMsg.state;
                    if (lastMsg.isImage)
                    {
                        LastActionIconText       = "\uE722";
                        LastActionIconVisability = Visibility.Visible;
                        LastActionText           = lastMsg.message ?? "You received an image";
                    }
                    else
                    {
                        switch (lastMsg.type)
                        {
                        case DirectMUCInvitationMessage.TYPE_MUC_DIRECT_INVITATION:
                            LastActionIconText       = "\uE8F2";
                            LastActionIconVisability = Visibility.Visible;
                            LastActionText           = "You have been invited to a MUC room";
                            break;

                        case MessageMessage.TYPE_ERROR:
                            LastActionIconText       = "\xE7BA";
                            LastActionIconVisability = Visibility.Visible;
                            LastActionText           = lastMsg.message ?? "You received an error message";
                            break;

                        case MUCHandler.TYPE_CHAT_INFO:
                            LastActionIconText       = "\uE946";
                            LastActionIconVisability = Visibility.Visible;
                            LastActionText           = (lastMsg.message ?? "-");
                            break;

                        default:
                            LastActionIconVisability = Visibility.Collapsed;
                            LastActionText           = lastMsg.message ?? "";
                            break;
                        }
                    }
                }
            });
        }
Beispiel #22
0
        //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
        #region --Constructors--


        #endregion
        //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
        #region --Set-, Get- Methods--
        /// <summary>
        ///
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public async Task <ImageTable> getImageAsync(ChatMessageTable msg)
        {
            ImageTable img = (ImageTable)await ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.FindAsync((x) => { return(x is ImageTable imageTable && string.Equals(imageTable.messageId, msg.id)); });

            if (img is null)
            {
                List <ImageTable> list = dB.Query <ImageTable>(true, "SELECT * FROM " + DBTableConsts.IMAGE_TABLE + " WHERE " + nameof(ImageTable.messageId) + " = ?;", msg.id);
                if (list.Count > 0)
                {
                    img = list[0];
                }
            }
            return(img);
        }
Beispiel #23
0
        /// <summary>
        /// Returns the image container from a given ChatMessageTable.
        /// </summary>
        /// <param name="msg">The ChatMessageTable.</param>
        /// <returns>The corresponding image container.</returns>
        public ImageTable getImageForMessage(ChatMessageTable msg)
        {
            ImageTable img = downloading.Find(x => string.Equals(x.messageId, msg.id));

            if (img == null)
            {
                List <ImageTable> list = dB.Query <ImageTable>(true, "SELECT * FROM " + DBTableConsts.IMAGE_TABLE + " WHERE messageId = ?;", msg.id);
                if (list.Count > 0)
                {
                    img = list[0];
                }
            }
            return(img);
        }
Beispiel #24
0
        /// <summary>
        /// Continues all outstanding downloads.
        /// </summary>
        private void contiuneAllDownloads()
        {
            List <ImageTable> list = dB.Query <ImageTable>(true, "SELECT * FROM " + DBTableConsts.IMAGE_TABLE + " WHERE state = 0 OR state = 1;");

            foreach (ImageTable img in list)
            {
                Task.Run(async() =>
                {
                    // Reset image progress:
                    img.progress = 0;

                    ChatMessageTable msg = ChatDBManager.INSTANCE.getChatMessageById(img.messageId);
                    await downloadImageAsync(img, msg.message);
                });
            }
        }
Beispiel #25
0
 public void setChatMessage(ChatMessageTable message, bool triggerNewChatMessage, bool triggerMessageChanged)
 {
     update(message);
     if (triggerNewChatMessage)
     {
         NewChatMessage?.Invoke(this, new NewChatMessageEventArgs(message));
         if (message.isImage)
         {
             cacheImage(message);
         }
     }
     if (triggerMessageChanged)
     {
         ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(message));
     }
 }
Beispiel #26
0
 public void setChatMessage(ChatMessageTable message, bool triggerNewChatMessage, bool triggerMessageChanged)
 {
     dB.InsertOrReplace(message);
     if (triggerNewChatMessage)
     {
         NewChatMessage?.Invoke(this, new NewChatMessageEventArgs(message));
         if (message.isImage && !Settings.getSettingBoolean(SettingsConsts.DISABLE_IMAGE_AUTO_DOWNLOAD))
         {
             cacheImage(message);
         }
     }
     if (triggerMessageChanged)
     {
         ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(message, false));
     }
 }
Beispiel #27
0
        private void addChatInfoMessage(string chatId, string fromUser, string message)
        {
            ChatMessageTable msg = new ChatMessageTable
            {
                id       = ChatMessageTable.generateId(AbstractMessage.getRandomId(), chatId),
                chatId   = chatId,
                date     = DateTime.Now,
                fromUser = fromUser,
                isImage  = false,
                message  = message,
                state    = MessageState.UNREAD,
                type     = TYPE_CHAT_INFO
            };

            ChatDBManager.INSTANCE.setChatMessage(msg, true, false);
        }
Beispiel #28
0
        public async Task deleteChatMessageAsync(ChatMessageTable message, bool triggerMessageChanged)
        {
            if (message.isImage)
            {
                await ImageDBManager.INSTANCE.deleteImageAsync(message);
            }

            if (string.Equals(message.type, DirectMUCInvitationMessage.TYPE_MUC_DIRECT_INVITATION))
            {
                deleteMucDirectInvite(message);
            }

            dB.Delete(message);
            if (triggerMessageChanged)
            {
                ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(message, true));
            }
        }
Beispiel #29
0
 /// <summary>
 /// Creates a new task, downloads the image from the given message and stores it locally.
 /// </summary>
 /// <param name="msg">The ChatMessageTable containing the image url.</param>
 public void downloadImage(ChatMessageTable msg)
 {
     if (msg.isImage)
     {
         Task.Run(async() =>
         {
             ImageTable img = new ImageTable()
             {
                 messageId = msg.id,
                 path      = null,
                 state     = DownloadState.WAITING,
                 progress  = 0
             };
             update(img);
             await downloadImageAsync(img, msg.message);
         });
     }
 }
Beispiel #30
0
 //--------------------------------------------------------Events:---------------------------------------------------------------------\\
 #region --Events--
 private async void INSTANCE_NewChatMessage(ChatDBManager handler, NewChatMessageEventArgs args)
 {
     await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
     {
         ChatMessageTable msg = args.MESSAGE;
         if (Chat != null && Chat.id.Equals(msg.chatId))
         {
             // Only update for unread messages:
             if (msg.state == MessageState.UNREAD)
             {
                 msg.state = MessageState.READ;
                 ChatDBManager.INSTANCE.setChatMessage(msg, false, true);
             }
             chatMessages.Add(new ChatMessageDataTemplate()
             {
                 message = msg,
                 chat    = Chat
             });
         }
     });
 }