< Summary

Class:ChatHUDView
Assembly:ChatHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/ChatWidgetHUD/ChatHUDView.cs
Covered lines:91
Uncovered lines:36
Coverable lines:127
Total lines:284
Line coverage:71.6% (91 of 127)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ChatHUDView()0%110100%
ChatHUDView()0%110100%
Create()0%110100%
Initialize(...)0%110100%
OnInputFieldSubmit(...)0%660100%
OnInputFieldSelect(...)0%110100%
OnInputFieldDeselect(...)0%110100%
ResetInputField()0%2100%
OnEnable()0%110100%
FocusInputField()0%110100%
EntryIsVisible(...)0%110100%
SetFadeoutMode(...)0%4.074083.33%
AddEntry(...)0%20.0914068.57%
MessagesSentTooFast(...)0%2100%
IsSpamming(...)0%6.744044.44%
CreateBaseDateTime()0%2100%
OnOpenContextMenu(...)0%2100%
OnMessageTriggerHover(...)0%12300%
OnMessageCancelHover()0%110100%
SortEntries()0%440100%
CleanAllEntries()0%3.053081.82%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/ChatWidgetHUD/ChatHUDView.cs

#LineLine coverage
 1using DCL.Helpers;
 2using DCL.Interface;
 3using System;
 4using System.Collections.Generic;
 5using System.Linq;
 6using TMPro;
 7using UnityEngine;
 8using UnityEngine.Events;
 9using UnityEngine.UI;
 10using System.Text.RegularExpressions;
 11
 12public class ChatHUDView : MonoBehaviour
 13{
 114    static string VIEW_PATH = "Chat Widget";
 5115    string ENTRY_PATH = "Chat Entry";
 16    private const int MAX_CONTINUOUS_MESSAGES = 6;
 17    private const int MIN_MILLISECONDS_BETWEEN_MESSAGES = 1500;
 18    private const int TEMPORARILY_MUTE_MINUTES = 10;
 19
 5120    public bool detectWhisper = true;
 21    public TMP_InputField inputField;
 22    public RectTransform chatEntriesContainer;
 23
 24    public ScrollRect scrollRect;
 25    public ChatHUDController controller;
 26    public GameObject messageHoverPanel;
 27    public TextMeshProUGUI messageHoverText;
 28    public UserContextMenu contextMenu;
 29    public UserContextConfirmationDialog confirmationDialog;
 30
 5131    [NonSerialized] public List<ChatEntry> entries = new List<ChatEntry>();
 5132    [NonSerialized] public List<DateSeparatorEntry> dateSeparators = new List<DateSeparatorEntry>();
 33
 5134    ChatMessage currentMessage = new ChatMessage();
 5135    Regex whisperRegex = new Regex(@"(?i)^\/(whisper|w) (\S+)( *)(.*)");
 36    Match whisperRegexMatch;
 5137    private List<ChatEntry.Model> lastMessages = new List<ChatEntry.Model>();
 5138    private Dictionary<string, ulong> temporarilyMutedSenders = new Dictionary<string, ulong>();
 39
 40    public event UnityAction<string> OnPressPrivateMessage;
 41    public event UnityAction<ChatMessage> OnSendMessage;
 42
 43    public static ChatHUDView Create()
 44    {
 1445        var view = Instantiate(Resources.Load<GameObject>(VIEW_PATH)).GetComponent<ChatHUDView>();
 1446        return view;
 47    }
 48
 49    public void Initialize(ChatHUDController controller, UnityAction<ChatMessage> OnSendMessage)
 50    {
 3251        this.controller = controller;
 3252        this.OnSendMessage += OnSendMessage;
 3253        inputField.onSubmit.AddListener(OnInputFieldSubmit);
 3254        inputField.onSelect.AddListener(OnInputFieldSelect);
 3255        inputField.onDeselect.AddListener(OnInputFieldDeselect);
 3256    }
 57
 58    private void OnInputFieldSubmit(string message)
 59    {
 460        currentMessage.body = message;
 461        currentMessage.sender = UserProfile.GetOwnUserProfile().userId;
 462        currentMessage.messageType = ChatMessage.Type.NONE;
 463        currentMessage.recipient = string.Empty;
 64
 465        if (detectWhisper && !string.IsNullOrWhiteSpace(message))
 66        {
 467            whisperRegexMatch = whisperRegex.Match(message);
 68
 469            if (whisperRegexMatch.Success)
 70            {
 271                currentMessage.messageType = ChatMessage.Type.PRIVATE;
 272                currentMessage.recipient = whisperRegexMatch.Groups[2].Value;
 273                currentMessage.body = whisperRegexMatch.Groups[4].Value;
 74            }
 75        }
 76
 77        // A TMP_InputField is automatically marked as 'wasCanceled' when the ESC key is pressed
 478        if (inputField.wasCanceled)
 179            currentMessage.body = string.Empty;
 80
 481        OnSendMessage?.Invoke(currentMessage);
 482    }
 83
 1284    private void OnInputFieldSelect(string message) { AudioScriptableObjects.inputFieldFocus.Play(true); }
 85
 486    private void OnInputFieldDeselect(string message) { AudioScriptableObjects.inputFieldUnfocus.Play(true); }
 87
 88    public void ResetInputField()
 89    {
 090        inputField.text = string.Empty;
 091        inputField.caretColor = Color.white;
 092    }
 93
 8094    void OnEnable() { Utils.ForceUpdateLayout(transform as RectTransform); }
 95
 96    public void FocusInputField()
 97    {
 498        inputField.ActivateInputField();
 499        inputField.Select();
 4100    }
 101
 102    bool enableFadeoutMode = false;
 103
 104    bool EntryIsVisible(ChatEntry entry)
 105    {
 1106        int visibleCorners =
 107            (entry.transform as RectTransform).CountCornersVisibleFrom(scrollRect.viewport.transform as RectTransform);
 1108        return visibleCorners > 0;
 109    }
 110
 111    public void SetFadeoutMode(bool enabled)
 112    {
 8113        enableFadeoutMode = enabled;
 114
 18115        for (int i = 0; i < entries.Count; i++)
 116        {
 1117            ChatEntry entry = entries[i];
 118
 1119            if (enabled)
 120            {
 0121                entry.SetFadeout(EntryIsVisible(entry));
 0122            }
 123            else
 124            {
 1125                entry.SetFadeout(false);
 126            }
 127        }
 128
 8129        if (enabled)
 130        {
 3131            confirmationDialog.Hide();
 132        }
 8133    }
 134
 135    public virtual void AddEntry(ChatEntry.Model chatEntryModel, bool setScrollPositionToBottom = false)
 136    {
 31137        if (IsSpamming(chatEntryModel.senderName))
 0138            return;
 139
 31140        var chatEntryGO = Instantiate(Resources.Load(ENTRY_PATH) as GameObject, chatEntriesContainer);
 31141        ChatEntry chatEntry = chatEntryGO.GetComponent<ChatEntry>();
 142
 31143        if (enableFadeoutMode && EntryIsVisible(chatEntry))
 0144            chatEntry.SetFadeout(true);
 145        else
 31146            chatEntry.SetFadeout(false);
 147
 31148        chatEntry.Populate(chatEntryModel);
 149
 31150        if (chatEntryModel.messageType == ChatMessage.Type.PRIVATE)
 5151            chatEntry.OnPress += OnPressPrivateMessage;
 152
 31153        if (chatEntryModel.messageType == ChatMessage.Type.PUBLIC || chatEntryModel.messageType == ChatMessage.Type.PRIV
 31154            chatEntry.OnPressRightButton += OnOpenContextMenu;
 155
 31156        chatEntry.OnTriggerHover += OnMessageTriggerHover;
 31157        chatEntry.OnCancelHover += OnMessageCancelHover;
 158
 31159        entries.Add(chatEntry);
 160
 31161        SortEntries();
 162
 31163        Utils.ForceUpdateLayout(chatEntry.transform as RectTransform, delayed: false);
 164
 31165        if (setScrollPositionToBottom && scrollRect.verticalNormalizedPosition > 0)
 0166            scrollRect.verticalNormalizedPosition = 0;
 167
 31168        if (string.IsNullOrEmpty(chatEntryModel.senderId))
 26169            return;
 170
 5171        if (lastMessages.Count == 0)
 172        {
 4173            lastMessages.Add(chatEntryModel);
 4174        }
 1175        else if(lastMessages[lastMessages.Count-1].senderName == chatEntryModel.senderName)
 176        {
 0177            if (MessagesSentTooFast(lastMessages[lastMessages.Count - 1].timestamp, chatEntryModel.timestamp))
 178            {
 0179                lastMessages.Add(chatEntryModel);
 180
 0181                if (lastMessages.Count == MAX_CONTINUOUS_MESSAGES)
 182                {
 0183                    temporarilyMutedSenders.Add(chatEntryModel.senderName, chatEntryModel.timestamp);
 0184                    lastMessages.Clear();
 185                }
 0186            }
 187            else
 188            {
 0189                lastMessages.Clear();
 190            }
 0191        }
 192        else
 193        {
 1194            lastMessages.Clear();
 195        }
 1196    }
 197
 198    bool MessagesSentTooFast(ulong oldMessageTimeStamp, ulong newMessageTimeStamp)
 199    {
 0200        System.DateTime oldDateTime = CreateBaseDateTime().AddMilliseconds(oldMessageTimeStamp).ToLocalTime();
 0201        System.DateTime newDateTime = CreateBaseDateTime().AddMilliseconds(newMessageTimeStamp).ToLocalTime();
 202
 0203        return (newDateTime - oldDateTime).TotalMilliseconds < MIN_MILLISECONDS_BETWEEN_MESSAGES;
 204    }
 205
 206    private bool IsSpamming(string senderName)
 207    {
 31208        if (string.IsNullOrEmpty(senderName))
 0209            return false;
 210
 31211        bool isSpamming = false;
 212
 31213        if (temporarilyMutedSenders.ContainsKey(senderName))
 214        {
 0215            System.DateTime muteTimestamp = CreateBaseDateTime().AddMilliseconds(temporarilyMutedSenders[senderName]).To
 0216            if ((System.DateTime.Now - muteTimestamp).Minutes < TEMPORARILY_MUTE_MINUTES)
 0217                isSpamming = true;
 218            else
 0219                temporarilyMutedSenders.Remove(senderName);
 220        }
 221
 31222        return isSpamming;
 223    }
 224
 225    private System.DateTime CreateBaseDateTime()
 226    {
 0227        return new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
 228    }
 229
 230    private void OnOpenContextMenu(ChatEntry chatEntry)
 231    {
 0232        contextMenu.transform.position = chatEntry.contextMenuPositionReference.position;
 0233        contextMenu.transform.parent = this.transform;
 0234        contextMenu.Show(chatEntry.model.senderId);
 0235    }
 236
 237    protected virtual void OnMessageTriggerHover(ChatEntry chatEntry)
 238    {
 0239        if (contextMenu == null || contextMenu.isVisible)
 0240            return;
 241
 0242        messageHoverText.text = chatEntry.messageLocalDateTime;
 0243        messageHoverPanel.transform.position = chatEntry.hoverPanelPositionReference.position;
 0244        messageHoverPanel.SetActive(true);
 0245    }
 246
 247    public void OnMessageCancelHover()
 248    {
 38249        messageHoverPanel.SetActive(false);
 38250        messageHoverText.text = string.Empty;
 38251    }
 252
 253    public void SortEntries()
 254    {
 158255        entries = entries.OrderBy(x => x.model.timestamp).ToList();
 256
 31257        int count = entries.Count;
 316258        for (int i = 0; i < count; i++)
 259        {
 127260            if (entries[i].transform.GetSiblingIndex() != i)
 261            {
 44262                entries[i].transform.SetSiblingIndex(i);
 44263                Utils.ForceUpdateLayout(entries[i].transform as RectTransform, delayed: false);
 264            }
 265        }
 31266    }
 267
 268    public void CleanAllEntries()
 269    {
 18270        foreach (var entry in entries)
 271        {
 1272            Destroy(entry.gameObject);
 273        }
 274
 8275        entries.Clear();
 276
 16277        foreach (DateSeparatorEntry separator in dateSeparators)
 278        {
 0279            Destroy(separator.gameObject);
 280        }
 281
 8282        dateSeparators.Clear();
 8283    }
 284}